+ separated demo-mode and solver; solver dialog
+ added statistics progression; statistics progression dialog + new animation speed: `medium'; renamed `timer based' to `fast' + added flip animation (animatedFlip) + added move to waste animation (animatedFlipAndMove) + added cancel-drag animation (moveCardsBackHandler) * improved demo game (snapshots based check for loop) - removed setting text color from file name - removed auto generation shadows (too slow) * optimized menu creation * changed some keybindings * updated russian translation * many bugfixes git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@138 39dd0a4e-7c14-0410-91b3-c4f2d318f732
|
@ -24,7 +24,7 @@ graft html-src
|
||||||
## data - images
|
## data - images
|
||||||
##
|
##
|
||||||
#graft data/images
|
#graft data/images
|
||||||
recursive-include data/images *.gif *.png
|
recursive-include data/images *.gif *.png *.jpg
|
||||||
graft data/tiles
|
graft data/tiles
|
||||||
include data/pysol.xbm data/pysol.xpm data/pysol.ico
|
include data/pysol.xbm data/pysol.xpm data/pysol.ico
|
||||||
##
|
##
|
||||||
|
|
|
@ -38,7 +38,6 @@ gchar *s = N_("Highlight piles:");
|
||||||
gchar *s = N_("Highlight cards:");
|
gchar *s = N_("Highlight cards:");
|
||||||
gchar *s = N_("Highlight same rank:");
|
gchar *s = N_("Highlight same rank:");
|
||||||
gchar *s = N_("Set colors");
|
gchar *s = N_("Set colors");
|
||||||
gchar *s = N_("Text foreground:");
|
|
||||||
gchar *s = N_("Highlight piles:");
|
gchar *s = N_("Highlight piles:");
|
||||||
gchar *s = N_("Highlight cards 1:");
|
gchar *s = N_("Highlight cards 1:");
|
||||||
gchar *s = N_("Highlight cards 2:");
|
gchar *s = N_("Highlight cards 2:");
|
||||||
|
@ -54,6 +53,7 @@ gchar *s = N_("Change...");
|
||||||
gchar *s = N_("Change...");
|
gchar *s = N_("Change...");
|
||||||
gchar *s = N_("Change...");
|
gchar *s = N_("Change...");
|
||||||
gchar *s = N_("Change...");
|
gchar *s = N_("Change...");
|
||||||
|
gchar *s = N_("Text foreground:");
|
||||||
gchar *s = N_("Set font");
|
gchar *s = N_("Set font");
|
||||||
gchar *s = N_("HTML: ");
|
gchar *s = N_("HTML: ");
|
||||||
gchar *s = N_("Small: ");
|
gchar *s = N_("Small: ");
|
||||||
|
|
BIN
data/images/stats/progression.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
|
@ -2051,30 +2051,6 @@
|
||||||
<property name="row_spacing">0</property>
|
<property name="row_spacing">0</property>
|
||||||
<property name="column_spacing">0</property>
|
<property name="column_spacing">0</property>
|
||||||
|
|
||||||
<child>
|
|
||||||
<widget class="GtkCheckButton" id="use_default_checkbutton">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="label" translatable="yes">Text foreground:</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
|
||||||
<property name="focus_on_click">True</property>
|
|
||||||
<property name="active">False</property>
|
|
||||||
<property name="inconsistent">False</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="left_attach">0</property>
|
|
||||||
<property name="right_attach">1</property>
|
|
||||||
<property name="top_attach">0</property>
|
|
||||||
<property name="bottom_attach">1</property>
|
|
||||||
<property name="x_padding">4</property>
|
|
||||||
<property name="y_padding">4</property>
|
|
||||||
<property name="x_options">fill</property>
|
|
||||||
<property name="y_options"></property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label31">
|
<widget class="GtkLabel" id="label31">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -3128,6 +3104,32 @@
|
||||||
<property name="y_options">fill</property>
|
<property name="y_options">fill</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label79">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Text foreground:</property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">False</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="right_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
<property name="bottom_attach">1</property>
|
||||||
|
<property name="x_padding">4</property>
|
||||||
|
<property name="y_padding">4</property>
|
||||||
|
<property name="x_options">fill</property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="padding">0</property>
|
<property name="padding">0</property>
|
||||||
|
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 6 KiB After Width: | Height: | Size: 6 KiB |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 206 KiB |
|
@ -1,5 +1,4 @@
|
||||||
<h1>PySol - a Solitaire Game Collection</h1>
|
<h1>PySol - a Solitaire Game Collection</h1>
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p> <a href="intro.html">Introduction</a>
|
<p> <a href="intro.html">Introduction</a>
|
||||||
<p> <a href="install.html">Installation</a>
|
<p> <a href="install.html">Installation</a>
|
||||||
|
|
|
@ -26,6 +26,3 @@ by court artisans. No cards from this pack are known to still exist.
|
||||||
<h3>Strategy</h3>
|
<h3>Strategy</h3>
|
||||||
Build sequences on the rows that will play when the correct card turns
|
Build sequences on the rows that will play when the correct card turns
|
||||||
over from the talon. This game type requires careful strategy to win.
|
over from the talon. This game type requires careful strategy to win.
|
||||||
<p>
|
|
||||||
<br>
|
|
||||||
<a href="../ganjifa.html">General Ganjifa Rules</a>
|
|
||||||
|
|
|
@ -15,5 +15,5 @@ and the number of cards you can move as a sequence is not restricted.
|
||||||
<p>
|
<p>
|
||||||
All cards are dealt to 9 piles at the start of the game, each Raja or King
|
All cards are dealt to 9 piles at the start of the game, each Raja or King
|
||||||
starting a new pile. Rows build down in rank and alternate color.
|
starting a new pile. Rows build down in rank and alternate color.
|
||||||
Refer to the general <a href="ganjifa.html">Ganjifa</a> page.
|
Refer to the general <a href="../ganjifa.html">Ganjifa</a> page.
|
||||||
Empty rows cannot be filled. The eight free cells will hold one card each.
|
Empty rows cannot be filled. The eight free cells will hold one card each.
|
||||||
|
|
|
@ -8,7 +8,7 @@ Move all cards to the foundations.
|
||||||
|
|
||||||
<h3>Quick Description</h3>
|
<h3>Quick Description</h3>
|
||||||
<p>
|
<p>
|
||||||
Like <a href="freecell.html">FreeCell</a>,
|
Like <a href="relaxedfreecell.html">Relaxed FreeCell</a>,
|
||||||
but with 2 decks, and empty rows are not filled.
|
but with 2 decks, and empty rows are not filled.
|
||||||
|
|
||||||
<h3>Rules</h3>
|
<h3>Rules</h3>
|
||||||
|
@ -19,7 +19,3 @@ To compensate for this there are 8 free cells which can hold any
|
||||||
- and just one - card.
|
- and just one - card.
|
||||||
<p>
|
<p>
|
||||||
Piles build down by alternate color, and an empty space cannot be filled.
|
Piles build down by alternate color, and an empty space cannot be filled.
|
||||||
<p>
|
|
||||||
The number of cards you can move as a sequence is restricted by
|
|
||||||
the number of free cells - the number of free cells required is the
|
|
||||||
same as if you would make an equivalent sequence of moves with single cards.
|
|
||||||
|
|
16
html-src/rules/newbritishconstitution.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<h1>New British Constitution</h1>
|
||||||
|
<p>
|
||||||
|
Two-Deck game type. 2 decks. No redeals.
|
||||||
|
|
||||||
|
<h3>Object</h3>
|
||||||
|
<p>
|
||||||
|
Move all cards to the foundations.
|
||||||
|
|
||||||
|
<h3>Quick Description</h3>
|
||||||
|
<p>
|
||||||
|
Like <a href="britishconstitution.html">British Constitution</a>,
|
||||||
|
but only Jacks on empty spaces and the piles build down by rank ignoring suit.
|
||||||
|
|
||||||
|
<h3>Rules</h3>
|
||||||
|
<p>
|
||||||
|
<i>[To be written]</i>
|
25
html-src/rules/retinue.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<h1>Retinue</h1>
|
||||||
|
<p>
|
||||||
|
FreeCell type. 2 decks. No redeal.
|
||||||
|
|
||||||
|
<h3>Object</h3>
|
||||||
|
<p>
|
||||||
|
Move all cards to the foundations.
|
||||||
|
|
||||||
|
<h3>Quick Description</h3>
|
||||||
|
<p>
|
||||||
|
Like <a href="freecell.html">FreeCell</a>,
|
||||||
|
but with 2 decks, and empty rows are not filled.
|
||||||
|
|
||||||
|
<h3>Rules</h3>
|
||||||
|
<p>
|
||||||
|
All cards are dealt to 8 piles at the start of the game, each King
|
||||||
|
starting a new pile.
|
||||||
|
To compensate for this there are 8 free cells which can hold any
|
||||||
|
- and just one - card.
|
||||||
|
<p>
|
||||||
|
Piles build down by alternate color, and an empty space cannot be filled.
|
||||||
|
<p>
|
||||||
|
The number of cards you can move as a sequence is restricted by
|
||||||
|
the number of free cells - the number of free cells required is the
|
||||||
|
same as if you would make an equivalent sequence of moves with single cards.
|
|
@ -5,7 +5,7 @@ Seven Devils is arguably the most difficult of all solitaire games. It is a
|
||||||
two pack game widely available as a computer version.
|
two pack game widely available as a computer version.
|
||||||
<p>
|
<p>
|
||||||
28 cards are dealt out to seven diminishing columns with the bottom card of
|
28 cards are dealt out to seven diminishing columns with the bottom card of
|
||||||
each column face up, and a further seven cards (the \u201cdevil\u201d) are
|
each column face up, and a further seven cards (the "devil") are
|
||||||
dealt face up to the right of the columns.
|
dealt face up to the right of the columns.
|
||||||
<p>
|
<p>
|
||||||
The aim is to move all the cards into thirteen-card sequences on the goal
|
The aim is to move all the cards into thirteen-card sequences on the goal
|
||||||
|
|
11
po/games.pot
|
@ -5,7 +5,7 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PySol 0.0.1\n"
|
"Project-Id-Version: PySol 0.0.1\n"
|
||||||
"POT-Creation-Date: Fri Jan 12 13:34:09 2007\n"
|
"POT-Creation-Date: Thu Feb 15 18:35:01 2007\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -216,6 +216,9 @@ msgstr ""
|
||||||
msgid "Baroness"
|
msgid "Baroness"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Barrier"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Bastille Day"
|
msgid "Bastille Day"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -243,6 +246,9 @@ msgstr ""
|
||||||
msgid "Beatle"
|
msgid "Beatle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bebop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Beetle"
|
msgid "Beetle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3717,6 +3723,9 @@ msgstr ""
|
||||||
msgid "Wasp"
|
msgid "Wasp"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Waterfall"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Waterloo"
|
msgid "Waterloo"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
1086
po/pysol.pot
|
@ -5,8 +5,8 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PySol 0.0.1\n"
|
"Project-Id-Version: PySol 0.0.1\n"
|
||||||
"POT-Creation-Date: Fri Jan 12 13:34:09 2007\n"
|
"POT-Creation-Date: Thu Feb 15 18:35:01 2007\n"
|
||||||
"PO-Revision-Date: 2007-01-17 19:12+0300\n"
|
"PO-Revision-Date: 2007-02-12 19:08+0300\n"
|
||||||
"Last-Translator: Скоморох <skomoroh@gmail.com>\n"
|
"Last-Translator: Скоморох <skomoroh@gmail.com>\n"
|
||||||
"Language-Team: Russian <ru@li.org>\n"
|
"Language-Team: Russian <ru@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
|
@ -217,6 +217,10 @@ msgstr "Баларама"
|
||||||
msgid "Baroness"
|
msgid "Baroness"
|
||||||
msgstr "Баронесса"
|
msgstr "Баронесса"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Barrier"
|
||||||
|
msgstr "Причудливый"
|
||||||
|
|
||||||
msgid "Bastille Day"
|
msgid "Bastille Day"
|
||||||
msgstr "День Бастилии"
|
msgstr "День Бастилии"
|
||||||
|
|
||||||
|
@ -244,6 +248,9 @@ msgstr "Клюв и ласты"
|
||||||
msgid "Beatle"
|
msgid "Beatle"
|
||||||
msgstr "Жук"
|
msgstr "Жук"
|
||||||
|
|
||||||
|
msgid "Bebop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Beetle"
|
msgid "Beetle"
|
||||||
msgstr "Жук"
|
msgstr "Жук"
|
||||||
|
|
||||||
|
@ -3772,6 +3779,10 @@ msgstr "Фаворит Вашингтона"
|
||||||
msgid "Wasp"
|
msgid "Wasp"
|
||||||
msgstr "Оса"
|
msgstr "Оса"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Waterfall"
|
||||||
|
msgstr "Ватерлоо"
|
||||||
|
|
||||||
msgid "Waterloo"
|
msgid "Waterloo"
|
||||||
msgstr "Ватерлоо"
|
msgstr "Ватерлоо"
|
||||||
|
|
||||||
|
|
1062
po/ru_pysol.po
|
@ -50,6 +50,7 @@ from stats import FileStatsFormatter
|
||||||
from pysoltk import SingleGame_StatsDialog, AllGames_StatsDialog
|
from pysoltk import SingleGame_StatsDialog, AllGames_StatsDialog
|
||||||
from pysoltk import FullLog_StatsDialog, SessionLog_StatsDialog
|
from pysoltk import FullLog_StatsDialog, SessionLog_StatsDialog
|
||||||
from pysoltk import Status_StatsDialog, Top_StatsDialog
|
from pysoltk import Status_StatsDialog, Top_StatsDialog
|
||||||
|
from pysoltk import ProgressionDialog
|
||||||
from pysoltk import GameInfoDialog
|
from pysoltk import GameInfoDialog
|
||||||
|
|
||||||
# toolkit imports
|
# toolkit imports
|
||||||
|
@ -61,6 +62,7 @@ from pysoltk import ColorsDialog
|
||||||
from pysoltk import FontsDialog
|
from pysoltk import FontsDialog
|
||||||
from pysoltk import EditTextDialog
|
from pysoltk import EditTextDialog
|
||||||
from pysoltk import create_find_card_dialog
|
from pysoltk import create_find_card_dialog
|
||||||
|
from pysoltk import create_solver_dialog
|
||||||
from help import help_about, help_html
|
from help import help_about, help_html
|
||||||
|
|
||||||
gettext = _
|
gettext = _
|
||||||
|
@ -473,11 +475,13 @@ class PysolMenubarActions:
|
||||||
|
|
||||||
def mDrop(self, *args):
|
def mDrop(self, *args):
|
||||||
if self._cancelDrag(): return
|
if self._cancelDrag(): return
|
||||||
self.game.autoPlay(autofaceup=-1, autodrop=1)
|
##self.game.autoPlay(autofaceup=-1, autodrop=1)
|
||||||
|
self.game.autoDrop(autofaceup=-1)
|
||||||
|
|
||||||
def mDrop1(self, *args):
|
def mDrop1(self, *args):
|
||||||
if self._cancelDrag(): return
|
if self._cancelDrag(): return
|
||||||
self.game.autoPlay(autofaceup=1, autodrop=1)
|
##self.game.autoPlay(autofaceup=1, autodrop=1)
|
||||||
|
self.game.autoDrop(autofaceup=1)
|
||||||
|
|
||||||
def mStatus(self, *args):
|
def mStatus(self, *args):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
|
@ -495,6 +499,9 @@ class PysolMenubarActions:
|
||||||
create_find_card_dialog(self.game.top, self.game,
|
create_find_card_dialog(self.game.top, self.game,
|
||||||
self.app.getFindCardImagesDir())
|
self.app.getFindCardImagesDir())
|
||||||
|
|
||||||
|
def mSolver(self, *args):
|
||||||
|
create_solver_dialog(self.game.top, self.app)
|
||||||
|
|
||||||
def mEditGameComment(self, *args):
|
def mEditGameComment(self, *args):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
game, gi = self.game, self.game.gameinfo
|
game, gi = self.game, self.game.gameinfo
|
||||||
|
@ -593,6 +600,9 @@ class PysolMenubarActions:
|
||||||
elif mode == 106:
|
elif mode == 106:
|
||||||
header = _("Game Info")
|
header = _("Game Info")
|
||||||
d = GameInfoDialog(self.top, header, self.app)
|
d = GameInfoDialog(self.top, header, self.app)
|
||||||
|
elif mode == 107:
|
||||||
|
header = _("Statistics progression")
|
||||||
|
d = ProgressionDialog(self.top, header, self.app, player, gameid=self.game.id)
|
||||||
elif mode == 202:
|
elif mode == 202:
|
||||||
# print stats to file
|
# print stats to file
|
||||||
write_method = FileStatsFormatter.writeStats
|
write_method = FileStatsFormatter.writeStats
|
||||||
|
@ -698,9 +708,7 @@ class PysolMenubarActions:
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
d = ColorsDialog(self.top, _("Set colors"), self.app)
|
d = ColorsDialog(self.top, _("Set colors"), self.app)
|
||||||
text_color = self.app.opt.colors['text']
|
text_color = self.app.opt.colors['text']
|
||||||
use_default_text_color = self.app.opt.use_default_text_color
|
|
||||||
if d.status == 0 and d.button == 0:
|
if d.status == 0 and d.button == 0:
|
||||||
self.app.opt.use_default_text_color = d.use_default_color
|
|
||||||
self.app.opt.colors['text'] = d.text_color
|
self.app.opt.colors['text'] = d.text_color
|
||||||
self.app.opt.colors['piles'] = d.piles_color
|
self.app.opt.colors['piles'] = d.piles_color
|
||||||
self.app.opt.colors['cards_1'] = d.cards_1_color
|
self.app.opt.colors['cards_1'] = d.cards_1_color
|
||||||
|
@ -710,9 +718,8 @@ class PysolMenubarActions:
|
||||||
self.app.opt.colors['hintarrow'] = d.hintarrow_color
|
self.app.opt.colors['hintarrow'] = d.hintarrow_color
|
||||||
self.app.opt.colors['not_matching'] = d.not_matching_color
|
self.app.opt.colors['not_matching'] = d.not_matching_color
|
||||||
#
|
#
|
||||||
if (text_color != self.app.opt.colors['text'] or
|
if text_color != self.app.opt.colors['text']:
|
||||||
use_default_text_color != self.app.opt.use_default_text_color):
|
self.app.setTile(self.app.tabletile_index, force=True)
|
||||||
self.app.setTile(self.app.tabletile_index)
|
|
||||||
|
|
||||||
def mOptFonts(self, *args):
|
def mOptFonts(self, *args):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
|
|
|
@ -71,6 +71,8 @@ from pysoltk import SelectDialogTreeData
|
||||||
from pysoltk import HTMLViewer
|
from pysoltk import HTMLViewer
|
||||||
from pysoltk import TOOLBAR_BUTTONS
|
from pysoltk import TOOLBAR_BUTTONS
|
||||||
from pysoltk import destroy_find_card_dialog
|
from pysoltk import destroy_find_card_dialog
|
||||||
|
from pysoltk import destroy_solver_dialog
|
||||||
|
from pysoltk import connect_game_solver_dialog
|
||||||
from help import help_about, destroy_help_html
|
from help import help_about, destroy_help_html
|
||||||
|
|
||||||
gettext = _
|
gettext = _
|
||||||
|
@ -102,7 +104,7 @@ class Options:
|
||||||
self.mahjongg_show_removed = False
|
self.mahjongg_show_removed = False
|
||||||
self.mahjongg_create_solvable = True
|
self.mahjongg_create_solvable = True
|
||||||
self.shisen_show_hint = True
|
self.shisen_show_hint = True
|
||||||
self.animations = 2 # default to Timer based
|
self.animations = 2 # default to Fast
|
||||||
self.redeal_animation = True
|
self.redeal_animation = True
|
||||||
self.win_animation = True
|
self.win_animation = True
|
||||||
self.shadow = True
|
self.shadow = True
|
||||||
|
@ -112,13 +114,14 @@ class Options:
|
||||||
self.demo_logo = True
|
self.demo_logo = True
|
||||||
self.tile_theme = 'default'
|
self.tile_theme = 'default'
|
||||||
if WIN_SYSTEM == 'win32':
|
if WIN_SYSTEM == 'win32':
|
||||||
self.tile_theme = 'winnative'
|
self.tile_theme = self.default_tile_theme = 'winnative'
|
||||||
if sys.getwindowsversion() >= (5, 1): # xp
|
if sys.getwindowsversion() >= (5, 1): # xp
|
||||||
self.tile_theme = 'xpnative'
|
self.tile_theme = 'xpnative'
|
||||||
elif WIN_SYSTEM == 'x11':
|
elif WIN_SYSTEM == 'x11':
|
||||||
self.tile_theme = 'step'
|
self.tile_theme = 'clam'
|
||||||
|
self.default_tile_theme = 'default'
|
||||||
elif WIN_SYSTEM == 'aqua':
|
elif WIN_SYSTEM == 'aqua':
|
||||||
self.tile_theme = 'aqua'
|
self.tile_theme = self.default_tile_theme = 'aqua'
|
||||||
self.toolbar = 1 # 0 == hide, 1,2,3,4 == top, bottom, lef, right
|
self.toolbar = 1 # 0 == hide, 1,2,3,4 == top, bottom, lef, right
|
||||||
##self.toolbar_style = 'default'
|
##self.toolbar_style = 'default'
|
||||||
self.toolbar_style = 'bluecurve'
|
self.toolbar_style = 'bluecurve'
|
||||||
|
@ -190,7 +193,6 @@ class Options:
|
||||||
'hintarrow': '#303030',
|
'hintarrow': '#303030',
|
||||||
'not_matching': '#ff0000',
|
'not_matching': '#ff0000',
|
||||||
}
|
}
|
||||||
self.use_default_text_color = False
|
|
||||||
# delays
|
# delays
|
||||||
self.timeouts = {
|
self.timeouts = {
|
||||||
'hint': 1.0,
|
'hint': 1.0,
|
||||||
|
@ -708,10 +710,12 @@ class Application:
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
pass
|
pass
|
||||||
# save game geometry
|
|
||||||
self.wm_save_state()
|
self.wm_save_state()
|
||||||
|
# save game geometry
|
||||||
if self.opt.save_games_geometry and not self.opt.wm_maximized:
|
if self.opt.save_games_geometry and not self.opt.wm_maximized:
|
||||||
geom = (self.canvas.winfo_width(), self.canvas.winfo_height())
|
w = self.canvas.winfo_width()
|
||||||
|
h = self.canvas.winfo_height()
|
||||||
|
geom = (w-2, h-2) # XXX: subtract canvas borderwidth
|
||||||
self.opt.games_geometry[self.game.id] = geom
|
self.opt.games_geometry[self.game.id] = geom
|
||||||
self.freeGame()
|
self.freeGame()
|
||||||
#
|
#
|
||||||
|
@ -726,8 +730,9 @@ class Application:
|
||||||
# hide main window
|
# hide main window
|
||||||
self.wm_withdraw()
|
self.wm_withdraw()
|
||||||
#
|
#
|
||||||
destroy_find_card_dialog()
|
|
||||||
destroy_help_html()
|
destroy_help_html()
|
||||||
|
destroy_find_card_dialog()
|
||||||
|
destroy_solver_dialog()
|
||||||
# update options
|
# update options
|
||||||
self.opt.last_gameid = id
|
self.opt.last_gameid = id
|
||||||
# save options
|
# save options
|
||||||
|
@ -1005,7 +1010,7 @@ class Application:
|
||||||
#from pprint import pprint; pprint(self.opt.cardset)
|
#from pprint import pprint; pprint(self.opt.cardset)
|
||||||
|
|
||||||
def loadCardset(self, cs, id=0, update=7, progress=None):
|
def loadCardset(self, cs, id=0, update=7, progress=None):
|
||||||
#print 'loadCardset', cs.ident
|
##print 'loadCardset', cs.ident
|
||||||
r = 0
|
r = 0
|
||||||
if cs is None or cs.error:
|
if cs is None or cs.error:
|
||||||
return 0
|
return 0
|
||||||
|
@ -1049,6 +1054,10 @@ class Application:
|
||||||
elif self.images is not None:
|
elif self.images is not None:
|
||||||
##self.images.destruct()
|
##self.images.destruct()
|
||||||
destruct(self.images)
|
destruct(self.images)
|
||||||
|
#
|
||||||
|
if self.cardset and self.cardset.ident != cs.ident and \
|
||||||
|
self.cardset.type == cs.type:
|
||||||
|
self.opt.games_geometry = {} # clear saved games geometry
|
||||||
# update
|
# update
|
||||||
self.images = images
|
self.images = images
|
||||||
self.subsampled_images = simages
|
self.subsampled_images = simages
|
||||||
|
@ -1381,6 +1390,9 @@ Please select a %s type %s.
|
||||||
names.sort()
|
names.sort()
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
def getGamesForSolver(self):
|
||||||
|
return self.gdb.getGamesForSolver()
|
||||||
|
|
||||||
#
|
#
|
||||||
# plugins
|
# plugins
|
||||||
#
|
#
|
||||||
|
@ -1591,7 +1603,6 @@ Please select a %s type %s.
|
||||||
##print dirs
|
##print dirs
|
||||||
s = "((\\" + ")|(\\".join(IMAGE_EXTENSIONS) + "))$"
|
s = "((\\" + ")|(\\".join(IMAGE_EXTENSIONS) + "))$"
|
||||||
ext_re = re.compile(s, re.I)
|
ext_re = re.compile(s, re.I)
|
||||||
text_color_re = re.compile(r"^(.+)-([0-9A-Fa-f]{6})$")
|
|
||||||
found, t = [], {}
|
found, t = [], {}
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
dir = dir.strip()
|
dir = dir.strip()
|
||||||
|
@ -1611,16 +1622,6 @@ Please select a %s type %s.
|
||||||
n = ext_re.sub("", name.strip())
|
n = ext_re.sub("", name.strip())
|
||||||
if os.path.split(dir)[-1] == 'stretch':
|
if os.path.split(dir)[-1] == 'stretch':
|
||||||
tile.stretch = 1
|
tile.stretch = 1
|
||||||
elif n.find('-stretch') > 0:
|
|
||||||
# stretch?
|
|
||||||
tile.stretch = 1
|
|
||||||
n = n.replace('-stretch', '')
|
|
||||||
#else:
|
|
||||||
# tile.stretch = 0
|
|
||||||
m = text_color_re.search(n)
|
|
||||||
if m:
|
|
||||||
n = m.group(1)
|
|
||||||
tile.text_color = "#" + m.group(2).lower()
|
|
||||||
#n = re.sub("[-_]", " ", n)
|
#n = re.sub("[-_]", " ", n)
|
||||||
n = n.replace('_', ' ')
|
n = n.replace('_', ' ')
|
||||||
##n = unicode(n)
|
##n = unicode(n)
|
||||||
|
|
400
pysollib/game.py
|
@ -37,6 +37,7 @@
|
||||||
# imports
|
# imports
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
|
import md5
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
# PySol imports
|
# PySol imports
|
||||||
|
@ -57,7 +58,9 @@ from pysoltk import after, after_idle, after_cancel
|
||||||
from pysoltk import MfxMessageDialog, MfxExceptionDialog
|
from pysoltk import MfxMessageDialog, MfxExceptionDialog
|
||||||
from pysoltk import MfxCanvasText, MfxCanvasLine, MfxCanvasRectangle
|
from pysoltk import MfxCanvasText, MfxCanvasLine, MfxCanvasRectangle
|
||||||
from pysoltk import Card
|
from pysoltk import Card
|
||||||
from move import AMoveMove, AFlipMove, ATurnStackMove
|
from pysoltk import reset_solver_dialog
|
||||||
|
from move import AMoveMove, AFlipMove, AFlipAndMoveMove
|
||||||
|
from move import ASingleFlipMove, ATurnStackMove
|
||||||
from move import ANextRoundMove, ASaveSeedMove, AShuffleStackMove
|
from move import ANextRoundMove, ASaveSeedMove, AShuffleStackMove
|
||||||
from move import AUpdateStackMove, AFlipAllMove, ASaveStateMove
|
from move import AUpdateStackMove, AFlipAllMove, ASaveStateMove
|
||||||
from move import ASingleCardMove
|
from move import ASingleCardMove
|
||||||
|
@ -114,6 +117,8 @@ class Game:
|
||||||
self.cards = []
|
self.cards = []
|
||||||
self.stackmap = {} # dict with (x,y) tuples as key
|
self.stackmap = {} # dict with (x,y) tuples as key
|
||||||
self.allstacks = []
|
self.allstacks = []
|
||||||
|
self.sn_groups = [] # snapshot groups; list of list of similar stacks
|
||||||
|
self.snapshots = []
|
||||||
self.stackdesc_list = []
|
self.stackdesc_list = []
|
||||||
self.demo_logo = None
|
self.demo_logo = None
|
||||||
self.pause_logo = None
|
self.pause_logo = None
|
||||||
|
@ -160,6 +165,7 @@ class Game:
|
||||||
# set some defaults
|
# set some defaults
|
||||||
self.sg.openstacks = filter(lambda s: s.cap.max_accept >= s.cap.min_accept, self.sg.openstacks)
|
self.sg.openstacks = filter(lambda s: s.cap.max_accept >= s.cap.min_accept, self.sg.openstacks)
|
||||||
self.sg.hp_stacks = filter(lambda s: s.cap.max_move >= 2, self.sg.dropstacks)
|
self.sg.hp_stacks = filter(lambda s: s.cap.max_move >= 2, self.sg.dropstacks)
|
||||||
|
self.createSnGroups()
|
||||||
# convert stackgroups to tuples (speed)
|
# convert stackgroups to tuples (speed)
|
||||||
self.allstacks = tuple(self.allstacks)
|
self.allstacks = tuple(self.allstacks)
|
||||||
self.s.foundations = tuple(self.s.foundations)
|
self.s.foundations = tuple(self.s.foundations)
|
||||||
|
@ -193,15 +199,15 @@ class Game:
|
||||||
# update display properties
|
# update display properties
|
||||||
self.top.wm_geometry("") # cancel user-specified geometry
|
self.top.wm_geometry("") # cancel user-specified geometry
|
||||||
self.canvas.setInitialSize(self.width, self.height)
|
self.canvas.setInitialSize(self.width, self.height)
|
||||||
|
if self.app.opt.save_games_geometry and \
|
||||||
|
self.id in self.app.opt.games_geometry:
|
||||||
|
# restore game geometry
|
||||||
|
w, h = self.app.opt.games_geometry[self.id]
|
||||||
|
self.canvas.config(width=w, height=h)
|
||||||
self.top.update_idletasks() # apply geometry now
|
self.top.update_idletasks() # apply geometry now
|
||||||
if DEBUG >= 4:
|
if DEBUG >= 4:
|
||||||
MfxCanvasRectangle(self.canvas, 0, 0, self.width, self.height,
|
MfxCanvasRectangle(self.canvas, 0, 0, self.width, self.height,
|
||||||
width=2, fill=None, outline='green')
|
width=2, fill=None, outline='green')
|
||||||
# restore game geometry
|
|
||||||
if self.app.opt.save_games_geometry:
|
|
||||||
w, h = self.app.opt.games_geometry.get(self.id, (0, 0))
|
|
||||||
w, h = max(w, self.width), max(h, self.height)
|
|
||||||
self.canvas.config(width=w, height=h)
|
|
||||||
#
|
#
|
||||||
self.stats.update_time = time.time()
|
self.stats.update_time = time.time()
|
||||||
self.busy = old_busy
|
self.busy = old_busy
|
||||||
|
@ -253,10 +259,9 @@ class Game:
|
||||||
bind(self.canvas, "<2>", self.clickHandler)
|
bind(self.canvas, "<2>", self.clickHandler)
|
||||||
##bind(self.canvas, "<3>", self.clickHandler)
|
##bind(self.canvas, "<3>", self.clickHandler)
|
||||||
##bind(self.canvas, "<Double-1>", self.undoHandler)
|
##bind(self.canvas, "<Double-1>", self.undoHandler)
|
||||||
##bind(self.canvas, "<Double-1>", self.undoHandler)
|
|
||||||
bind(self.canvas, "<1>", self.undoHandler)
|
bind(self.canvas, "<1>", self.undoHandler)
|
||||||
bind(self.canvas, "<3>", self.redoHandler)
|
bind(self.canvas, "<3>", self.redoHandler)
|
||||||
bind(self.top, '<Unmap>', self._unmapHandler)
|
bind(self.canvas, '<Unmap>', self._unmapHandler)
|
||||||
|
|
||||||
def __createCommon(self, app):
|
def __createCommon(self, app):
|
||||||
self.busy = 1
|
self.busy = 1
|
||||||
|
@ -324,6 +329,7 @@ class Game:
|
||||||
def reset(self, restart=0):
|
def reset(self, restart=0):
|
||||||
self.filename = ""
|
self.filename = ""
|
||||||
self.demo = None
|
self.demo = None
|
||||||
|
self.solver = None
|
||||||
self.hints = Struct(
|
self.hints = Struct(
|
||||||
list = None, # list of hints for the current move
|
list = None, # list of hints for the current move
|
||||||
index = -1,
|
index = -1,
|
||||||
|
@ -337,6 +343,7 @@ class Game:
|
||||||
talon_round = 1,
|
talon_round = 1,
|
||||||
ncards = 0,
|
ncards = 0,
|
||||||
)
|
)
|
||||||
|
self.snapshots = []
|
||||||
# local statistics are reset on each game restart
|
# local statistics are reset on each game restart
|
||||||
self.stats = Struct(
|
self.stats = Struct(
|
||||||
hints = 0, # number of hints consumed
|
hints = 0, # number of hints consumed
|
||||||
|
@ -434,6 +441,7 @@ class Game:
|
||||||
gamenumber=self.getGameNumber(format=1),
|
gamenumber=self.getGameNumber(format=1),
|
||||||
moves=(0, 0),
|
moves=(0, 0),
|
||||||
stats=self.app.stats.getStats(self.app.opt.player, self.id))
|
stats=self.app.stats.getStats(self.app.opt.player, self.id))
|
||||||
|
reset_solver_dialog()
|
||||||
# unhide toplevel when we use a progress bar
|
# unhide toplevel when we use a progress bar
|
||||||
if not self.preview:
|
if not self.preview:
|
||||||
wm_map(self.top, maximized=self.app.opt.wm_maximized)
|
wm_map(self.top, maximized=self.app.opt.wm_maximized)
|
||||||
|
@ -458,6 +466,7 @@ class Game:
|
||||||
self.startMoves()
|
self.startMoves()
|
||||||
for stack in self.allstacks:
|
for stack in self.allstacks:
|
||||||
stack.updateText()
|
stack.updateText()
|
||||||
|
self.updateSnapshots()
|
||||||
self.updateText()
|
self.updateText()
|
||||||
self.updateStatus(moves=(0, 0))
|
self.updateStatus(moves=(0, 0))
|
||||||
self.updateMenus()
|
self.updateMenus()
|
||||||
|
@ -490,6 +499,7 @@ class Game:
|
||||||
self.gsaveinfo = game.gsaveinfo
|
self.gsaveinfo = game.gsaveinfo
|
||||||
self.s.talon.round = game.loadinfo.talon_round
|
self.s.talon.round = game.loadinfo.talon_round
|
||||||
self.finished = game.finished
|
self.finished = game.finished
|
||||||
|
self.snapshots = game.snapshots
|
||||||
# 3) move cards to stacks
|
# 3) move cards to stacks
|
||||||
assert len(self.allstacks) == len(game.loadinfo.stacks)
|
assert len(self.allstacks) == len(game.loadinfo.stacks)
|
||||||
for i in range(len(self.allstacks)):
|
for i in range(len(self.allstacks)):
|
||||||
|
@ -644,6 +654,49 @@ class Game:
|
||||||
def leaveState(self, old_state):
|
def leaveState(self, old_state):
|
||||||
self.moves.state = old_state
|
self.moves.state = old_state
|
||||||
|
|
||||||
|
def getSnapshot(self, hex=False):
|
||||||
|
# generate hash (unique string) of current move
|
||||||
|
sn = []
|
||||||
|
for stack in self.allstacks:
|
||||||
|
s = []
|
||||||
|
for card in stack.cards:
|
||||||
|
s.append('%d%03d%d' % (card.suit, card.rank, card.face_up))
|
||||||
|
sn.append(''.join(s))
|
||||||
|
sn = '-'.join(sn)
|
||||||
|
# make more short string
|
||||||
|
if hex:
|
||||||
|
sn = md5.new(sn).hexdigest()
|
||||||
|
else:
|
||||||
|
sn = md5.new(sn).digest()
|
||||||
|
return sn
|
||||||
|
|
||||||
|
def createSnGroups(self):
|
||||||
|
# group stacks by class and cap
|
||||||
|
sg = {}
|
||||||
|
for s in self.allstacks:
|
||||||
|
for k in sg:
|
||||||
|
if s.__class__ is k.__class__ and \
|
||||||
|
s.cap.__dict__ == k.cap.__dict__:
|
||||||
|
g = sg[k]
|
||||||
|
g.append(s.id)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# new group
|
||||||
|
sg[s] = [s.id]
|
||||||
|
sg = sg.values()
|
||||||
|
self.sn_groups = sg
|
||||||
|
##print sg
|
||||||
|
|
||||||
|
|
||||||
|
def updateSnapshots(self):
|
||||||
|
sn = self.getSnapshot()
|
||||||
|
if sn in self.snapshots:
|
||||||
|
##self.updateStatus(snapshot=True)
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.snapshots.append(sn)
|
||||||
|
##self.updateStatus(snapshot=False)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# card creation & shuffling
|
# card creation & shuffling
|
||||||
|
@ -810,7 +863,10 @@ class Game:
|
||||||
if self.demo:
|
if self.demo:
|
||||||
self.stopDemo()
|
self.stopDemo()
|
||||||
return
|
return
|
||||||
if self.app.opt.mouse_undo and not self.event_handled:
|
if not self.event_handled:
|
||||||
|
if self.drag.stack:
|
||||||
|
self.drag.stack.cancelDrag(event)
|
||||||
|
elif self.app.opt.mouse_undo:
|
||||||
self.app.menubar.mUndo()
|
self.app.menubar.mUndo()
|
||||||
self.event_handled = False
|
self.event_handled = False
|
||||||
return EVENT_PROPAGATE
|
return EVENT_PROPAGATE
|
||||||
|
@ -823,7 +879,10 @@ class Game:
|
||||||
if self.demo:
|
if self.demo:
|
||||||
self.stopDemo()
|
self.stopDemo()
|
||||||
return
|
return
|
||||||
if self.app.opt.mouse_undo and not self.event_handled:
|
if not self.event_handled:
|
||||||
|
if self.drag.stack:
|
||||||
|
self.drag.stack.cancelDrag(event)
|
||||||
|
elif self.app.opt.mouse_undo:
|
||||||
self.app.menubar.mRedo()
|
self.app.menubar.mRedo()
|
||||||
self.event_handled = False
|
self.event_handled = False
|
||||||
return EVENT_PROPAGATE
|
return EVENT_PROPAGATE
|
||||||
|
@ -895,7 +954,7 @@ class Game:
|
||||||
|
|
||||||
def _unmapHandler(self, event):
|
def _unmapHandler(self, event):
|
||||||
# pause game if root window has been iconified
|
# pause game if root window has been iconified
|
||||||
if event.widget is self.top and not self.pause:
|
if self.app and not self.pause:
|
||||||
self.app.menubar.mPause()
|
self.app.menubar.mPause()
|
||||||
|
|
||||||
|
|
||||||
|
@ -925,11 +984,11 @@ class Game:
|
||||||
if a and not self.preview:
|
if a and not self.preview:
|
||||||
self.canvas.update_idletasks()
|
self.canvas.update_idletasks()
|
||||||
if self.app.audio and self.app.opt.sound and self.app.opt.sound_samples['deal']:
|
if self.app.audio and self.app.opt.sound and self.app.opt.sound_samples['deal']:
|
||||||
if a in (1, 2, 5):
|
if a in (1, 2, 3, 10):
|
||||||
self.playSample("deal01", priority=100, loop=loop)
|
self.playSample("deal01", priority=100, loop=loop)
|
||||||
elif a == 3:
|
|
||||||
self.playSample("deal04", priority=100, loop=loop)
|
|
||||||
elif a == 4:
|
elif a == 4:
|
||||||
|
self.playSample("deal04", priority=100, loop=loop)
|
||||||
|
elif a == 5:
|
||||||
self.playSample("deal08", priority=100, loop=loop)
|
self.playSample("deal08", priority=100, loop=loop)
|
||||||
|
|
||||||
|
|
||||||
|
@ -960,7 +1019,16 @@ class Game:
|
||||||
bitmap="error")
|
bitmap="error")
|
||||||
|
|
||||||
# main animation method
|
# main animation method
|
||||||
def animatedMoveTo(self, from_stack, to_stack, cards, x, y, tkraise=1, frames=-1, shadow=-1):
|
def animatedMoveTo(self, from_stack, to_stack, cards, x, y,
|
||||||
|
tkraise=1, frames=-1, shadow=-1):
|
||||||
|
# available values of app.opt.animations:
|
||||||
|
# 0 - without animations
|
||||||
|
# 1 - very fast (without timer)
|
||||||
|
# 2 - fast (default)
|
||||||
|
# 3 - medium (2/3 of fast speed)
|
||||||
|
# 4 - slow (1/4 of fast speed)
|
||||||
|
# 5 - very slow (1/8 of fast speed)
|
||||||
|
# 10 - used internally in game preview
|
||||||
if self.app.opt.animations == 0 or frames == 0:
|
if self.app.opt.animations == 0 or frames == 0:
|
||||||
return
|
return
|
||||||
# init timer - need a high resolution for this to work
|
# init timer - need a high resolution for this to work
|
||||||
|
@ -971,13 +1039,16 @@ class Game:
|
||||||
if frames < 0:
|
if frames < 0:
|
||||||
frames = 8
|
frames = 8
|
||||||
assert frames >= 2
|
assert frames >= 2
|
||||||
if self.app.opt.animations == 3: # slow
|
if self.app.opt.animations == 3: # medium
|
||||||
|
frames = frames * 3
|
||||||
|
SPF = SPF / 2
|
||||||
|
elif self.app.opt.animations == 4: # slow
|
||||||
frames = frames * 8
|
frames = frames * 8
|
||||||
SPF = SPF / 2
|
SPF = SPF / 2
|
||||||
elif self.app.opt.animations == 4: # very slow
|
elif self.app.opt.animations == 5: # very slow
|
||||||
frames = frames * 16
|
frames = frames * 16
|
||||||
SPF = SPF / 2
|
SPF = SPF / 2
|
||||||
elif self.app.opt.animations == 5:
|
elif self.app.opt.animations == 10:
|
||||||
# this is used internally in game preview to speed up
|
# this is used internally in game preview to speed up
|
||||||
# the initial dealing
|
# the initial dealing
|
||||||
if self.moves.state == self.S_INIT and frames > 4:
|
if self.moves.state == self.S_INIT and frames > 4:
|
||||||
|
@ -986,7 +1057,6 @@ class Game:
|
||||||
shadow = self.app.opt.shadow
|
shadow = self.app.opt.shadow
|
||||||
shadows = ()
|
shadows = ()
|
||||||
# start animation
|
# start animation
|
||||||
from_stack._unshadeStack()
|
|
||||||
if tkraise:
|
if tkraise:
|
||||||
for card in cards:
|
for card in cards:
|
||||||
card.tkraise()
|
card.tkraise()
|
||||||
|
@ -1030,21 +1100,19 @@ class Game:
|
||||||
card.moveBy(dx, dy)
|
card.moveBy(dx, dy)
|
||||||
self.canvas.update_idletasks()
|
self.canvas.update_idletasks()
|
||||||
|
|
||||||
def animatedFlip(self, stack):
|
|
||||||
|
def doAnimatedFlipAndMove(self, from_stack, to_stack=None, frames=-1):
|
||||||
|
if self.app.opt.animations == 0 or frames == 0:
|
||||||
return False
|
return False
|
||||||
if self.app.opt.animations == 0:
|
if not from_stack.cards:
|
||||||
return False
|
return False
|
||||||
if TOOLKIT == 'gtk':
|
if TOOLKIT == 'gtk':
|
||||||
return False
|
return False
|
||||||
if not stack.cards:
|
|
||||||
return False
|
|
||||||
if not Image:
|
if not Image:
|
||||||
return False
|
return False
|
||||||
if self.moves.state == self.S_INIT:
|
|
||||||
# don't use flip animation for initial dealing
|
|
||||||
return False
|
|
||||||
canvas = self.canvas
|
canvas = self.canvas
|
||||||
card = stack.cards[-1]
|
card = from_stack.cards[-1]
|
||||||
im1 = card._active_image._pil_image
|
im1 = card._active_image._pil_image
|
||||||
if card.face_up:
|
if card.face_up:
|
||||||
im2 = card._back_image._pil_image
|
im2 = card._back_image._pil_image
|
||||||
|
@ -1053,51 +1121,134 @@ class Game:
|
||||||
w, h = im1.size
|
w, h = im1.size
|
||||||
id = card.item.id
|
id = card.item.id
|
||||||
#
|
#
|
||||||
delay = 10
|
SPF = 0.1/8 # animation speed - seconds per frame
|
||||||
frames = 3.0 # num frames for each step
|
frames = 4.0 # num frames for each step
|
||||||
if self.app.opt.animations == 3: # slow
|
if self.app.opt.animations == 3: # medium
|
||||||
delay = 10
|
SPF = 0.1/8
|
||||||
frames = 7.0
|
frames = 7.0
|
||||||
elif self.app.opt.animations == 4: # very slow
|
elif self.app.opt.animations == 4: # slow
|
||||||
delay = 10
|
SPF = 0.1/8
|
||||||
frames = 12.0
|
frames = 12.0
|
||||||
delta = 2*int(w/frames/2) # should be even for save position
|
elif self.app.opt.animations == 5: # very slow
|
||||||
ddx, ddy = 0, self.app.images.SHADOW_YOFFSET/2 # ascent of the card
|
SPF = 0.1/8
|
||||||
# siep 1
|
frames = 24.0
|
||||||
ww = w
|
|
||||||
dx = delta/2
|
if to_stack is None:
|
||||||
canvas.move(id, -ddx, -ddy)
|
x0, y0 = from_stack.getPositionFor(card)
|
||||||
canvas.update_idletasks()
|
x1, y1 = x0, y0
|
||||||
canvas.after(delay)
|
dest_x, dest_y = 0, 0
|
||||||
while True:
|
else:
|
||||||
if ww-delta <= 0:
|
x0, y0 = from_stack.getPositionFor(card)
|
||||||
break
|
x1, y1 = to_stack.getPositionForNextCard()
|
||||||
ww -= delta
|
dest_x, dest_y = x1-x0, y1-y0
|
||||||
tmp = im1.resize((ww, h))
|
|
||||||
|
if dest_x == 0 and dest_y == 0:
|
||||||
|
# flip
|
||||||
|
#ascent_dx, ascent_dy = 0, self.app.images.SHADOW_YOFFSET/frames
|
||||||
|
ascent_dx, ascent_dy = 0, h/10.0/frames
|
||||||
|
min_size = w/10
|
||||||
|
shrink_dx = (w-min_size) / (frames-1)
|
||||||
|
shrink_dy = 0
|
||||||
|
elif dest_y == 0:
|
||||||
|
# move to left/right waste
|
||||||
|
#ascent_dx, ascent_dy = 0, self.app.images.SHADOW_YOFFSET/frames
|
||||||
|
ascent_dx, ascent_dy = 0, h/10.0/frames
|
||||||
|
min_size = w/10
|
||||||
|
shrink_dx = (w-min_size) / (frames-1)
|
||||||
|
shrink_dy = 0
|
||||||
|
elif dest_x == 0:
|
||||||
|
# move to top/bottom waste
|
||||||
|
return False
|
||||||
|
ascent_dx, ascent_dy = 0, 0
|
||||||
|
## min_size = h/10
|
||||||
|
## shrink_dx = 0
|
||||||
|
## shrink_dy = (h-min_size) / (frames-1)
|
||||||
|
min_size = w/10
|
||||||
|
shrink_dx = (w-min_size) / (frames-1)
|
||||||
|
shrink_dy = 0
|
||||||
|
|
||||||
|
else:
|
||||||
|
# dest_x != 0 and dest_y != 0
|
||||||
|
return False
|
||||||
|
|
||||||
|
move_dx = dest_x / frames / 2
|
||||||
|
move_dy = dest_y / frames / 2
|
||||||
|
xpos, ypos = float(x0), float(y0)
|
||||||
|
|
||||||
|
card.tkraise()
|
||||||
|
|
||||||
|
# step 1
|
||||||
|
d_x = shrink_dx/2+move_dx-ascent_dx
|
||||||
|
d_y = shrink_dy/2+move_dy-ascent_dy
|
||||||
|
nframe = 0
|
||||||
|
while nframe < frames:
|
||||||
|
starttime = uclock()
|
||||||
|
# resize img
|
||||||
|
ww = w - nframe*shrink_dx
|
||||||
|
hh = h - nframe*shrink_dy
|
||||||
|
tmp = im1.resize((int(ww), int(hh)))
|
||||||
tk_tmp = ImageTk.PhotoImage(image=tmp)
|
tk_tmp = ImageTk.PhotoImage(image=tmp)
|
||||||
canvas.itemconfig(id, image=tk_tmp)
|
canvas.itemconfig(id, image=tk_tmp)
|
||||||
canvas.move(id, dx, 0)
|
# move img
|
||||||
|
xpos += d_x
|
||||||
|
ypos += d_y
|
||||||
|
card.moveTo(int(round(xpos)), int(round(ypos)))
|
||||||
canvas.update_idletasks()
|
canvas.update_idletasks()
|
||||||
canvas.after(delay)
|
|
||||||
dx = -dx
|
nframe += 1
|
||||||
|
t = (SPF-(uclock()-starttime))*1000 # milliseconds
|
||||||
|
if t > 0:
|
||||||
|
usleep(t/1000)
|
||||||
|
## else:
|
||||||
|
## nframe += 1
|
||||||
|
## xpos += d_x
|
||||||
|
## ypos += d_y
|
||||||
|
|
||||||
# step 2
|
# step 2
|
||||||
while True:
|
d_x = -shrink_dx/2+move_dx+ascent_dx
|
||||||
tmp = im2.resize((ww, h))
|
d_y = -shrink_dy/2+move_dy+ascent_dy
|
||||||
|
nframe = 0
|
||||||
|
while nframe < frames:
|
||||||
|
starttime = uclock()
|
||||||
|
# resize img
|
||||||
|
ww = w - (frames-nframe-1)*shrink_dx
|
||||||
|
hh = h - (frames-nframe-1)*shrink_dy
|
||||||
|
tmp = im2.resize((int(ww), int(hh)))
|
||||||
tk_tmp = ImageTk.PhotoImage(image=tmp)
|
tk_tmp = ImageTk.PhotoImage(image=tmp)
|
||||||
canvas.itemconfig(id, image=tk_tmp)
|
canvas.itemconfig(id, image=tk_tmp)
|
||||||
canvas.move(id, dx, 0)
|
# move img
|
||||||
|
xpos += d_x
|
||||||
|
ypos += d_y
|
||||||
|
card.moveTo(int(round(xpos)), int(round(ypos)))
|
||||||
canvas.update_idletasks()
|
canvas.update_idletasks()
|
||||||
canvas.after(delay)
|
|
||||||
ww += delta
|
nframe += 1
|
||||||
if ww >= w:
|
t = (SPF-(uclock()-starttime))*1000 # milliseconds
|
||||||
break
|
if t > 0:
|
||||||
canvas.move(id, ddx, ddy)
|
usleep(t/1000)
|
||||||
|
## else:
|
||||||
|
## nframe += 1
|
||||||
|
## xpos += d_x
|
||||||
|
## ypos += d_y
|
||||||
|
|
||||||
|
card.moveTo(x1, y1)
|
||||||
|
#canvas.update_idletasks()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def doWinAnimation(self):
|
def animatedFlip(self, stack):
|
||||||
|
##return False
|
||||||
|
return self.doAnimatedFlipAndMove(stack)
|
||||||
|
|
||||||
|
def animatedFlipAndMove(self, from_stack, to_stack, frames=-1):
|
||||||
|
##return False
|
||||||
|
return self.doAnimatedFlipAndMove(from_stack, to_stack, frames)
|
||||||
|
|
||||||
|
|
||||||
|
def winAnimationEvent(self):
|
||||||
# based on code from pygtk-demo
|
# based on code from pygtk-demo
|
||||||
FRAME_DELAY = 40
|
FRAME_DELAY = 80
|
||||||
CYCLE_LEN = 60
|
CYCLE_LEN = 60
|
||||||
|
starttime = uclock()
|
||||||
images = self.win_animation.images
|
images = self.win_animation.images
|
||||||
saved_images = self.win_animation.saved_images # cached images
|
saved_images = self.win_animation.saved_images # cached images
|
||||||
canvas = self.canvas
|
canvas = self.canvas
|
||||||
|
@ -1107,6 +1258,10 @@ class Game:
|
||||||
x0 = int(int(canvas.cget('width'))*(canvas.xview()[0]))
|
x0 = int(int(canvas.cget('width'))*(canvas.xview()[0]))
|
||||||
y0 = int(int(canvas.cget('height'))*(canvas.yview()[0]))
|
y0 = int(int(canvas.cget('height'))*(canvas.yview()[0]))
|
||||||
width, height = self.win_animation.width, self.win_animation.height
|
width, height = self.win_animation.width, self.win_animation.height
|
||||||
|
cw = self.canvas.winfo_width()
|
||||||
|
ch = self.canvas.winfo_height()
|
||||||
|
x0 -= (width-cw)/2
|
||||||
|
y0 -= (height-ch)/2
|
||||||
|
|
||||||
tmp_tk_images = []
|
tmp_tk_images = []
|
||||||
raised_images = []
|
raised_images = []
|
||||||
|
@ -1143,7 +1298,7 @@ class Game:
|
||||||
if round_k == 100:
|
if round_k == 100:
|
||||||
tmp = im
|
tmp = im
|
||||||
else:
|
else:
|
||||||
tmp = im.resize(new_size, resample=Image.BICUBIC)
|
tmp = im.resize(new_size, resample=Image.BILINEAR)
|
||||||
tk_tmp = ImageTk.PhotoImage(image=tmp)
|
tk_tmp = ImageTk.PhotoImage(image=tmp)
|
||||||
saved_images[img_index][round_k] = tk_tmp
|
saved_images[img_index][round_k] = tk_tmp
|
||||||
|
|
||||||
|
@ -1161,7 +1316,11 @@ class Game:
|
||||||
self.win_animation.tk_images = tmp_tk_images
|
self.win_animation.tk_images = tmp_tk_images
|
||||||
canvas.update_idletasks()
|
canvas.update_idletasks()
|
||||||
# loop
|
# loop
|
||||||
self.win_animation.timer = after(canvas, FRAME_DELAY, self.doWinAnimation)
|
t = FRAME_DELAY-int((uclock()-starttime)*1000)
|
||||||
|
if t > 0:
|
||||||
|
self.win_animation.timer = after(canvas, t, self.winAnimationEvent)
|
||||||
|
else:
|
||||||
|
self.win_animation.timer = after_idle(canvas, self.winAnimationEvent)
|
||||||
|
|
||||||
def stopWinAnimation(self):
|
def stopWinAnimation(self):
|
||||||
if self.win_animation.timer:
|
if self.win_animation.timer:
|
||||||
|
@ -1178,8 +1337,8 @@ class Game:
|
||||||
def winAnimation(self, perfect=0):
|
def winAnimation(self, perfect=0):
|
||||||
if self.preview:
|
if self.preview:
|
||||||
return
|
return
|
||||||
if not self.app.opt.animations:
|
#if not self.app.opt.animations:
|
||||||
return
|
# return
|
||||||
if not self.app.opt.win_animation:
|
if not self.app.opt.win_animation:
|
||||||
return
|
return
|
||||||
if TOOLKIT == 'gtk':
|
if TOOLKIT == 'gtk':
|
||||||
|
@ -1190,7 +1349,8 @@ class Game:
|
||||||
# select some random cards
|
# select some random cards
|
||||||
cards = self.cards[:]
|
cards = self.cards[:]
|
||||||
scards = []
|
scards = []
|
||||||
for i in xrange(10):
|
ncards = min(10, len(cards))
|
||||||
|
for i in xrange(ncards):
|
||||||
c = self.app.miscrandom.choice(cards)
|
c = self.app.miscrandom.choice(cards)
|
||||||
scards.append(c)
|
scards.append(c)
|
||||||
cards.remove(c)
|
cards.remove(c)
|
||||||
|
@ -1200,7 +1360,8 @@ class Game:
|
||||||
self.win_animation.width = self.canvas.winfo_width()
|
self.win_animation.width = self.canvas.winfo_width()
|
||||||
self.win_animation.height = self.canvas.winfo_height()
|
self.win_animation.height = self.canvas.winfo_height()
|
||||||
# run win animation in background
|
# run win animation in background
|
||||||
after_idle(self.canvas, self.doWinAnimation)
|
##after_idle(self.canvas, self.winAnimationEvent)
|
||||||
|
after(self.canvas, 200, self.winAnimationEvent)
|
||||||
return
|
return
|
||||||
|
|
||||||
def redealAnimation(self):
|
def redealAnimation(self):
|
||||||
|
@ -1208,14 +1369,6 @@ class Game:
|
||||||
return
|
return
|
||||||
if not self.app.opt.animations or not self.app.opt.redeal_animation:
|
if not self.app.opt.animations or not self.app.opt.redeal_animation:
|
||||||
return
|
return
|
||||||
self.setCursor(cursor=CURSOR_WATCH)
|
|
||||||
self.top.busyUpdate()
|
|
||||||
self.canvas.update_idletasks()
|
|
||||||
old_a = self.app.opt.animations
|
|
||||||
if old_a == 0:
|
|
||||||
self.app.opt.animations = 1 # timer based
|
|
||||||
elif old_a == 4: # very slow
|
|
||||||
self.app.opt.animations = 3 # slow
|
|
||||||
cards = []
|
cards = []
|
||||||
for s in self.allstacks:
|
for s in self.allstacks:
|
||||||
if s is not self.s.talon:
|
if s is not self.s.talon:
|
||||||
|
@ -1223,6 +1376,16 @@ class Game:
|
||||||
cards.append((c,s))
|
cards.append((c,s))
|
||||||
if not cards:
|
if not cards:
|
||||||
return
|
return
|
||||||
|
self.setCursor(cursor=CURSOR_WATCH)
|
||||||
|
self.top.busyUpdate()
|
||||||
|
self.canvas.update_idletasks()
|
||||||
|
old_a = self.app.opt.animations
|
||||||
|
if old_a == 0:
|
||||||
|
self.app.opt.animations = 1 # very fast
|
||||||
|
elif old_a == 3: # medium
|
||||||
|
self.app.opt.animations = 2 # fast
|
||||||
|
elif old_a == 4: # very slow
|
||||||
|
self.app.opt.animations = 3 # slow
|
||||||
# select some random cards
|
# select some random cards
|
||||||
acards = []
|
acards = []
|
||||||
scards = cards[:]
|
scards = cards[:]
|
||||||
|
@ -1381,6 +1544,7 @@ class Game:
|
||||||
|
|
||||||
# the actual hint class (or None)
|
# the actual hint class (or None)
|
||||||
Hint_Class = DefaultHint
|
Hint_Class = DefaultHint
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
def getHintClass(self):
|
def getHintClass(self):
|
||||||
return self.Hint_Class
|
return self.Hint_Class
|
||||||
|
@ -1625,7 +1789,8 @@ for %d moves.
|
||||||
if s.canFlipCard():
|
if s.canFlipCard():
|
||||||
if sound:
|
if sound:
|
||||||
self.playSample("autoflip", priority=5)
|
self.playSample("autoflip", priority=5)
|
||||||
s.flipMove()
|
#~s.flipMove()
|
||||||
|
s.flipMove(animation=True)
|
||||||
done_something = 1
|
done_something = 1
|
||||||
# each single flip is undo-able unless opt.autofaceup
|
# each single flip is undo-able unless opt.autofaceup
|
||||||
self.finishMove()
|
self.finishMove()
|
||||||
|
@ -1661,6 +1826,13 @@ for %d moves.
|
||||||
return self.dealCards(sound=sound)
|
return self.dealCards(sound=sound)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def autoDrop(self, autofaceup=-1):
|
||||||
|
old_a = self.app.opt.animations
|
||||||
|
if old_a == 3: # medium
|
||||||
|
self.app.opt.animations = 2 # fast
|
||||||
|
self.autoPlay(autofaceup=autofaceup, autodrop=1)
|
||||||
|
self.app.opt.animations = old_a
|
||||||
|
|
||||||
## for find_card_dialog
|
## for find_card_dialog
|
||||||
def highlightCard(self, suit, rank):
|
def highlightCard(self, suit, rank):
|
||||||
if not self.app:
|
if not self.app:
|
||||||
|
@ -1681,11 +1853,12 @@ for %d moves.
|
||||||
return ((self.sg.hp_stacks, 2),)
|
return ((self.sg.hp_stacks, 2),)
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
def _highlightCards(self, info, sleep=1.5):
|
def _highlightCards(self, info, sleep=1.5, delta=(1,1,1,1)):
|
||||||
if not info:
|
if not info:
|
||||||
return 0
|
return 0
|
||||||
if self.pause:
|
if self.pause:
|
||||||
return 0
|
return 0
|
||||||
|
self.stopWinAnimation()
|
||||||
items = []
|
items = []
|
||||||
for s, c1, c2, color in info:
|
for s, c1, c2, color in info:
|
||||||
assert c1 in s.cards and c2 in s.cards
|
assert c1 in s.cards and c2 in s.cards
|
||||||
|
@ -1741,13 +1914,15 @@ for %d moves.
|
||||||
y2 = y2 + self.app.images.CARDH
|
y2 = y2 + self.app.images.CARDH
|
||||||
tkraise = True
|
tkraise = True
|
||||||
##print c1, c2, x1, y1, x2, y2
|
##print c1, c2, x1, y1, x2, y2
|
||||||
|
x1, x2 = x1-delta[0], x2+delta[1]
|
||||||
|
y1, y2 = y1-delta[2], y2+delta[3]
|
||||||
if TOOLKIT == 'tk':
|
if TOOLKIT == 'tk':
|
||||||
r = MfxCanvasRectangle(self.canvas, x1-1, y1-1, x2+1, y2+1,
|
r = MfxCanvasRectangle(self.canvas, x1, y1, x2, y2,
|
||||||
width=4, fill=None, outline=color)
|
width=4, fill=None, outline=color)
|
||||||
if tkraise:
|
if tkraise:
|
||||||
r.tkraise(c2.item)
|
r.tkraise(c2.item)
|
||||||
elif TOOLKIT == 'gtk':
|
elif TOOLKIT == 'gtk':
|
||||||
r = MfxCanvasRectangle(self.canvas, x1-1, y1-1, x2+1, y2+1,
|
r = MfxCanvasRectangle(self.canvas, x1, y1, x2, y2,
|
||||||
width=4, fill=None, outline=color,
|
width=4, fill=None, outline=color,
|
||||||
group=s.group)
|
group=s.group)
|
||||||
if tkraise:
|
if tkraise:
|
||||||
|
@ -1801,7 +1976,7 @@ for %d moves.
|
||||||
for s in si[0]:
|
for s in si[0]:
|
||||||
pile = s.getPile()
|
pile = s.getPile()
|
||||||
if pile and len(pile) >= si[1]:
|
if pile and len(pile) >= si[1]:
|
||||||
hi.append((s, pile[0], pile[-1], col[1]))
|
hi.append((s, pile[0], pile[-1], col))
|
||||||
if not hi:
|
if not hi:
|
||||||
self.highlightNotMatching()
|
self.highlightNotMatching()
|
||||||
return 0
|
return 0
|
||||||
|
@ -1855,7 +2030,7 @@ for %d moves.
|
||||||
# for spider-type stacks
|
# for spider-type stacks
|
||||||
if to_stack.cards:
|
if to_stack.cards:
|
||||||
# check suit
|
# check suit
|
||||||
return int(from_stack.cards[-1].suit == to_stack.cards[-1].suit)+1
|
return int(from_stack.cards[-ncards].suit == to_stack.cards[-1].suit)+1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -1896,6 +2071,10 @@ for %d moves.
|
||||||
# compute all hints for the current position
|
# compute all hints for the current position
|
||||||
# this is the only method that actually uses class Hint
|
# this is the only method that actually uses class Hint
|
||||||
def getHints(self, level, taken_hint=None):
|
def getHints(self, level, taken_hint=None):
|
||||||
|
if level == 3:
|
||||||
|
#if self.solver is None:
|
||||||
|
# return None
|
||||||
|
return self.solver.getHints(taken_hint)
|
||||||
hint_class = self.getHintClass()
|
hint_class = self.getHintClass()
|
||||||
if hint_class is None:
|
if hint_class is None:
|
||||||
return None
|
return None
|
||||||
|
@ -1941,10 +2120,17 @@ for %d moves.
|
||||||
# a move move
|
# a move move
|
||||||
assert to_stack
|
assert to_stack
|
||||||
assert 1 <= ncards <= len(from_stack.cards)
|
assert 1 <= ncards <= len(from_stack.cards)
|
||||||
|
if DEBUG:
|
||||||
|
if not to_stack.acceptsCards(
|
||||||
|
from_stack, from_stack.cards[-ncards:]):
|
||||||
|
print '*fail accepts cards*', from_stack, to_stack, ncards
|
||||||
|
if not from_stack.canMoveCards(from_stack.cards[-ncards:]):
|
||||||
|
print '*fail move cards*', from_stack, ncards
|
||||||
|
##assert from_stack.canMoveCards(from_stack.cards[-ncards:]) # FIXME: Pyramid
|
||||||
assert to_stack.acceptsCards(from_stack, from_stack.cards[-ncards:])
|
assert to_stack.acceptsCards(from_stack, from_stack.cards[-ncards:])
|
||||||
if sleep <= 0.0:
|
if sleep <= 0.0:
|
||||||
return h
|
return h
|
||||||
info = (level == 1) or (level > 1 and DEBUG >= 3)
|
info = (level == 1) or (level > 1 and DEBUG)
|
||||||
if info and self.app.statusbar and self.app.opt.statusbar:
|
if info and self.app.statusbar and self.app.opt.statusbar:
|
||||||
self.app.statusbar.configLabel("info", text=_("Score %6d") % (score), fg=text_color)
|
self.app.statusbar.configLabel("info", text=_("Score %6d") % (score), fg=text_color)
|
||||||
else:
|
else:
|
||||||
|
@ -2000,6 +2186,7 @@ for %d moves.
|
||||||
mixed = mixed,
|
mixed = mixed,
|
||||||
sleep = self.app.opt.timeouts['demo'],
|
sleep = self.app.opt.timeouts['demo'],
|
||||||
last_deal = [],
|
last_deal = [],
|
||||||
|
snapshots = [],
|
||||||
hint = None,
|
hint = None,
|
||||||
keypress = None,
|
keypress = None,
|
||||||
start_demo_moves = self.stats.demo_moves,
|
start_demo_moves = self.stats.demo_moves,
|
||||||
|
@ -2036,6 +2223,8 @@ for %d moves.
|
||||||
timeout = 10000
|
timeout = 10000
|
||||||
if 1 and player_moves == 0:
|
if 1 and player_moves == 0:
|
||||||
timeout = 5000
|
timeout = 5000
|
||||||
|
if self.demo and self.demo.level == 3:
|
||||||
|
timeout = 0
|
||||||
if self.isGameWon():
|
if self.isGameWon():
|
||||||
self.updateTime()
|
self.updateTime()
|
||||||
finished = 1
|
finished = 1
|
||||||
|
@ -2044,7 +2233,7 @@ for %d moves.
|
||||||
if not self.top.winfo_ismapped():
|
if not self.top.winfo_ismapped():
|
||||||
status = 2
|
status = 2
|
||||||
elif player_moves == 0:
|
elif player_moves == 0:
|
||||||
self.playSample("autopilotwon")
|
self.playSample("autopilotwon", priority=1000)
|
||||||
s = self.app.miscrandom.choice((_("&Great"), _("&Cool"), _("&Yeah"), _("&Wow"))) # ??? accelerators
|
s = self.app.miscrandom.choice((_("&Great"), _("&Cool"), _("&Yeah"), _("&Wow"))) # ??? accelerators
|
||||||
d = MfxMessageDialog(self.top, title=PACKAGE+_(" Autopilot"),
|
d = MfxMessageDialog(self.top, title=PACKAGE+_(" Autopilot"),
|
||||||
text=_("\nGame solved in %d moves.\n") % self.moves.index,
|
text=_("\nGame solved in %d moves.\n") % self.moves.index,
|
||||||
|
@ -2067,7 +2256,7 @@ for %d moves.
|
||||||
status = 2
|
status = 2
|
||||||
else:
|
else:
|
||||||
if player_moves == 0:
|
if player_moves == 0:
|
||||||
self.playSample("autopilotlost")
|
self.playSample("autopilotlost", priority=1000)
|
||||||
s = self.app.miscrandom.choice((_("&Oh well"), _("&That's life"), _("&Hmm"))) # ??? accelerators
|
s = self.app.miscrandom.choice((_("&Oh well"), _("&That's life"), _("&Hmm"))) # ??? accelerators
|
||||||
d = MfxMessageDialog(self.top, title=PACKAGE+_(" Autopilot"),
|
d = MfxMessageDialog(self.top, title=PACKAGE+_(" Autopilot"),
|
||||||
text=_("\nThis won't come out...\n"),
|
text=_("\nThis won't come out...\n"),
|
||||||
|
@ -2076,7 +2265,7 @@ for %d moves.
|
||||||
status = d.status
|
status = d.status
|
||||||
if finished:
|
if finished:
|
||||||
self.updateStats(demo=1)
|
self.updateStats(demo=1)
|
||||||
if self.demo and status == 2:
|
if not DEBUG and self.demo and status == 2:
|
||||||
# timeout in dialog
|
# timeout in dialog
|
||||||
if self.stats.demo_moves > self.demo.start_demo_moves:
|
if self.stats.demo_moves > self.demo.start_demo_moves:
|
||||||
# we only increase the splash-screen counter if the last
|
# we only increase the splash-screen counter if the last
|
||||||
|
@ -2143,9 +2332,10 @@ for %d moves.
|
||||||
score, pos, ncards, from_stack, to_stack, text_color, forced_move = h
|
score, pos, ncards, from_stack, to_stack, text_color, forced_move = h
|
||||||
if ncards == 0:
|
if ncards == 0:
|
||||||
# a deal-move
|
# a deal-move
|
||||||
|
# do not let games like Klondike and Canfield deal forever
|
||||||
if self.dealCards() == 0:
|
if self.dealCards() == 0:
|
||||||
return 1
|
return 1
|
||||||
# do not let games like Klondike and Canfield deal forever
|
if 0: # old version, based on dealing card
|
||||||
c = self.s.talon.getCard()
|
c = self.s.talon.getCard()
|
||||||
if c in demo.last_deal:
|
if c in demo.last_deal:
|
||||||
# We went through the whole Talon. Give up.
|
# We went through the whole Talon. Give up.
|
||||||
|
@ -2153,19 +2343,27 @@ for %d moves.
|
||||||
# Note that `None' is a valid entry in last_deal[]
|
# Note that `None' is a valid entry in last_deal[]
|
||||||
# (this means that all cards are on the Waste).
|
# (this means that all cards are on the Waste).
|
||||||
demo.last_deal.append(c)
|
demo.last_deal.append(c)
|
||||||
|
else: # new version, based on snapshots
|
||||||
|
# check snapshot
|
||||||
|
sn = self.getSnapshot()
|
||||||
|
if sn in demo.snapshots:
|
||||||
|
# not unique
|
||||||
|
return 1
|
||||||
|
demo.snapshots.append(sn)
|
||||||
elif from_stack == to_stack:
|
elif from_stack == to_stack:
|
||||||
# a flip-move
|
# a flip-move
|
||||||
from_stack.flipMove()
|
from_stack.flipMove(animation=True)
|
||||||
demo.last_deal = []
|
demo.last_deal = []
|
||||||
else:
|
else:
|
||||||
# a move-move
|
# a move-move
|
||||||
from_stack.moveMove(ncards, to_stack, frames=-1)
|
from_stack.moveMove(ncards, to_stack, frames=-1)
|
||||||
demo.last_deal = []
|
demo.last_deal = []
|
||||||
##print self.moves.index
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def createDemoInfoText(self):
|
def createDemoInfoText(self):
|
||||||
## TODO - the text placement is not fully ok
|
## TODO - the text placement is not fully ok
|
||||||
|
if DEBUG:
|
||||||
|
self.showHelp('help', self.getDemoInfoText())
|
||||||
return
|
return
|
||||||
if not self.demo or self.demo.info_text or self.preview:
|
if not self.demo or self.demo.info_text or self.preview:
|
||||||
return
|
return
|
||||||
|
@ -2177,13 +2375,15 @@ for %d moves.
|
||||||
]
|
]
|
||||||
ta = self.getDemoInfoTextAttr(tinfo)
|
ta = self.getDemoInfoTextAttr(tinfo)
|
||||||
if ta:
|
if ta:
|
||||||
font = self.app.getFont("canvas_large")
|
#font = self.app.getFont("canvas_large")
|
||||||
|
font = self.app.getFont("default")
|
||||||
self.demo.info_text = MfxCanvasText(self.canvas, ta[1], ta[2],
|
self.demo.info_text = MfxCanvasText(self.canvas, ta[1], ta[2],
|
||||||
anchor=ta[0], font=font,
|
anchor=ta[0], font=font,
|
||||||
text=self.getDemoInfoText())
|
text=self.getDemoInfoText())
|
||||||
|
|
||||||
def getDemoInfoText(self):
|
def getDemoInfoText(self):
|
||||||
return self.gameinfo.short_name
|
h = self.Hint_Class is None and 'None' or self.Hint_Class.__name__
|
||||||
|
return '%s (%s)' % (self.gameinfo.short_name, h)
|
||||||
|
|
||||||
def getDemoInfoTextAttr(self, tinfo):
|
def getDemoInfoTextAttr(self, tinfo):
|
||||||
items1, items2 = [], []
|
items1, items2 = [], []
|
||||||
|
@ -2291,6 +2491,21 @@ for %d moves.
|
||||||
am.do(self)
|
am.do(self)
|
||||||
self.hints.list = None
|
self.hints.list = None
|
||||||
|
|
||||||
|
def singleFlipMove(self, stack):
|
||||||
|
# flip with animation (without "moveMove" in this move)
|
||||||
|
assert stack
|
||||||
|
am = ASingleFlipMove(stack)
|
||||||
|
self.__storeMove(am)
|
||||||
|
am.do(self)
|
||||||
|
self.hints.list = None
|
||||||
|
|
||||||
|
def flipAndMoveMove(self, from_stack, to_stack, frames=-1):
|
||||||
|
assert from_stack and to_stack and (from_stack is not to_stack)
|
||||||
|
am = AFlipAndMoveMove(from_stack, to_stack, frames)
|
||||||
|
self.__storeMove(am)
|
||||||
|
am.do(self)
|
||||||
|
self.hints.list = None
|
||||||
|
|
||||||
# move type 3
|
# move type 3
|
||||||
def turnStackMove(self, from_stack, to_stack, update_flags=1):
|
def turnStackMove(self, from_stack, to_stack, update_flags=1):
|
||||||
assert from_stack and to_stack and (from_stack is not to_stack)
|
assert from_stack and to_stack and (from_stack is not to_stack)
|
||||||
|
@ -2398,11 +2613,14 @@ for %d moves.
|
||||||
assert moves.index == len(moves.history)
|
assert moves.index == len(moves.history)
|
||||||
|
|
||||||
moves.current = []
|
moves.current = []
|
||||||
|
self.updateSnapshots()
|
||||||
# update view
|
# update view
|
||||||
self.updateText()
|
self.updateText()
|
||||||
self.updateStatus(moves=(moves.index, self.stats.total_moves))
|
self.updateStatus(moves=(moves.index, self.stats.total_moves))
|
||||||
self.updateMenus()
|
self.updateMenus()
|
||||||
self.updatePlayTime(do_after=0)
|
self.updatePlayTime(do_after=0)
|
||||||
|
reset_solver_dialog()
|
||||||
|
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@ -2428,6 +2646,7 @@ for %d moves.
|
||||||
self.stats.undo_moves += 1
|
self.stats.undo_moves += 1
|
||||||
self.stats.total_moves += 1
|
self.stats.total_moves += 1
|
||||||
self.hints.list = None
|
self.hints.list = None
|
||||||
|
self.updateSnapshots()
|
||||||
self.updateText()
|
self.updateText()
|
||||||
self.updateStatus(moves=(self.moves.index, self.stats.total_moves))
|
self.updateStatus(moves=(self.moves.index, self.stats.total_moves))
|
||||||
self.updateMenus()
|
self.updateMenus()
|
||||||
|
@ -2451,6 +2670,7 @@ for %d moves.
|
||||||
self.stats.redo_moves += 1
|
self.stats.redo_moves += 1
|
||||||
self.stats.total_moves += 1
|
self.stats.total_moves += 1
|
||||||
self.hints.list = None
|
self.hints.list = None
|
||||||
|
self.updateSnapshots()
|
||||||
self.updateText()
|
self.updateText()
|
||||||
self.updateStatus(moves=(self.moves.index, self.stats.total_moves))
|
self.updateStatus(moves=(self.moves.index, self.stats.total_moves))
|
||||||
self.updateMenus()
|
self.updateMenus()
|
||||||
|
@ -2707,6 +2927,9 @@ in the current implementation.''' % version
|
||||||
moves = pload()
|
moves = pload()
|
||||||
assert isinstance(moves, Struct), err_txt
|
assert isinstance(moves, Struct), err_txt
|
||||||
game.moves.__dict__.update(moves.__dict__)
|
game.moves.__dict__.update(moves.__dict__)
|
||||||
|
snapshots = p.load()
|
||||||
|
assert isinstance(snapshots, list), err_txt
|
||||||
|
game.snapshots = snapshots
|
||||||
if 0 <= bookmark <= 1:
|
if 0 <= bookmark <= 1:
|
||||||
gstats = pload()
|
gstats = pload()
|
||||||
assert isinstance(gstats, Struct), err_txt
|
assert isinstance(gstats, Struct), err_txt
|
||||||
|
@ -2763,6 +2986,7 @@ in the current implementation.''' % version
|
||||||
p.dump(self.saveinfo)
|
p.dump(self.saveinfo)
|
||||||
p.dump(self.gsaveinfo)
|
p.dump(self.gsaveinfo)
|
||||||
p.dump(self.moves)
|
p.dump(self.moves)
|
||||||
|
p.dump(self.snapshots)
|
||||||
if 0 <= bookmark <= 1:
|
if 0 <= bookmark <= 1:
|
||||||
if bookmark == 0:
|
if bookmark == 0:
|
||||||
self.gstats.saved = self.gstats.saved + 1
|
self.gstats.saved = self.gstats.saved + 1
|
||||||
|
|
|
@ -339,6 +339,7 @@ class GI:
|
||||||
('fc-0.9.2', tuple(range(441, 466))),
|
('fc-0.9.2', tuple(range(441, 466))),
|
||||||
('fc-0.9.3', tuple(range(466, 661))),
|
('fc-0.9.3', tuple(range(466, 661))),
|
||||||
('fc-0.9.4', tuple(range(661, 671))),
|
('fc-0.9.4', tuple(range(661, 671))),
|
||||||
|
('fc-1.0', tuple(range(671, 711))),
|
||||||
)
|
)
|
||||||
|
|
||||||
# deprecated - the correct way is to or a GI.GT_XXX flag
|
# deprecated - the correct way is to or a GI.GT_XXX flag
|
||||||
|
@ -346,8 +347,6 @@ class GI:
|
||||||
_CHILDREN_GAMES = [16, 33, 55, 90, 91, 96, 97, 176, 903,]
|
_CHILDREN_GAMES = [16, 33, 55, 90, 91, 96, 97, 176, 903,]
|
||||||
|
|
||||||
_OPEN_GAMES = []
|
_OPEN_GAMES = []
|
||||||
#_OPEN_GAMES = [ 5, 6, 8, 9, 26, 31, 45, 46, 50, 53, 63, 64, 77, 85, 86,
|
|
||||||
# 96, 116, 117, 118, 258, ]
|
|
||||||
|
|
||||||
_POPULAR_GAMES = [
|
_POPULAR_GAMES = [
|
||||||
1, # Gypsy
|
1, # Gypsy
|
||||||
|
@ -471,6 +470,7 @@ class GameManager:
|
||||||
self.__games_by_altname = None
|
self.__games_by_altname = None
|
||||||
self.__all_games = {} # includes hidden games
|
self.__all_games = {} # includes hidden games
|
||||||
self.__all_gamenames = {} # includes hidden games
|
self.__all_gamenames = {} # includes hidden games
|
||||||
|
self.__games_for_solver = []
|
||||||
self.loading_plugin = 0
|
self.loading_plugin = 0
|
||||||
self.registered_game_types = {}
|
self.registered_game_types = {}
|
||||||
|
|
||||||
|
@ -536,7 +536,9 @@ class GameManager:
|
||||||
## if gi.id in k: break
|
## if gi.id in k: break
|
||||||
## else:
|
## else:
|
||||||
## print gi.id
|
## print gi.id
|
||||||
|
if hasattr(gi.gameclass, 'Solver_Class') and \
|
||||||
|
gi.gameclass.Solver_Class is not None:
|
||||||
|
self.__games_for_solver.append(gi.id)
|
||||||
|
|
||||||
#
|
#
|
||||||
# access games database - we do not expose hidden games
|
# access games database - we do not expose hidden games
|
||||||
|
@ -591,6 +593,9 @@ class GameManager:
|
||||||
return gi.id
|
return gi.id
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def getGamesForSolver(self):
|
||||||
|
return self.__games_for_solver
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# //
|
||||||
|
|
|
@ -42,6 +42,8 @@ from pysollib.layout import Layout
|
||||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
from pysollib.pysoltk import MfxCanvasText
|
from pysollib.pysoltk import MfxCanvasText
|
||||||
|
|
||||||
|
from numerica import Numerica_Hint
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Tam O'Shanter
|
# // Tam O'Shanter
|
||||||
|
@ -159,6 +161,8 @@ class Strategy_RowStack(BasicRowStack):
|
||||||
|
|
||||||
|
|
||||||
class Strategy(Game):
|
class Strategy(Game):
|
||||||
|
Hint_Class = Numerica_Hint
|
||||||
|
|
||||||
def createGame(self, rows=8):
|
def createGame(self, rows=8):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
l, s = Layout(self), self.s
|
||||||
|
@ -181,6 +185,7 @@ class Strategy(Game):
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
l.defaultStackGroups()
|
||||||
|
self.sg.dropstacks.append(s.talon)
|
||||||
|
|
||||||
#
|
#
|
||||||
# game overrides
|
# game overrides
|
||||||
|
@ -209,14 +214,16 @@ class StrategyPlus(Strategy):
|
||||||
|
|
||||||
def fillStack(self, stack):
|
def fillStack(self, stack):
|
||||||
if stack is self.s.talon and stack.cards:
|
if stack is self.s.talon and stack.cards:
|
||||||
|
old_state = self.enterState(self.S_FILL)
|
||||||
c = stack.cards[-1]
|
c = stack.cards[-1]
|
||||||
while c.rank == ACE:
|
while c.rank == ACE:
|
||||||
old_state = self.enterState(self.S_FILL)
|
|
||||||
self.moveMove(1, stack, self.s.foundations[c.suit])
|
self.moveMove(1, stack, self.s.foundations[c.suit])
|
||||||
if stack.canFlipCard():
|
if stack.canFlipCard():
|
||||||
stack.flipMove()
|
stack.flipMove()
|
||||||
self.leaveState(old_state)
|
if not stack.cards:
|
||||||
|
break
|
||||||
c = stack.cards[-1]
|
c = stack.cards[-1]
|
||||||
|
self.leaveState(old_state)
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -480,6 +487,8 @@ class Amazons_Foundation(AbstractFoundationStack):
|
||||||
rank = 5
|
rank = 5
|
||||||
if (rank + self.cap.dir) % self.cap.mod != cards[0].rank:
|
if (rank + self.cap.dir) % self.cap.mod != cards[0].rank:
|
||||||
return False
|
return False
|
||||||
|
if cards[0].rank == QUEEN:
|
||||||
|
return True
|
||||||
i = list(self.game.s.foundations).index(self)
|
i = list(self.game.s.foundations).index(self)
|
||||||
j = list(self.game.s.rows).index(from_stack)
|
j = list(self.game.s.rows).index(from_stack)
|
||||||
return i == j
|
return i == j
|
||||||
|
|
|
@ -42,6 +42,8 @@ from pysollib.stack import *
|
||||||
from pysollib.game import Game
|
from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Castles in Spain
|
# // Castles in Spain
|
||||||
|
@ -51,8 +53,9 @@ class CastlesInSpain(Game):
|
||||||
Layout_Method = Layout.bakersDozenLayout
|
Layout_Method = Layout.bakersDozenLayout
|
||||||
Talon_Class = InitialDealTalonStack
|
Talon_Class = InitialDealTalonStack
|
||||||
Foundation_Class = SS_FoundationStack
|
Foundation_Class = SS_FoundationStack
|
||||||
RowStack_Class = AC_RowStack
|
RowStack_Class = SuperMoveAC_RowStack
|
||||||
Hint_Class = CautiousDefaultHint
|
Hint_Class = CautiousDefaultHint
|
||||||
|
Solver_Class = FreeCellSolverWrapper()
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
@ -69,8 +72,7 @@ class CastlesInSpain(Game):
|
||||||
for r in l.s.foundations:
|
for r in l.s.foundations:
|
||||||
s.foundations.append(self.Foundation_Class(r.x, r.y, self, suit=r.suit))
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self, suit=r.suit))
|
||||||
for r in l.s.rows:
|
for r in l.s.rows:
|
||||||
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
s.rows.append(self.RowStack_Class(r.x, r.y, self))
|
||||||
max_move=1, max_accept=1))
|
|
||||||
# default
|
# default
|
||||||
l.defaultAll()
|
l.defaultAll()
|
||||||
|
|
||||||
|
@ -96,7 +98,8 @@ class Martha_RowStack(AC_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class Martha(CastlesInSpain):
|
class Martha(CastlesInSpain):
|
||||||
RowStack_Class = FullStackWrapper(Martha_RowStack)
|
Solver_Class = None
|
||||||
|
RowStack_Class = Martha_RowStack
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
CastlesInSpain.createGame(self, rows=12, playcards=13)
|
CastlesInSpain.createGame(self, rows=12, playcards=13)
|
||||||
|
@ -115,7 +118,9 @@ class Martha(CastlesInSpain):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class BakersDozen(CastlesInSpain):
|
class BakersDozen(CastlesInSpain):
|
||||||
RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(RK_RowStack, max_move=1, max_accept=1,
|
||||||
|
base_rank=NO_RANK)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(preset='bakers_dozen')
|
||||||
|
|
||||||
def _shuffleHook(self, cards):
|
def _shuffleHook(self, cards):
|
||||||
# move Kings to bottom of each stack
|
# move Kings to bottom of each stack
|
||||||
|
@ -148,16 +153,19 @@ class BakersDozen(CastlesInSpain):
|
||||||
|
|
||||||
class SpanishPatience(BakersDozen):
|
class SpanishPatience(BakersDozen):
|
||||||
Foundation_Class = AC_FoundationStack
|
Foundation_Class = AC_FoundationStack
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
|
|
||||||
class PortugueseSolitaire(BakersDozen):
|
class PortugueseSolitaire(BakersDozen):
|
||||||
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank', esf='kings')
|
||||||
def _shuffleHook(self, cards):
|
def _shuffleHook(self, cards):
|
||||||
return cards
|
return cards
|
||||||
|
|
||||||
|
|
||||||
class SpanishPatienceII(PortugueseSolitaire):
|
class SpanishPatienceII(PortugueseSolitaire):
|
||||||
RowStack_Class = RK_RowStack
|
RowStack_Class = RK_RowStack
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank', sm='unlimited')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -165,6 +173,8 @@ class SpanishPatienceII(PortugueseSolitaire):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class GoodMeasure(BakersDozen):
|
class GoodMeasure(BakersDozen):
|
||||||
|
Solver_Class = FreeCellSolverWrapper(preset='good_measure')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
CastlesInSpain.createGame(self, rows=10)
|
CastlesInSpain.createGame(self, rows=10)
|
||||||
|
|
||||||
|
@ -189,8 +199,8 @@ class GoodMeasure(BakersDozen):
|
||||||
class Cruel_Talon(TalonStack):
|
class Cruel_Talon(TalonStack):
|
||||||
def canDealCards(self):
|
def canDealCards(self):
|
||||||
## FIXME: this is to avoid loops in the demo
|
## FIXME: this is to avoid loops in the demo
|
||||||
if self.game.demo and self.game.moves.index >= 100:
|
#if self.game.demo and self.game.moves.index >= 100:
|
||||||
return False
|
# return False
|
||||||
if self.round == self.max_rounds:
|
if self.round == self.max_rounds:
|
||||||
return False
|
return False
|
||||||
return not self.game.isGameWon()
|
return not self.game.isGameWon()
|
||||||
|
@ -238,6 +248,8 @@ class Cruel_Talon(TalonStack):
|
||||||
class Cruel(CastlesInSpain):
|
class Cruel(CastlesInSpain):
|
||||||
Talon_Class = StackWrapper(Cruel_Talon, max_rounds=-1)
|
Talon_Class = StackWrapper(Cruel_Talon, max_rounds=-1)
|
||||||
RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK)
|
||||||
|
##Solver_Class = FreeCellSolverWrapper(preset='cruel')
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
CastlesInSpain.createGame(self, rows=12)
|
CastlesInSpain.createGame(self, rows=12)
|
||||||
|
@ -289,6 +301,7 @@ class Indefatigable(Cruel):
|
||||||
class Perseverance(Cruel, BakersDozen):
|
class Perseverance(Cruel, BakersDozen):
|
||||||
Talon_Class = StackWrapper(Cruel_Talon, max_rounds=3)
|
Talon_Class = StackWrapper(Cruel_Talon, max_rounds=3)
|
||||||
RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK, dir=-1, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS)
|
RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK, dir=-1, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS)
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
def _shuffleHook(self, cards):
|
def _shuffleHook(self, cards):
|
||||||
# move Kings to bottom of each stack (???)
|
# move Kings to bottom of each stack (???)
|
||||||
|
@ -306,6 +319,7 @@ class Perseverance(Cruel, BakersDozen):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class RippleFan(CastlesInSpain):
|
class RippleFan(CastlesInSpain):
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
|
|
|
@ -49,36 +49,12 @@ from pysollib.hint import FreeCellType_Hint, FreeCellSolverWrapper
|
||||||
# // Baker's Game
|
# // Baker's Game
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
# To simplify playing we also consider the number of free rows.
|
|
||||||
# Note that this only is legal if the game.s.rows have a
|
|
||||||
# cap.base_rank == ANY_RANK.
|
|
||||||
# See also the "SuperMove" section in the FreeCell FAQ.
|
|
||||||
class BakersGame_RowStack(SS_RowStack):
|
|
||||||
def _getMaxMove(self, to_stack_ncards):
|
|
||||||
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
|
|
||||||
n = getNumberOfFreeStacks(self.game.s.rows)
|
|
||||||
if to_stack_ncards == 0:
|
|
||||||
n = n - 1
|
|
||||||
while n > 0 and max_move < 1000:
|
|
||||||
max_move = max_move * 2
|
|
||||||
n = n - 1
|
|
||||||
return max_move
|
|
||||||
|
|
||||||
def canMoveCards(self, cards):
|
|
||||||
max_move = self._getMaxMove(1)
|
|
||||||
return len(cards) <= max_move and SS_RowStack.canMoveCards(self, cards)
|
|
||||||
|
|
||||||
def acceptsCards(self, from_stack, cards):
|
|
||||||
max_move = self._getMaxMove(len(self.cards))
|
|
||||||
return len(cards) <= max_move and SS_RowStack.acceptsCards(self, from_stack, cards)
|
|
||||||
|
|
||||||
|
|
||||||
class BakersGame(Game):
|
class BakersGame(Game):
|
||||||
Layout_Method = Layout.freeCellLayout
|
Layout_Method = Layout.freeCellLayout
|
||||||
Foundation_Class = SS_FoundationStack
|
Foundation_Class = SS_FoundationStack
|
||||||
RowStack_Class = BakersGame_RowStack
|
RowStack_Class = SuperMoveSS_RowStack
|
||||||
##Hint_Class = FreeCellType_Hint
|
Hint_Class = FreeCellType_Hint
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'sbb' : "suit" })
|
Solver_Class = FreeCellSolverWrapper(sbb='suit')
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
@ -123,7 +99,7 @@ class BakersGame(Game):
|
||||||
|
|
||||||
class KingOnlyBakersGame(BakersGame):
|
class KingOnlyBakersGame(BakersGame):
|
||||||
RowStack_Class = StackWrapper(FreeCell_SS_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(FreeCell_SS_RowStack, base_rank=KING)
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'sbb' : "suit", 'esf' : "kings" })
|
Solver_Class = FreeCellSolverWrapper(sbb='suit', esf='kings')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -235,19 +211,22 @@ class SeahavenTowers(KingOnlyBakersGame):
|
||||||
|
|
||||||
class RelaxedSeahavenTowers(SeahavenTowers):
|
class RelaxedSeahavenTowers(SeahavenTowers):
|
||||||
RowStack_Class = KingSS_RowStack
|
RowStack_Class = KingSS_RowStack
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'sbb' : "suit", 'esf' : "kings", 'sm' : "unlimited",})
|
Solver_Class = FreeCellSolverWrapper(sbb='suit', esf='kings', sm='unlimited')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
# // Tuxedo
|
||||||
# // Penguin
|
# // Penguin
|
||||||
# // Opus
|
# // Opus
|
||||||
# // Tuxedo
|
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Tuxedo(Game):
|
class Tuxedo(Game):
|
||||||
|
|
||||||
RowStack_Class = SS_RowStack
|
RowStack_Class = StackWrapper(SS_RowStack, mod=13)
|
||||||
|
ReserveStack_Class = ReserveStack
|
||||||
|
Foundation_Class = StackWrapper(SS_FoundationStack, mod=13, max_move=0)
|
||||||
Hint_Class = FreeCellType_Hint
|
Hint_Class = FreeCellType_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='suit', sm='unlimited')
|
||||||
|
|
||||||
def createGame(self, rows=7, reserves=7):
|
def createGame(self, rows=7, reserves=7):
|
||||||
# create layout
|
# create layout
|
||||||
|
@ -265,16 +244,16 @@ class Tuxedo(Game):
|
||||||
# create stacks
|
# create stacks
|
||||||
x, y = self.width - l.XS, l.YM
|
x, y = self.width - l.XS, l.YM
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
s.foundations.append(SS_FoundationStack(x, y, self, i, mod=13, max_move=0))
|
s.foundations.append(self.Foundation_Class(x, y, self, suit=i))
|
||||||
y = y + l.YS
|
y = y + l.YS
|
||||||
self.setRegion(s.foundations, (x - l.CW/2, -999, 999999, 999999))
|
self.setRegion(s.foundations, (x - l.CW/2, -999, 999999, 999999))
|
||||||
x, y = l.XM + (maxrows-rows)*l.XS/2, l.YM
|
x, y = l.XM + (maxrows-rows)*l.XS/2, l.YM
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
s.rows.append(self.RowStack_Class(x, y, self, mod=13))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
x = x + l.XS
|
x = x + l.XS
|
||||||
x, y = l.XM + (maxrows-reserves)*l.XS/2, self.height - l.YS
|
x, y = l.XM + (maxrows-reserves)*l.XS/2, self.height - l.YS
|
||||||
for i in range(reserves):
|
for i in range(reserves):
|
||||||
s.reserves.append(ReserveStack(x, y, self))
|
s.reserves.append(self.ReserveStack_Class(x, y, self))
|
||||||
x = x + l.XS
|
x = x + l.XS
|
||||||
self.setRegion(s.reserves, (-999, y - l.CH / 2, 999999, 999999))
|
self.setRegion(s.reserves, (-999, y - l.CH / 2, 999999, 999999))
|
||||||
s.talon = InitialDealTalonStack(l.XM+1, y, self)
|
s.talon = InitialDealTalonStack(l.XM+1, y, self)
|
||||||
|
@ -294,6 +273,7 @@ class Tuxedo(Game):
|
||||||
|
|
||||||
class Penguin(Tuxedo):
|
class Penguin(Tuxedo):
|
||||||
GAME_VERSION = 2
|
GAME_VERSION = 2
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='suit', esf='kings', sm='unlimited')
|
||||||
|
|
||||||
def _shuffleHook(self, cards):
|
def _shuffleHook(self, cards):
|
||||||
# move base cards to top of the Talon (i.e. first cards to be dealt)
|
# move base cards to top of the Talon (i.e. first cards to be dealt)
|
||||||
|
|
|
@ -42,6 +42,7 @@ from pysollib.stack import *
|
||||||
from pysollib.game import Game
|
from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import CautiousDefaultHint, FreeCellType_Hint
|
from pysollib.hint import CautiousDefaultHint, FreeCellType_Hint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
from pysollib.pysoltk import MfxCanvasText
|
from pysollib.pysoltk import MfxCanvasText
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,9 +61,11 @@ class BeleagueredCastleType_Hint(CautiousDefaultHint):
|
||||||
|
|
||||||
class StreetsAndAlleys(Game):
|
class StreetsAndAlleys(Game):
|
||||||
Hint_Class = BeleagueredCastleType_Hint
|
Hint_Class = BeleagueredCastleType_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper(preset='streets_and_alleys')
|
||||||
|
|
||||||
Foundation_Class = SS_FoundationStack
|
Foundation_Class = SS_FoundationStack
|
||||||
RowStack_Class = RK_RowStack
|
##RowStack_Class = RK_RowStack
|
||||||
|
RowStack_Class = SuperMoveRK_RowStack
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
@ -102,7 +105,7 @@ class StreetsAndAlleys(Game):
|
||||||
for x in (x0, x2):
|
for x in (x0, x2):
|
||||||
y = l.YM+l.YS*int(reserves!=0)
|
y = l.YM+l.YS*int(reserves!=0)
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
stack = self.RowStack_Class(x, y, self, max_move=1, max_accept=1)
|
stack = self.RowStack_Class(x, y, self)
|
||||||
stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0
|
stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0
|
||||||
s.rows.append(stack)
|
s.rows.append(stack)
|
||||||
y = y + l.YS
|
y = y + l.YS
|
||||||
|
@ -178,6 +181,8 @@ class Citadel(StreetsAndAlleys):
|
||||||
|
|
||||||
|
|
||||||
class ExiledKings(Citadel):
|
class ExiledKings(Citadel):
|
||||||
|
Hint_Class = BeleagueredCastleType_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank', esf='kings')
|
||||||
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,11 +437,13 @@ class Chessboard(Fortress):
|
||||||
|
|
||||||
class Stronghold(StreetsAndAlleys):
|
class Stronghold(StreetsAndAlleys):
|
||||||
Hint_Class = FreeCellType_Hint
|
Hint_Class = FreeCellType_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank')
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
StreetsAndAlleys.createGame(self, reserves=1)
|
StreetsAndAlleys.createGame(self, reserves=1)
|
||||||
|
|
||||||
class Fastness(StreetsAndAlleys):
|
class Fastness(StreetsAndAlleys):
|
||||||
Hint_Class = FreeCellType_Hint
|
Hint_Class = FreeCellType_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank')
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
StreetsAndAlleys.createGame(self, reserves=2)
|
StreetsAndAlleys.createGame(self, reserves=2)
|
||||||
|
|
||||||
|
@ -727,6 +734,8 @@ class Rittenhouse(Game):
|
||||||
class Lightweight(StreetsAndAlleys):
|
class Lightweight(StreetsAndAlleys):
|
||||||
DEAL = (7, 1)
|
DEAL = (7, 1)
|
||||||
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank', esf='kings',
|
||||||
|
sm='unlimited')
|
||||||
|
|
||||||
def createGame(self, rows=12, playcards=20):
|
def createGame(self, rows=12, playcards=20):
|
||||||
l, s = Layout(self), self.s
|
l, s = Layout(self), self.s
|
||||||
|
@ -765,6 +774,7 @@ class Lightweight(StreetsAndAlleys):
|
||||||
class CastleMount(Lightweight):
|
class CastleMount(Lightweight):
|
||||||
DEAL = (11, 1)
|
DEAL = (11, 1)
|
||||||
RowStack_Class = Spider_SS_RowStack
|
RowStack_Class = Spider_SS_RowStack
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
shallHighlightMatch = Game._shallHighlightMatch_RK
|
shallHighlightMatch = Game._shallHighlightMatch_RK
|
||||||
getQuickPlayScore = Game._getSpiderQuickPlayScore
|
getQuickPlayScore = Game._getSpiderQuickPlayScore
|
||||||
|
@ -786,6 +796,7 @@ class SelectiveCastle_RowStack(RK_RowStack):
|
||||||
class SelectiveCastle(StreetsAndAlleys, Chessboard):
|
class SelectiveCastle(StreetsAndAlleys, Chessboard):
|
||||||
Foundation_Class = Chessboard_Foundation
|
Foundation_Class = Chessboard_Foundation
|
||||||
RowStack_Class = StackWrapper(SelectiveCastle_RowStack, mod=13)
|
RowStack_Class = StackWrapper(SelectiveCastle_RowStack, mod=13)
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
StreetsAndAlleys.createGame(self, texts=True)
|
StreetsAndAlleys.createGame(self, texts=True)
|
||||||
|
@ -854,7 +865,7 @@ class Soother(Game):
|
||||||
|
|
||||||
class PenelopesWeb(StreetsAndAlleys):
|
class PenelopesWeb(StreetsAndAlleys):
|
||||||
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank', esf='kings')
|
||||||
|
|
||||||
|
|
||||||
# register the game
|
# register the game
|
||||||
|
|
|
@ -204,7 +204,7 @@ class Realm(Game):
|
||||||
l, s = Layout(self), self.s
|
l, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
w, h = l.XM+8*l.XS, l.YM+2*l.YS+15*l.YOFFSET
|
w, h = 3*l.XM+8*l.XS, l.YM+2*l.YS+15*l.YOFFSET
|
||||||
self.setSize(w, h)
|
self.setSize(w, h)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
|
|
|
@ -368,7 +368,7 @@ class SeniorWrangler_Talon(DealRowTalonStack):
|
||||||
r = self.game.s.rows[self.round-1]
|
r = self.game.s.rows[self.round-1]
|
||||||
if not r.cards:
|
if not r.cards:
|
||||||
self.game.nextRoundMove(self)
|
self.game.nextRoundMove(self)
|
||||||
return
|
return 1
|
||||||
if sound:
|
if sound:
|
||||||
self.game.startDealSample()
|
self.game.startDealSample()
|
||||||
old_state = self.game.enterState(self.game.S_DEAL)
|
old_state = self.game.enterState(self.game.S_DEAL)
|
||||||
|
|
|
@ -379,7 +379,8 @@ class PrincessPatience_RowStack(SS_RowStack):
|
||||||
def canMoveCards(self, cards):
|
def canMoveCards(self, cards):
|
||||||
if not SS_RowStack.canMoveCards(self, cards):
|
if not SS_RowStack.canMoveCards(self, cards):
|
||||||
return False
|
return False
|
||||||
index = list(self.game.s.rows).index(self)
|
##index = list(self.game.s.rows).index(self) # don't work in demo-mode with cloned stack
|
||||||
|
index = self.id
|
||||||
col = index % 4
|
col = index % 4
|
||||||
row = index / 4
|
row = index / 4
|
||||||
if index < 16: # left
|
if index < 16: # left
|
||||||
|
@ -403,6 +404,7 @@ class PrincessPatience_RowStack(SS_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class PrincessPatience(Game):
|
class PrincessPatience(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
RowStack_Class = PrincessPatience_RowStack
|
RowStack_Class = PrincessPatience_RowStack
|
||||||
|
|
||||||
def createGame(self, max_rounds=1):
|
def createGame(self, max_rounds=1):
|
||||||
|
|
|
@ -40,7 +40,7 @@ from gypsy import DieRussische_Foundation
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Capricieuse(Game):
|
class Capricieuse(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
Talon_Class = StackWrapper(RedealTalonStack, max_rounds=3)
|
Talon_Class = StackWrapper(RedealTalonStack, max_rounds=3)
|
||||||
RowStack_Class = UD_SS_RowStack
|
RowStack_Class = UD_SS_RowStack
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ class Nationale(Capricieuse):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Strata(Game):
|
class Strata(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
|
||||||
|
|
|
@ -286,6 +286,7 @@ class Harvestman(Arachnida):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class GermanPatience(Game):
|
class GermanPatience(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
def createGame(self, rows=8):
|
def createGame(self, rows=8):
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ from pysollib.stack import *
|
||||||
from pysollib.game import Game
|
from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
from pysollib.pysoltk import MfxCanvasText
|
from pysollib.pysoltk import MfxCanvasText
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,6 +134,10 @@ class Fan(Game):
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
|
class FanGame(Fan):
|
||||||
|
Solver_Class = FreeCellSolverWrapper(preset='fan')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Scotch Patience
|
# // Scotch Patience
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
@ -461,6 +466,8 @@ class CloverLeaf_RowStack(UD_SS_RowStack):
|
||||||
if not self.cards:
|
if not self.cards:
|
||||||
return cards[0].rank in (ACE, KING)
|
return cards[0].rank in (ACE, KING)
|
||||||
return True
|
return True
|
||||||
|
def _getBaseCard(self):
|
||||||
|
return _('Base card - Ace or King.')
|
||||||
|
|
||||||
|
|
||||||
class CloverLeaf(Game):
|
class CloverLeaf(Game):
|
||||||
|
@ -531,6 +538,8 @@ class CloverLeaf(Game):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class FreeFan(Fan):
|
class FreeFan(Fan):
|
||||||
|
RowStack_Class = FullStackWrapper(SuperMoveSS_RowStack, base_rank=KING)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(esf='kings', sbb='suit')
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
Fan.createGame(self, reserves=2, playcards=8)
|
Fan.createGame(self, reserves=2, playcards=8)
|
||||||
|
|
||||||
|
@ -542,6 +551,7 @@ class FreeFan(Fan):
|
||||||
class BoxFan(Fan):
|
class BoxFan(Fan):
|
||||||
|
|
||||||
RowStack_Class = KingAC_RowStack
|
RowStack_Class = KingAC_RowStack
|
||||||
|
Solver_Class = FreeCellSolverWrapper(esf='kings')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
Fan.createGame(self, rows=(4,4,4,4))
|
Fan.createGame(self, rows=(4,4,4,4))
|
||||||
|
@ -632,7 +642,7 @@ class FascinationFan(Fan):
|
||||||
def redealCards(self):
|
def redealCards(self):
|
||||||
r0 = r1 = len(self.s.talon.cards)/3
|
r0 = r1 = len(self.s.talon.cards)/3
|
||||||
m = len(self.s.talon.cards)%3
|
m = len(self.s.talon.cards)%3
|
||||||
if m >= 1: r2 += 1
|
if m >= 1: r1 += 1
|
||||||
self.s.talon.dealRow(rows=self.s.rows[:r0], flip=0, frames=4)
|
self.s.talon.dealRow(rows=self.s.rows[:r0], flip=0, frames=4)
|
||||||
self.s.talon.dealRow(rows=self.s.rows[:r1], flip=0, frames=4)
|
self.s.talon.dealRow(rows=self.s.rows[:r1], flip=0, frames=4)
|
||||||
self.s.talon.dealRowAvail(frames=4)
|
self.s.talon.dealRowAvail(frames=4)
|
||||||
|
@ -726,7 +736,7 @@ class Crescent(Game):
|
||||||
|
|
||||||
|
|
||||||
# register the game
|
# register the game
|
||||||
registerGame(GameInfo(56, Fan, "Fan",
|
registerGame(GameInfo(56, FanGame, "Fan",
|
||||||
GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
|
GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
|
||||||
registerGame(GameInfo(87, ScotchPatience, "Scotch Patience",
|
registerGame(GameInfo(87, ScotchPatience, "Scotch Patience",
|
||||||
GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
|
GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
|
||||||
|
|
|
@ -542,6 +542,7 @@ class Octave_Talon(WasteTalonStack):
|
||||||
|
|
||||||
|
|
||||||
class Octave(Game):
|
class Octave(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
|
|
@ -51,37 +51,14 @@ from spider import Spider_AC_Foundation
|
||||||
# // FreeCell
|
# // FreeCell
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
# To simplify playing we also consider the number of free rows.
|
|
||||||
# Note that this only is legal if the game.s.rows have a
|
|
||||||
# cap.base_rank == ANY_RANK.
|
|
||||||
# See also the "SuperMove" section in the FreeCell FAQ.
|
|
||||||
class FreeCell_RowStack(AC_RowStack):
|
|
||||||
def _getMaxMove(self, to_stack_ncards):
|
|
||||||
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
|
|
||||||
n = getNumberOfFreeStacks(self.game.s.rows)
|
|
||||||
if to_stack_ncards == 0:
|
|
||||||
n = n - 1
|
|
||||||
while n > 0 and max_move < 1000:
|
|
||||||
max_move = max_move * 2
|
|
||||||
n = n - 1
|
|
||||||
return max_move
|
|
||||||
|
|
||||||
def canMoveCards(self, cards):
|
|
||||||
max_move = self._getMaxMove(1)
|
|
||||||
return len(cards) <= max_move and AC_RowStack.canMoveCards(self, cards)
|
|
||||||
|
|
||||||
def acceptsCards(self, from_stack, cards):
|
|
||||||
max_move = self._getMaxMove(len(self.cards))
|
|
||||||
return len(cards) <= max_move and AC_RowStack.acceptsCards(self, from_stack, cards)
|
|
||||||
|
|
||||||
|
|
||||||
class FreeCell(Game):
|
class FreeCell(Game):
|
||||||
Layout_Method = Layout.freeCellLayout
|
Layout_Method = Layout.freeCellLayout
|
||||||
Talon_Class = InitialDealTalonStack
|
Talon_Class = InitialDealTalonStack
|
||||||
Foundation_Class = SS_FoundationStack
|
Foundation_Class = SS_FoundationStack
|
||||||
RowStack_Class = FreeCell_RowStack
|
RowStack_Class = SuperMoveAC_RowStack
|
||||||
ReserveStack_Class = ReserveStack
|
ReserveStack_Class = ReserveStack
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {})
|
Hint_Class = FreeCellType_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -127,7 +104,7 @@ class FreeCell(Game):
|
||||||
|
|
||||||
class RelaxedFreeCell(FreeCell):
|
class RelaxedFreeCell(FreeCell):
|
||||||
RowStack_Class = AC_RowStack
|
RowStack_Class = AC_RowStack
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'sm' : "unlimited"})
|
Solver_Class = FreeCellSolverWrapper(sm='unlimited')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -136,7 +113,7 @@ class RelaxedFreeCell(FreeCell):
|
||||||
|
|
||||||
class ForeCell(FreeCell):
|
class ForeCell(FreeCell):
|
||||||
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=KING)
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'esf' : "kings"})
|
Solver_Class = FreeCellSolverWrapper(esf='kings')
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
|
@ -159,7 +136,7 @@ class ChallengeFreeCell(FreeCell):
|
||||||
|
|
||||||
class SuperChallengeFreeCell(ChallengeFreeCell):
|
class SuperChallengeFreeCell(ChallengeFreeCell):
|
||||||
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=KING)
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'esf' : "kings"})
|
Solver_Class = FreeCellSolverWrapper(esf='kings')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -169,7 +146,7 @@ class SuperChallengeFreeCell(ChallengeFreeCell):
|
||||||
class Stalactites(FreeCell):
|
class Stalactites(FreeCell):
|
||||||
Foundation_Class = StackWrapper(RK_FoundationStack, suit=ANY_SUIT, mod=13, min_cards=1)
|
Foundation_Class = StackWrapper(RK_FoundationStack, suit=ANY_SUIT, mod=13, min_cards=1)
|
||||||
RowStack_Class = StackWrapper(BasicRowStack, max_move=1, max_accept=0)
|
RowStack_Class = StackWrapper(BasicRowStack, max_move=1, max_accept=0)
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
FreeCell.createGame(self, reserves=2)
|
FreeCell.createGame(self, reserves=2)
|
||||||
|
@ -192,7 +169,7 @@ class Stalactites(FreeCell):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class DoubleFreecell(FreeCell):
|
class DoubleFreecell(FreeCell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
@ -246,7 +223,7 @@ class DoubleFreecell(FreeCell):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class TripleFreecell(FreeCell):
|
class TripleFreecell(FreeCell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
@ -267,8 +244,8 @@ class TripleFreecell(FreeCell):
|
||||||
s.talon = self.Talon_Class(l.XM, h-l.YS, self)
|
s.talon = self.Talon_Class(l.XM, h-l.YS, self)
|
||||||
|
|
||||||
x, y = l.XM+(max_rows-decks*4)*l.XS/2, l.YM
|
x, y = l.XM+(max_rows-decks*4)*l.XS/2, l.YM
|
||||||
for i in range(decks):
|
|
||||||
for j in range(4):
|
for j in range(4):
|
||||||
|
for i in range(decks):
|
||||||
s.foundations.append(self.Foundation_Class(x, y, self, suit=j))
|
s.foundations.append(self.Foundation_Class(x, y, self, suit=j))
|
||||||
x += l.XS
|
x += l.XS
|
||||||
x, y = l.XM+(max_rows-reserves)*l.XS/2, l.YM+l.YS
|
x, y = l.XM+(max_rows-reserves)*l.XS/2, l.YM+l.YS
|
||||||
|
@ -323,16 +300,24 @@ class BigCell(TripleFreecell):
|
||||||
# // Spidercells
|
# // Spidercells
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Spidercells_RowStack(FreeCell_RowStack):
|
class Spidercells_RowStack(SuperMoveAC_RowStack):
|
||||||
def canMoveCards(self, cards):
|
def canMoveCards(self, cards):
|
||||||
if len(cards) == 13 and isAlternateColorSequence(cards):
|
if len(cards) == 13 and isAlternateColorSequence(cards):
|
||||||
return True
|
return True
|
||||||
return FreeCell_RowStack.canMoveCards(self, cards)
|
return SuperMoveAC_RowStack.canMoveCards(self, cards)
|
||||||
|
def canDropCards(self, stacks):
|
||||||
|
if len(self.cards) < 13:
|
||||||
|
return (None, 0)
|
||||||
|
cards = self.cards[-13:]
|
||||||
|
for s in stacks:
|
||||||
|
if s is not self and s.acceptsCards(self, cards):
|
||||||
|
return (s, 13)
|
||||||
|
return (None, 0)
|
||||||
|
|
||||||
|
|
||||||
class Spidercells(FreeCell):
|
class Spidercells(FreeCell):
|
||||||
|
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
Foundation_Class = Spider_AC_Foundation
|
Foundation_Class = Spider_AC_Foundation
|
||||||
RowStack_Class = Spidercells_RowStack
|
RowStack_Class = Spidercells_RowStack
|
||||||
|
|
||||||
|
@ -361,8 +346,6 @@ class Spidercells(FreeCell):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class SevenByFour(FreeCell):
|
class SevenByFour(FreeCell):
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {})
|
|
||||||
#Hint_Class = FreeCellType_Hint
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
FreeCell.createGame(self, rows=7)
|
FreeCell.createGame(self, rows=7)
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
|
@ -377,9 +360,8 @@ class SevenByFive(SevenByFour):
|
||||||
FreeCell.createGame(self, rows=7, reserves=5)
|
FreeCell.createGame(self, rows=7, reserves=5)
|
||||||
|
|
||||||
class Bath(FreeCell):
|
class Bath(FreeCell):
|
||||||
Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, {'esf' : 'kings'})
|
Solver_Class = FreeCellSolverWrapper(esf='kings')
|
||||||
#Hint_Class = FreeCellType_Hint
|
RowStack_Class = StackWrapper(SuperMoveAC_RowStack, base_rank=KING)
|
||||||
RowStack_Class = StackWrapper(FreeCell_RowStack, base_rank=KING)
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
FreeCell.createGame(self, rows=10, reserves=2)
|
FreeCell.createGame(self, rows=10, reserves=2)
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
|
@ -395,7 +377,7 @@ class Bath(FreeCell):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Clink(FreeCell):
|
class Clink(FreeCell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
|
@ -440,7 +422,7 @@ class Clink(FreeCell):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Repair(FreeCell):
|
class Repair(FreeCell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = FreeCellSolverWrapper(sm='unlimited')
|
||||||
RowStack_Class = AC_RowStack
|
RowStack_Class = AC_RowStack
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
@ -464,7 +446,7 @@ class FourColours_RowStack(AC_RowStack):
|
||||||
return self.game.app.images.getReserveBottom()
|
return self.game.app.images.getReserveBottom()
|
||||||
|
|
||||||
class FourColours(FreeCell):
|
class FourColours(FreeCell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
RowStack_Class = AC_RowStack
|
RowStack_Class = AC_RowStack
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
@ -507,7 +489,7 @@ class GermanFreeCell_Reserve(ReserveStack):
|
||||||
|
|
||||||
|
|
||||||
class GermanFreeCell(SevenByFour):
|
class GermanFreeCell(SevenByFour):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = None
|
||||||
RowStack_Class = AC_RowStack
|
RowStack_Class = AC_RowStack
|
||||||
ReserveStack_Class = GermanFreeCell_Reserve
|
ReserveStack_Class = GermanFreeCell_Reserve
|
||||||
|
|
||||||
|
@ -524,7 +506,7 @@ class GermanFreeCell(SevenByFour):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class OceanTowers(TripleFreecell):
|
class OceanTowers(TripleFreecell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = FreeCellSolverWrapper(esf='kings', sbb='suit')
|
||||||
RowStack_Class = StackWrapper(FreeCell_SS_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(FreeCell_SS_RowStack, base_rank=KING)
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
@ -550,7 +532,7 @@ class KingCell_RowStack(RK_RowStack):
|
||||||
return len(cards) <= max_move and RK_RowStack.canMoveCards(self, cards)
|
return len(cards) <= max_move and RK_RowStack.canMoveCards(self, cards)
|
||||||
|
|
||||||
class KingCell(FreeCell):
|
class KingCell(FreeCell):
|
||||||
Hint_Class = FreeCellType_Hint
|
Solver_Class = FreeCellSolverWrapper(esf='kings')
|
||||||
RowStack_Class = StackWrapper(KingCell_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(KingCell_RowStack, base_rank=KING)
|
||||||
|
|
||||||
shallHighlightMatch = Game._shallHighlightMatch_RK
|
shallHighlightMatch = Game._shallHighlightMatch_RK
|
||||||
|
@ -612,6 +594,7 @@ class Headquarters(Game):
|
||||||
|
|
||||||
class CanCan(FreeCell):
|
class CanCan(FreeCell):
|
||||||
Hint_Class = DefaultHint
|
Hint_Class = DefaultHint
|
||||||
|
Solver_Class = None
|
||||||
RowStack_Class = KingAC_RowStack
|
RowStack_Class = KingAC_RowStack
|
||||||
ReserveStack_Class = StackWrapper(OpenStack, max_accept=0)
|
ReserveStack_Class = StackWrapper(OpenStack, max_accept=0)
|
||||||
|
|
||||||
|
|
|
@ -291,6 +291,8 @@ class BlackHole_Foundation(AbstractFoundationStack):
|
||||||
r1, r2 = self.cards[-1].rank, cards[0].rank
|
r1, r2 = self.cards[-1].rank, cards[0].rank
|
||||||
return (r1 + 1) % self.cap.mod == r2 or (r2 + 1) % self.cap.mod == r1
|
return (r1 + 1) % self.cap.mod == r2 or (r2 + 1) % self.cap.mod == r1
|
||||||
return 1
|
return 1
|
||||||
|
def getHelp(self):
|
||||||
|
return _('Foundation. Build up or down regardless of suit.')
|
||||||
|
|
||||||
|
|
||||||
class BlackHole_RowStack(ReserveStack):
|
class BlackHole_RowStack(ReserveStack):
|
||||||
|
|
|
@ -462,9 +462,9 @@ class BigBen(Game):
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRow(rows=self.s.foundations)
|
self.s.talon.dealRow(rows=self.s.foundations, frames=4)
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
self.s.talon.dealRow()
|
self.s.talon.dealRow(frames=4)
|
||||||
|
|
||||||
def _autoDeal(self, sound=1):
|
def _autoDeal(self, sound=1):
|
||||||
# don't deal a card to the waste if the waste is empty
|
# don't deal a card to the waste if the waste is empty
|
||||||
|
|
|
@ -263,6 +263,7 @@ class BigDeal(DoubleKlondike):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Delivery(BigDeal):
|
class Delivery(BigDeal):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
RowStack_Class = StackWrapper(SS_RowStack, max_move=1)
|
RowStack_Class = StackWrapper(SS_RowStack, max_move=1)
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
|
|
@ -45,6 +45,7 @@ class HeadsAndTails_Reserve(OpenStack):
|
||||||
|
|
||||||
|
|
||||||
class HeadsAndTails(Game):
|
class HeadsAndTails(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
|
|
@ -41,6 +41,7 @@ from pysollib.stack import *
|
||||||
from pysollib.game import Game
|
from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import DefaultHint, FreeCellType_Hint, CautiousDefaultHint
|
from pysollib.hint import DefaultHint, FreeCellType_Hint, CautiousDefaultHint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
from pysollib.pysoltk import MfxCanvasText
|
from pysollib.pysoltk import MfxCanvasText
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ class DerKatzenschwanz_Hint(FreeCellType_Hint):
|
||||||
class DerKatzenschwanz(Game):
|
class DerKatzenschwanz(Game):
|
||||||
RowStack_Class = StackWrapper(AC_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(AC_RowStack, base_rank=NO_RANK)
|
||||||
Hint_Class = DerKatzenschwanz_Hint
|
Hint_Class = DerKatzenschwanz_Hint
|
||||||
|
Solver_Class = FreeCellSolverWrapper(esf='none', sm='unlimited')
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
@ -145,6 +147,7 @@ class DerKatzenschwanz(Game):
|
||||||
class DieSchlange(DerKatzenschwanz):
|
class DieSchlange(DerKatzenschwanz):
|
||||||
|
|
||||||
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=NO_RANK)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(esf='none')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
DerKatzenschwanz.createGame(self, rows=9, reserves=7)
|
DerKatzenschwanz.createGame(self, rows=9, reserves=7)
|
||||||
|
@ -171,8 +174,8 @@ class DieSchlange(DerKatzenschwanz):
|
||||||
|
|
||||||
class Kings(DerKatzenschwanz):
|
class Kings(DerKatzenschwanz):
|
||||||
|
|
||||||
##RowStack_Class = StackWrapper(AC_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(AC_RowStack, base_rank=NO_RANK)
|
||||||
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=NO_RANK)
|
Solver_Class = FreeCellSolverWrapper(esf='none', sm='unlimited')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
return DerKatzenschwanz.createGame(self, rows=8, reserves=8)
|
return DerKatzenschwanz.createGame(self, rows=8, reserves=8)
|
||||||
|
@ -192,8 +195,8 @@ class Kings(DerKatzenschwanz):
|
||||||
|
|
||||||
class Retinue(DieSchlange, Kings):
|
class Retinue(DieSchlange, Kings):
|
||||||
|
|
||||||
##RowStack_Class = StackWrapper(AC_RowStack, base_rank=NO_RANK)
|
|
||||||
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=NO_RANK)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(esf='none')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
return DerKatzenschwanz.createGame(self, rows=8, reserves=8)
|
return DerKatzenschwanz.createGame(self, rows=8, reserves=8)
|
||||||
|
@ -249,6 +252,7 @@ class SalicLaw_Talon(OpenTalonStack):
|
||||||
class SalicLaw(DerKatzenschwanz):
|
class SalicLaw(DerKatzenschwanz):
|
||||||
|
|
||||||
Hint_Class = SalicLaw_Hint
|
Hint_Class = SalicLaw_Hint
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
Foundation_Classes = [
|
Foundation_Classes = [
|
||||||
StackWrapper(AbstractFoundationStack, max_cards=1, base_rank=QUEEN),
|
StackWrapper(AbstractFoundationStack, max_cards=1, base_rank=QUEEN),
|
||||||
|
@ -340,6 +344,7 @@ class SalicLaw(DerKatzenschwanz):
|
||||||
|
|
||||||
class Deep(DerKatzenschwanz):
|
class Deep(DerKatzenschwanz):
|
||||||
RowStack_Class = StackWrapper(AC_RowStack, base_rank=ANY_RANK)
|
RowStack_Class = StackWrapper(AC_RowStack, base_rank=ANY_RANK)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sm='unlimited')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
return DerKatzenschwanz.createGame(self, rows=8, reserves=8)
|
return DerKatzenschwanz.createGame(self, rows=8, reserves=8)
|
||||||
|
@ -499,6 +504,7 @@ class StepUp_RowStack(AC_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class StepUp(Game):
|
class StepUp(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
l, s = Layout(self), self.s
|
l, s = Layout(self), self.s
|
||||||
|
|
|
@ -43,6 +43,7 @@ from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
from pysollib.hint import KlondikeType_Hint
|
from pysollib.hint import KlondikeType_Hint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
from pysollib.pysoltk import MfxCanvasText
|
from pysollib.pysoltk import MfxCanvasText
|
||||||
|
|
||||||
from canfield import CanfieldRush_Talon
|
from canfield import CanfieldRush_Talon
|
||||||
|
@ -283,15 +284,14 @@ class BlindAlleys(Eastcliff):
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Somerset
|
# // Somerset
|
||||||
# // Morehead
|
# // Morehead
|
||||||
# // Canister
|
# // Usk
|
||||||
# // American Canister
|
|
||||||
# // British Canister
|
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Somerset(Klondike):
|
class Somerset(Klondike):
|
||||||
Talon_Class = InitialDealTalonStack
|
Talon_Class = InitialDealTalonStack
|
||||||
RowStack_Class = StackWrapper(AC_RowStack, max_move=1)
|
RowStack_Class = SuperMoveAC_RowStack
|
||||||
Hint_Class = CautiousDefaultHint
|
Hint_Class = CautiousDefaultHint
|
||||||
|
Solver_Class = FreeCellSolverWrapper()
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
Klondike.createGame(self, max_rounds=1, rows=10, waste=0, texts=0)
|
Klondike.createGame(self, max_rounds=1, rows=10, waste=0, texts=0)
|
||||||
|
@ -306,12 +306,14 @@ class Somerset(Klondike):
|
||||||
|
|
||||||
class Morehead(Somerset):
|
class Morehead(Somerset):
|
||||||
RowStack_Class = StackWrapper(BO_RowStack, max_move=1)
|
RowStack_Class = StackWrapper(BO_RowStack, max_move=1)
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
|
|
||||||
class Usk(Somerset):
|
class Usk(Somerset):
|
||||||
|
|
||||||
Talon_Class = RedealTalonStack
|
Talon_Class = RedealTalonStack
|
||||||
RowStack_Class = StackWrapper(AC_RowStack, base_rank=KING)
|
RowStack_Class = StackWrapper(AC_RowStack, base_rank=KING)
|
||||||
|
Solver_Class = None
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
Klondike.createGame(self, max_rounds=2, rows=10, waste=0, texts=0)
|
Klondike.createGame(self, max_rounds=2, rows=10, waste=0, texts=0)
|
||||||
|
@ -330,6 +332,8 @@ class Usk(Somerset):
|
||||||
|
|
||||||
class AmericanCanister(Klondike):
|
class AmericanCanister(Klondike):
|
||||||
Talon_Class = InitialDealTalonStack
|
Talon_Class = InitialDealTalonStack
|
||||||
|
RowStack_Class = AC_RowStack
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sm='unlimited')
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
Klondike.createGame(self, max_rounds=1, rows=8, waste=0, texts=0)
|
Klondike.createGame(self, max_rounds=1, rows=8, waste=0, texts=0)
|
||||||
|
@ -344,11 +348,13 @@ class AmericanCanister(Klondike):
|
||||||
|
|
||||||
class Canister(AmericanCanister):
|
class Canister(AmericanCanister):
|
||||||
RowStack_Class = RK_RowStack
|
RowStack_Class = RK_RowStack
|
||||||
|
Solver_Class = FreeCellSolverWrapper(sbb='rank', sm='unlimited')
|
||||||
shallHighlightMatch = Game._shallHighlightMatch_RK
|
shallHighlightMatch = Game._shallHighlightMatch_RK
|
||||||
|
|
||||||
|
|
||||||
class BritishCanister(AmericanCanister):
|
class BritishCanister(AmericanCanister):
|
||||||
RowStack_Class = StackWrapper(KingAC_RowStack, max_move=1)
|
RowStack_Class = StackWrapper(KingAC_RowStack, max_move=1)
|
||||||
|
Solver_Class = FreeCellSolverWrapper(esf='kings')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -813,6 +819,7 @@ class Alternation(Klondike):
|
||||||
|
|
||||||
class Lanes(Klondike):
|
class Lanes(Klondike):
|
||||||
|
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
Foundation_Class = StackWrapper(SS_FoundationStack, max_move=0)
|
Foundation_Class = StackWrapper(SS_FoundationStack, max_move=0)
|
||||||
RowStack_Class = StackWrapper(AC_RowStack, base_rank=ANY_RANK, max_move=1)
|
RowStack_Class = StackWrapper(AC_RowStack, base_rank=ANY_RANK, max_move=1)
|
||||||
|
|
||||||
|
@ -979,6 +986,8 @@ class DoubleDot(Klondike):
|
||||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||||
return abs(card1.rank-card2.rank) == 2
|
return abs(card1.rank-card2.rank) == 2
|
||||||
|
|
||||||
|
shallHighlightMatch = Game._shallHighlightMatch_RKW
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Seven Devils
|
# // Seven Devils
|
||||||
|
@ -1176,6 +1185,7 @@ class GoldMine(Klondike):
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class LuckyThirteen(Game):
|
class LuckyThirteen(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK)
|
RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK)
|
||||||
|
|
||||||
def createGame(self, xoffset=0, playcards=0):
|
def createGame(self, xoffset=0, playcards=0):
|
||||||
|
|
|
@ -95,8 +95,8 @@ class Mahjongg_Foundation(OpenStack):
|
||||||
def basicIsBlocked(self):
|
def basicIsBlocked(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def initBindings(self):
|
#def initBindings(self):
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
def _position(self, card):
|
def _position(self, card):
|
||||||
#AbstractFoundationStack._position(self, card)
|
#AbstractFoundationStack._position(self, card)
|
||||||
|
@ -360,11 +360,13 @@ class AbstractMahjonggGame(Game):
|
||||||
if self.preview:
|
if self.preview:
|
||||||
# Fixme
|
# Fixme
|
||||||
dx, dy, d_x, d_y = dx/2, dy/2, d_x/2, d_y/2
|
dx, dy, d_x, d_y = dx/2, dy/2, d_x/2, d_y/2
|
||||||
|
self._delta_x, self._delta_y = dx, -dy
|
||||||
else:
|
else:
|
||||||
dx = 3
|
dx = 3
|
||||||
dy = -3
|
dy = -3
|
||||||
d_x = 0
|
d_x = 0
|
||||||
d_y = 0
|
d_y = 0
|
||||||
|
self._delta_x, self._delta_y = 0, 0
|
||||||
#print dx, dy, d_x, d_y, cs.version
|
#print dx, dy, d_x, d_y, cs.version
|
||||||
|
|
||||||
font = self.app.getFont("canvas_default")
|
font = self.app.getFont("canvas_default")
|
||||||
|
@ -472,7 +474,7 @@ class AbstractMahjonggGame(Game):
|
||||||
y = l.YM+fdyy+j*cardh
|
y = l.YM+fdyy+j*cardh
|
||||||
else:
|
else:
|
||||||
if TOOLKIT == 'tk':
|
if TOOLKIT == 'tk':
|
||||||
x = -l.XS
|
x = -l.XS-self.canvas.xmargin
|
||||||
y = l.YM+dyy
|
y = l.YM+dyy
|
||||||
elif TOOLKIT == 'gtk':
|
elif TOOLKIT == 'gtk':
|
||||||
# FIXME
|
# FIXME
|
||||||
|
@ -635,6 +637,10 @@ class AbstractMahjonggGame(Game):
|
||||||
# Mahjongg special: highlight all moveable tiles
|
# Mahjongg special: highlight all moveable tiles
|
||||||
return ((self.s.rows, 1),)
|
return ((self.s.rows, 1),)
|
||||||
|
|
||||||
|
def _highlightCards(self, info, sleep=1.5, delta=(1,1,1,1)):
|
||||||
|
delta = (-self._delta_x, 0, 0, -self._delta_y)
|
||||||
|
Game._highlightCards(self, info, sleep=sleep, delta=delta)
|
||||||
|
|
||||||
def getCardFaceImage(self, deck, suit, rank):
|
def getCardFaceImage(self, deck, suit, rank):
|
||||||
if suit == 3:
|
if suit == 3:
|
||||||
cs = self.app.cardset
|
cs = self.app.cardset
|
||||||
|
@ -690,6 +696,7 @@ class AbstractMahjonggGame(Game):
|
||||||
return 7 >= card2.rank >= 4
|
return 7 >= card2.rank >= 4
|
||||||
return card1.rank == card2.rank
|
return card1.rank == card2.rank
|
||||||
|
|
||||||
|
|
||||||
## mahjongg util
|
## mahjongg util
|
||||||
def comp_cardset(ncards):
|
def comp_cardset(ncards):
|
||||||
# calc decks, ranks & trumps
|
# calc decks, ranks & trumps
|
||||||
|
|
|
@ -254,13 +254,14 @@ class Shisen_RowStack(Mahjongg_RowStack):
|
||||||
cardw = images.CARDW
|
cardw = images.CARDW
|
||||||
cardh = images.CARDH
|
cardh = images.CARDH
|
||||||
coords = []
|
coords = []
|
||||||
|
dx, dy = game._delta_x, game._delta_y
|
||||||
for x, y in path:
|
for x, y in path:
|
||||||
if x == 0:
|
if x == 0:
|
||||||
coords.append(6)
|
coords.append(6)
|
||||||
elif x == game.L[0]+1:
|
elif x == game.L[0]+1:
|
||||||
coords.append(x0+cardw*(x-1)+10)
|
coords.append(x0+cardw*(x-1)+10+dx)
|
||||||
else:
|
else:
|
||||||
coords.append(x0+cardw/2+cardw*(x-1))
|
coords.append(x0+cardw/2+cardw*(x-1)+dx)
|
||||||
if y == 0:
|
if y == 0:
|
||||||
coords.append(6)
|
coords.append(6)
|
||||||
elif y == game.L[1]+1:
|
elif y == game.L[1]+1:
|
||||||
|
@ -308,11 +309,13 @@ class AbstractShisenGame(AbstractMahjonggGame):
|
||||||
dy = -l.YOFFSET
|
dy = -l.YOFFSET
|
||||||
d_x = cs.SHADOW_XOFFSET
|
d_x = cs.SHADOW_XOFFSET
|
||||||
d_y = cs.SHADOW_YOFFSET
|
d_y = cs.SHADOW_YOFFSET
|
||||||
|
self._delta_x, self._delta_y = dx, -dy
|
||||||
else:
|
else:
|
||||||
dx = 3
|
dx = 3
|
||||||
dy = -3
|
dy = -3
|
||||||
d_x = 0
|
d_x = 0
|
||||||
d_y = 0
|
d_y = 0
|
||||||
|
self._delta_x, self._delta_y = 0, 0
|
||||||
|
|
||||||
font = self.app.getFont("canvas_default")
|
font = self.app.getFont("canvas_default")
|
||||||
|
|
||||||
|
@ -358,10 +361,9 @@ class AbstractShisenGame(AbstractMahjonggGame):
|
||||||
self.texts.info = MfxCanvasText(self.canvas,
|
self.texts.info = MfxCanvasText(self.canvas,
|
||||||
self.width - l.XM - ti_width, y,
|
self.width - l.XM - ti_width, y,
|
||||||
anchor="nw", font=font)
|
anchor="nw", font=font)
|
||||||
x = self.width + l.XS
|
|
||||||
y = self.height - l.YS - dxx
|
|
||||||
# the Talon is invisble
|
# the Talon is invisble
|
||||||
s.talon = InitialDealTalonStack(x, y + l.YS, self)
|
s.talon = InitialDealTalonStack(-l.XS-self.canvas.xmargin,
|
||||||
|
self.height-dyy, self)
|
||||||
|
|
||||||
# Define stack groups
|
# Define stack groups
|
||||||
l.defaultStackGroups()
|
l.defaultStackGroups()
|
||||||
|
|
|
@ -716,7 +716,7 @@ class Assembly_RowStack(RK_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class Assembly(Numerica):
|
class Assembly(Numerica):
|
||||||
Hint_Class = DefaultHint
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
Foundation_Class = StackWrapper(RK_FoundationStack, suit=ANY_SUIT)
|
Foundation_Class = StackWrapper(RK_FoundationStack, suit=ANY_SUIT)
|
||||||
RowStack_Class = StackWrapper(Assembly_RowStack, max_move=1)
|
RowStack_Class = StackWrapper(Assembly_RowStack, max_move=1)
|
||||||
|
|
|
@ -274,7 +274,7 @@ class Pyramid(Game):
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRow()
|
self.s.talon.dealRow(frames=4)
|
||||||
self.s.talon.dealCards() # deal first card to WasteStack
|
self.s.talon.dealCards() # deal first card to WasteStack
|
||||||
|
|
||||||
def getAutoStacks(self, event=None):
|
def getAutoStacks(self, event=None):
|
||||||
|
@ -585,7 +585,7 @@ class Fifteens_RowStack(Elevens_RowStack):
|
||||||
def acceptsCards(self, from_stack, cards):
|
def acceptsCards(self, from_stack, cards):
|
||||||
if not Elevens_RowStack.acceptsCards(self, from_stack, cards):
|
if not Elevens_RowStack.acceptsCards(self, from_stack, cards):
|
||||||
return False
|
return False
|
||||||
return cards[0].rank < 9 and self.cards[0] < 9
|
return cards[0].rank < 9 and self.cards[0].rank < 9
|
||||||
|
|
||||||
|
|
||||||
class Fifteens_Reserve(ReserveStack):
|
class Fifteens_Reserve(ReserveStack):
|
||||||
|
@ -919,7 +919,7 @@ class Apophis(Pharaohs):
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRow(frames=3)
|
self.s.talon.dealRow(frames=4)
|
||||||
self.s.talon.dealCards()
|
self.s.talon.dealCards()
|
||||||
|
|
||||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||||
|
@ -954,7 +954,7 @@ class Cheops_RowStack(Cheops_StackMethods, Pyramid_RowStack):
|
||||||
|
|
||||||
class Cheops(Pyramid):
|
class Cheops(Pyramid):
|
||||||
|
|
||||||
Foundation_Class = AbstractFoundationStack
|
Foundation_Class = StackWrapper(AbstractFoundationStack, max_accept=0)
|
||||||
Talon_Class = StackWrapper(Cheops_Talon, max_rounds=1, max_accept=1)
|
Talon_Class = StackWrapper(Cheops_Talon, max_rounds=1, max_accept=1)
|
||||||
RowStack_Class = Cheops_RowStack
|
RowStack_Class = Cheops_RowStack
|
||||||
WasteStack_Class = Cheops_Waste
|
WasteStack_Class = Cheops_Waste
|
||||||
|
|
|
@ -592,6 +592,7 @@ class ThreePirates_Talon(DealRowTalonStack):
|
||||||
|
|
||||||
|
|
||||||
class ThreePirates(Game):
|
class ThreePirates(Game):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
l, s = Layout(self), self.s
|
l, s = Layout(self), self.s
|
||||||
|
@ -634,6 +635,20 @@ class ThreePirates(Game):
|
||||||
# // Frames
|
# // Frames
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class Frames_Hint(CautiousDefaultHint):
|
||||||
|
def computeHints(self):
|
||||||
|
CautiousDefaultHint.computeHints(self)
|
||||||
|
if self.hints:
|
||||||
|
return
|
||||||
|
if not self.game.s.talon.cards:
|
||||||
|
return
|
||||||
|
for s in self.game.s.reserves:
|
||||||
|
if s.cards:
|
||||||
|
for r in self.game.s.rows:
|
||||||
|
if r.acceptsCards(s, s.cards):
|
||||||
|
self.addHint(5000, 1, s, r)
|
||||||
|
|
||||||
|
|
||||||
class Frames_Foundation(UnionSquare_Foundation):
|
class Frames_Foundation(UnionSquare_Foundation):
|
||||||
def acceptsCards(self, from_stack, cards):
|
def acceptsCards(self, from_stack, cards):
|
||||||
if not UnionSquare_Foundation.acceptsCards(self, from_stack, cards):
|
if not UnionSquare_Foundation.acceptsCards(self, from_stack, cards):
|
||||||
|
@ -664,7 +679,7 @@ class Frames_RowStack(UD_SS_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class Frames(Game):
|
class Frames(Game):
|
||||||
Hint_Class = CautiousDefaultHint
|
Hint_Class = Frames_Hint #CautiousDefaultHint
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
l, s = Layout(self), self.s
|
l, s = Layout(self), self.s
|
||||||
|
@ -1053,7 +1068,7 @@ class Colonel(Game):
|
||||||
|
|
||||||
x, y = l.XM+2*l.XS, l.YM
|
x, y = l.XM+2*l.XS, l.YM
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
s.foundations.append(SS_FoundationStack(x, y, self, suit=i%4,
|
s.foundations.append(SS_FoundationStack(x, y, self, suit=i/2,
|
||||||
max_move=0))
|
max_move=0))
|
||||||
x += l.XS
|
x += l.XS
|
||||||
|
|
||||||
|
@ -1079,7 +1094,7 @@ class Colonel(Game):
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRow()
|
self.s.talon.dealRow(frames=4)
|
||||||
self.s.talon.dealCards()
|
self.s.talon.dealCards()
|
||||||
|
|
||||||
shallHighlightMatch = Game._shallHighlightMatch_SS
|
shallHighlightMatch = Game._shallHighlightMatch_SS
|
||||||
|
|
|
@ -161,6 +161,19 @@ class SiebenBisAs(Game):
|
||||||
# // Maze
|
# // Maze
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class Maze_Hint(SiebenBisAs_Hint):
|
||||||
|
def shallMovePile(self, from_stack, to_stack, pile, rpile):
|
||||||
|
if from_stack is to_stack or not to_stack.acceptsCards(from_stack, pile):
|
||||||
|
return 0
|
||||||
|
# now check for loops
|
||||||
|
rr = self.ClonedStack(from_stack, stackcards=rpile)
|
||||||
|
if rr.acceptsCards(to_stack, pile):
|
||||||
|
# the pile we are going to move could be moved back -
|
||||||
|
# this is dangerous as we can create endless loops...
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class Maze_RowStack(BasicRowStack):
|
class Maze_RowStack(BasicRowStack):
|
||||||
def acceptsCards(self, from_stack, cards):
|
def acceptsCards(self, from_stack, cards):
|
||||||
if not BasicRowStack.acceptsCards(self, from_stack, cards):
|
if not BasicRowStack.acceptsCards(self, from_stack, cards):
|
||||||
|
@ -189,7 +202,7 @@ class Maze_RowStack(BasicRowStack):
|
||||||
class Maze(Game):
|
class Maze(Game):
|
||||||
GAME_VERSION = 2
|
GAME_VERSION = 2
|
||||||
|
|
||||||
Hint_Class = SiebenBisAs_Hint
|
Hint_Class = Maze_Hint #SiebenBisAs_Hint
|
||||||
|
|
||||||
#
|
#
|
||||||
# game layout
|
# game layout
|
||||||
|
|
|
@ -42,6 +42,7 @@ from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
from pysollib.hint import SpiderType_Hint, YukonType_Hint
|
from pysollib.hint import SpiderType_Hint, YukonType_Hint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -112,6 +113,23 @@ class Spider_RowStack(Spider_SS_RowStack):
|
||||||
return (None, 0)
|
return (None, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class SuperMoveSpider_RowStack(SuperMoveStack_StackMethods, Spider_RowStack):
|
||||||
|
def acceptsCards(self, from_stack, cards):
|
||||||
|
if not Spider_RowStack.acceptsCards(self, from_stack, cards):
|
||||||
|
return False
|
||||||
|
num_seq = self._getNumSSSeq(cards)
|
||||||
|
max_move = self._getMaxMove(len(self.cards))
|
||||||
|
return num_seq <= max_move
|
||||||
|
def canMoveCards(self, cards):
|
||||||
|
if not self.basicCanMoveCards(cards):
|
||||||
|
return False
|
||||||
|
if not isRankSequence(cards, self.cap.mod, self.cap.dir):
|
||||||
|
return False
|
||||||
|
num_seq = self._getNumSSSeq(cards)
|
||||||
|
max_move = self._getMaxMove(1)
|
||||||
|
return num_seq <= max_move
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Relaxed Spider
|
# // Relaxed Spider
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
@ -282,6 +300,8 @@ class WillOTheWisp(Spiderette):
|
||||||
|
|
||||||
class SimpleSimon(Spider):
|
class SimpleSimon(Spider):
|
||||||
Talon_Class = InitialDealTalonStack
|
Talon_Class = InitialDealTalonStack
|
||||||
|
RowStack_Class = SuperMoveSpider_RowStack
|
||||||
|
Solver_Class = FreeCellSolverWrapper(preset='simple_simon', base_rank=0)
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
Spider.createGame(self, rows=10, texts=0)
|
Spider.createGame(self, rows=10, texts=0)
|
||||||
|
@ -292,6 +312,12 @@ class SimpleSimon(Spider):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRow()
|
self.s.talon.dealRow()
|
||||||
|
|
||||||
|
class SimpleSimonII(SimpleSimon):
|
||||||
|
Solver_Class = None
|
||||||
|
Foundation_Class = StackWrapper(Spider_SS_Foundation,
|
||||||
|
base_rank=ANY_RANK, mod=13)
|
||||||
|
RowStack_Class = StackWrapper(SuperMoveSpider_RowStack, mod=13)
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Rachel
|
# // Rachel
|
||||||
|
@ -1370,4 +1396,6 @@ registerGame(GameInfo(685, FechtersGame, "Fechter's Game",
|
||||||
GI.GT_SPIDER, 2, 0, GI.SL_MOSTLY_SKILL))
|
GI.GT_SPIDER, 2, 0, GI.SL_MOSTLY_SKILL))
|
||||||
registerGame(GameInfo(710, Bebop, "Bebop",
|
registerGame(GameInfo(710, Bebop, "Bebop",
|
||||||
GI.GT_2DECK_TYPE | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL))
|
GI.GT_2DECK_TYPE | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL))
|
||||||
|
#registerGame(GameInfo(711, SimpleSimonII, "Simple Simon II",
|
||||||
|
# GI.GT_SPIDER | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
|
||||||
|
|
||||||
|
|
|
@ -762,13 +762,13 @@ class RoyalAids(Game):
|
||||||
s.waste = WasteStack(x, y, self)
|
s.waste = WasteStack(x, y, self)
|
||||||
l.createText(s.waste, 'se')
|
l.createText(s.waste, 'se')
|
||||||
|
|
||||||
x, y = l.XM+4*l.XS, l.YM+2*l.YS
|
x, y = l.XM+3.75*l.XS, l.YM+2*l.YS
|
||||||
for i in (0,1):
|
for i in (0,1):
|
||||||
stack = RoyalAids_RowStack(x, y, self, max_move=1)
|
stack = RoyalAids_RowStack(x, y, self, max_move=1)
|
||||||
s.rows.append(stack)
|
s.rows.append(stack)
|
||||||
stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0
|
stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0
|
||||||
x += l.XS
|
x += l.XS
|
||||||
x, y = l.XM+3*l.XS, l.YM+3*l.YS
|
x, y = l.XM+2.75*l.XS, l.YM+3*l.YS
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
stack = BasicRowStack(x, y, self)
|
stack = BasicRowStack(x, y, self)
|
||||||
s.reserves.append(stack)
|
s.reserves.append(stack)
|
||||||
|
@ -995,7 +995,7 @@ class Khedive(Game):
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRow()
|
self.s.talon.dealRow(frames=4)
|
||||||
self.s.talon.dealCards()
|
self.s.talon.dealCards()
|
||||||
|
|
||||||
def fillStack(self, stack):
|
def fillStack(self, stack):
|
||||||
|
|
|
@ -365,9 +365,9 @@ class BastilleDay_BastilleStack(Stack):
|
||||||
old_state = self.game.enterState(self.game.S_DEAL)
|
old_state = self.game.enterState(self.game.S_DEAL)
|
||||||
if sound and not self.game.demo:
|
if sound and not self.game.demo:
|
||||||
self.game.playSample("dealwaste")
|
self.game.playSample("dealwaste")
|
||||||
self.flipMove()
|
self.game.flipAndMoveMove(self, self.game.s.reserves[-1])
|
||||||
self.moveMove(1, self.game.s.reserves[-1], frames=4, shadow=0)
|
|
||||||
self.game.leaveState(old_state)
|
self.game.leaveState(old_state)
|
||||||
|
self.game.finishMove()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def getHelp(self):
|
def getHelp(self):
|
||||||
|
@ -432,7 +432,7 @@ class BastilleDay(Game):
|
||||||
if self.demo:
|
if self.demo:
|
||||||
r = self.s.reserves[0]
|
r = self.s.reserves[0]
|
||||||
if r.canDealCards():
|
if r.canDealCards():
|
||||||
self.demo.last_deal = [] # don't check last deal
|
##self.demo.last_deal = [] # don't check last deal
|
||||||
return r.dealCards(sound=sound)
|
return r.dealCards(sound=sound)
|
||||||
return Game.dealCards(self, sound=sound)
|
return Game.dealCards(self, sound=sound)
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,7 @@ class DutchSolitaire_RowStack(UD_RK_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class DutchSolitaire(Windmill):
|
class DutchSolitaire(Windmill):
|
||||||
|
Hint_Class = CautiousDefaultHint
|
||||||
Foundation_Classes = [
|
Foundation_Classes = [
|
||||||
StackWrapper(BlackHole_Foundation, suit=ANY_SUIT, mod=13,
|
StackWrapper(BlackHole_Foundation, suit=ANY_SUIT, mod=13,
|
||||||
max_cards=UNLIMITED_CARDS, min_cards=1),
|
max_cards=UNLIMITED_CARDS, min_cards=1),
|
||||||
|
@ -270,7 +271,7 @@ class Corners(Game):
|
||||||
self.setSize(5*l.XS+l.XM, 4*l.YS+3*l.YM)
|
self.setSize(5*l.XS+l.XM, 4*l.YS+3*l.YM)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
x, y = l.XM+l.XS, l.YM
|
x, y = l.XM+1.5*l.XS, l.YM
|
||||||
s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds)
|
s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds)
|
||||||
l.createText(s.talon, "sw")
|
l.createText(s.talon, "sw")
|
||||||
x += l.XS
|
x += l.XS
|
||||||
|
|
|
@ -43,6 +43,7 @@ from pysollib.game import Game
|
||||||
from pysollib.layout import Layout
|
from pysollib.layout import Layout
|
||||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
from pysollib.hint import YukonType_Hint
|
from pysollib.hint import YukonType_Hint
|
||||||
|
from pysollib.hint import FreeCellSolverWrapper
|
||||||
from pysollib.pysoltk import MfxCanvasText
|
from pysollib.pysoltk import MfxCanvasText
|
||||||
|
|
||||||
from spider import Spider_SS_Foundation
|
from spider import Spider_SS_Foundation
|
||||||
|
|
355
pysollib/hint.py
|
@ -36,8 +36,10 @@
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
import os, sys
|
import os, sys
|
||||||
|
import time
|
||||||
|
|
||||||
# PySol imports
|
# PySol imports
|
||||||
|
from settings import USE_FREECELL_SOLVER, FCS_COMMAND
|
||||||
from mfxutil import destruct
|
from mfxutil import destruct
|
||||||
from util import KING
|
from util import KING
|
||||||
|
|
||||||
|
@ -689,289 +691,234 @@ class SpiderType_Hint(DefaultHint):
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# // FreeCell-Solver
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
FreecellSolver = None
|
|
||||||
|
|
||||||
## try:
|
class FreeCellSolver_Hint:
|
||||||
## import FreecellSolver
|
|
||||||
## except:
|
|
||||||
## FreecellSolver = None
|
|
||||||
|
|
||||||
fcs_command = 'fc-solve'
|
def __init__(self, game, dialog, **game_type):
|
||||||
if os.name == 'nt':
|
self.game = game
|
||||||
if sys.path[0] and not os.path.isdir(sys.path[0]): # i.e. library.zip
|
self.dialog = dialog
|
||||||
fcs_command = os.path.join(os.path.split(sys.path[0])[0], 'fc-solve.exe')
|
self.game_type = game_type
|
||||||
fcs_command = '"%s"' % fcs_command
|
self.options = {
|
||||||
|
'method': 'dfs',
|
||||||
|
'max_iters': 10000,
|
||||||
|
'max_depth': 1000,
|
||||||
|
'progress': False,
|
||||||
|
'preset': None,
|
||||||
|
}
|
||||||
|
self.hints = []
|
||||||
|
self.hints_index = 0
|
||||||
|
|
||||||
if os.name in ('posix', 'nt'):
|
# correct cards rank if foundations.base_rank != 0 (Penguin, Opus)
|
||||||
try:
|
if 'base_rank' in game_type: # (Simple Simon)
|
||||||
pin, pout, perr = os.popen3(fcs_command+' --help')
|
self.base_rank = game_type['base_rank']
|
||||||
if pout.readline().startswith('fc-solve'):
|
else:
|
||||||
FreecellSolver = True
|
self.base_rank = game.s.foundations[0].cap.base_rank
|
||||||
del pin, pout, perr
|
##print 'game_type:', game_type
|
||||||
if os.name == 'posix':
|
##print 'base_rank:', self.base_rank
|
||||||
os.wait()
|
|
||||||
except:
|
def config(self, **kw):
|
||||||
##traceback.print_exc()
|
self.options.update(kw)
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class FreeCellSolverWrapper:
|
def card2str1(self, card):
|
||||||
__name__ = 'FreeCellSolverWrapper' # for gameinfodialog
|
# row and reserves
|
||||||
|
rank = (card.rank-self.base_rank) % 13
|
||||||
|
return "A23456789TJQK"[rank] + "CSHD"[card.suit]
|
||||||
|
def card2str2(self, card):
|
||||||
|
# foundations
|
||||||
|
rank = (card.rank-self.base_rank) % 13
|
||||||
|
return "CSHD"[card.suit] + "-" + "A23456789TJQK"[rank]
|
||||||
|
|
||||||
class FreeCellSolver_Hint(AbstractHint):
|
# hard solvable: Freecell #47038300998351211829 (65539 iters)
|
||||||
def str1(self, card):
|
|
||||||
return "A23456789TJQK"[card.rank] + "CSHD"[card.suit]
|
|
||||||
def str2(self, card):
|
|
||||||
return "CSHD"[card.suit] + "-" + "A23456789TJQK"[card.rank]
|
|
||||||
|
|
||||||
|
def getHints(self, taken_hint=None):
|
||||||
|
if taken_hint and taken_hint[6]:
|
||||||
|
return [taken_hint[6]]
|
||||||
|
h = self.hints[self.hints_index]
|
||||||
|
#print 'getHints', taken_hint, h
|
||||||
|
if h is None:
|
||||||
|
return None
|
||||||
|
ncards, src, dest = h
|
||||||
|
thint = None
|
||||||
|
if len(src.cards) > ncards and not src.cards[-ncards-1].face_up:
|
||||||
|
# flip card
|
||||||
|
thint = (999999, 0, 1, src, src, None, None)
|
||||||
|
if dest == None: # foundation
|
||||||
|
cards = src.cards[-ncards:]
|
||||||
|
for f in self.game.s.foundations:
|
||||||
|
if f.acceptsCards(src, cards):
|
||||||
|
dest = f
|
||||||
|
break
|
||||||
|
assert dest
|
||||||
|
hint = (999999, 0, ncards, src, dest, None, thint)
|
||||||
|
self.hints_index += 1
|
||||||
|
#print hint
|
||||||
|
return [hint]
|
||||||
|
|
||||||
def computeHints(self):
|
def computeHints(self):
|
||||||
##print 'FreeCellSolver_Hint.computeHints'
|
game = self.game
|
||||||
|
game_type = self.game_type
|
||||||
|
progress = self.options['progress']
|
||||||
board = ''
|
board = ''
|
||||||
pboard = {}
|
#
|
||||||
#
|
#
|
||||||
b = ''
|
b = ''
|
||||||
#l = []
|
|
||||||
for s in self.game.s.foundations:
|
for s in self.game.s.foundations:
|
||||||
if s.cards:
|
if s.cards:
|
||||||
b = b + ' ' + self.str2(s.cards[-1])
|
ss = self.card2str2(s.cards[-1])
|
||||||
#l.append(self.str2(s.cards[-1]))
|
b += ' ' + ss
|
||||||
if b:
|
if b:
|
||||||
board = board + 'Founds:' + b + '\n'
|
board += 'Founds:' + b + '\n'
|
||||||
#pboard['Founds'] = l
|
|
||||||
#
|
#
|
||||||
b = ''
|
b = ''
|
||||||
l = []
|
|
||||||
for s in self.game.s.reserves:
|
for s in self.game.s.reserves:
|
||||||
if s.cards:
|
if s.cards:
|
||||||
cs = self.str1(s.cards[-1])
|
cs = self.card2str1(s.cards[-1])
|
||||||
b = b + ' ' + cs
|
b += ' ' + cs
|
||||||
l.append(cs)
|
|
||||||
else:
|
else:
|
||||||
b = b + ' -'
|
b += ' -'
|
||||||
l.append(None)
|
|
||||||
if b:
|
if b:
|
||||||
board = board + 'FC:' + b + '\n'
|
board += 'FC:' + b + '\n'
|
||||||
pboard['FC'] = l
|
|
||||||
#
|
#
|
||||||
n = 0
|
|
||||||
for s in self.game.s.rows:
|
for s in self.game.s.rows:
|
||||||
b = ''
|
b = ''
|
||||||
l = []
|
|
||||||
for c in s.cards:
|
for c in s.cards:
|
||||||
cs = self.str1(c)
|
cs = self.card2str1(c)
|
||||||
if not c.face_up:
|
if not c.face_up:
|
||||||
cs = '<%s>' % cs
|
cs = '<%s>' % cs
|
||||||
b = b + cs + ' '
|
b += cs + ' '
|
||||||
l.append(cs)
|
|
||||||
board = board + b.strip() + '\n'
|
board = board + b.strip() + '\n'
|
||||||
pboard[n] = l
|
|
||||||
n += 1
|
|
||||||
#
|
#
|
||||||
##print board
|
##print '--------------------\n', board, '--------------------'
|
||||||
#
|
#
|
||||||
args = []
|
args = []
|
||||||
args += ['-sam', '-p', '--display-10-as-t']
|
##args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
||||||
##args += ['-l', 'good-intentions']
|
args += ['-m', '-p', '-opt']
|
||||||
args += ['--max-iters', 200000]
|
if self.options['preset'] and self.options['preset'] != 'none':
|
||||||
args += ['--decks-num', self.fcs_args[0],
|
args += ['-l', self.options['preset']]
|
||||||
'--stacks-num', self.fcs_args[1],
|
if progress:
|
||||||
'--freecells-num', self.fcs_args[2],
|
args += ['--iter-output']
|
||||||
|
##args += ['-s']
|
||||||
|
args += ['--max-iters', self.options['max_iters'],
|
||||||
|
'--max-depth', self.options['max_depth'],
|
||||||
|
'--method', self.options['method'],
|
||||||
|
'--decks-num', game.gameinfo.decks,
|
||||||
|
'--stacks-num', len(game.s.rows),
|
||||||
|
'--freecells-num', len(game.s.reserves),
|
||||||
]
|
]
|
||||||
#
|
#
|
||||||
game_type = self.fcs_args[3]
|
if 'preset' in game_type:
|
||||||
|
args += ['--preset', game_type['preset']]
|
||||||
if 'sbb' in game_type:
|
if 'sbb' in game_type:
|
||||||
args += ['--sequences-are-built-by', game_type['sbb']]
|
args += ['--sequences-are-built-by', game_type['sbb']]
|
||||||
if 'sm' in game_type:
|
if 'sm' in game_type:
|
||||||
args += ['--sequence-move', game_type['sm']]
|
args += ['--sequence-move', game_type['sm']]
|
||||||
if 'esf' in game_type:
|
if 'esf' in game_type:
|
||||||
args += ['--empty-stacks-filled-by', game_type['esf']]
|
args += ['--empty-stacks-filled-by', game_type['esf']]
|
||||||
if 'preset' in game_type:
|
|
||||||
args += ['--preset', game_type['preset']]
|
|
||||||
|
|
||||||
command = fcs_command+' '+' '.join([str(i) for i in args])
|
command = FCS_COMMAND+' '+' '.join([str(i) for i in args])
|
||||||
##print command
|
##print command
|
||||||
pin, pout, perr = os.popen3(command)
|
pin, pout, perr = os.popen3(command)
|
||||||
pin.write(board)
|
pin.write(board)
|
||||||
pin.close()
|
pin.close()
|
||||||
#
|
#
|
||||||
stack_types = {
|
stack_types = {
|
||||||
'the' : self.game.s.foundations,
|
'the' : game.s.foundations,
|
||||||
'stack' : self.game.s.rows,
|
'stack' : game.s.rows,
|
||||||
'freecell' : self.game.s.reserves,
|
'freecell' : game.s.reserves,
|
||||||
}
|
}
|
||||||
my_hints = []
|
##start_time = time.time()
|
||||||
pboard_n = 0
|
if progress:
|
||||||
##print pboard
|
# iteration output
|
||||||
|
iter = 0
|
||||||
|
depth = 0
|
||||||
|
states = 0
|
||||||
for s in pout:
|
for s in pout:
|
||||||
##print s,
|
##print s,
|
||||||
|
if s.startswith('Iter'):
|
||||||
|
#print `s`
|
||||||
|
iter = int(s[10:-1])
|
||||||
|
elif s.startswith('Depth'):
|
||||||
|
#print s,
|
||||||
|
depth = int(s[6:-1])
|
||||||
|
elif s.startswith('Stor'):
|
||||||
|
#print s,
|
||||||
|
states = int(s[14:-1])
|
||||||
|
if iter % 100 == 0:
|
||||||
|
self.dialog.setText(iter=iter, depth=depth,
|
||||||
|
states=states)
|
||||||
|
elif s.startswith('-=-') or \
|
||||||
|
s.startswith('I co'): # "I could not solve this game."
|
||||||
|
break
|
||||||
|
self.dialog.setText(iter=iter, depth=depth, states=states)
|
||||||
|
|
||||||
|
hints = []
|
||||||
|
for s in pout:
|
||||||
|
#print s,
|
||||||
|
# TODO:
|
||||||
|
# Total number of states checked is 6.
|
||||||
|
# This scan generated 6 states.
|
||||||
|
|
||||||
if not s.startswith('Move'):
|
if not s.startswith('Move'):
|
||||||
if s.startswith('Freecells:'):
|
|
||||||
ss=s[10:]
|
|
||||||
pboard['FC'] = [ss[i:i+4].strip() for i in range(0, len(ss), 4)]
|
|
||||||
elif s.startswith(':'):
|
|
||||||
pboard[pboard_n] = s.split()[1:]
|
|
||||||
pboard_n += 1
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
words = s.split()
|
words = s.split()
|
||||||
ncards = words[1]
|
ncards = words[1]
|
||||||
if ncards == 'a':
|
if ncards == 'the':
|
||||||
|
# "Move the sequence on top of Stack 1 to the foundations"
|
||||||
|
# (Simple Simon)
|
||||||
|
ncards = 0
|
||||||
|
elif ncards == 'a':
|
||||||
ncards = 1
|
ncards = 1
|
||||||
else:
|
else:
|
||||||
ncards = int(ncards)
|
ncards = int(ncards)
|
||||||
|
|
||||||
sn = int(words[5])
|
if ncards:
|
||||||
st = stack_types[words[4]]
|
st = stack_types[words[4]]
|
||||||
src = st[sn]
|
sn = int(words[5])
|
||||||
|
src = st[sn] # source stack
|
||||||
if words[7] == 'the':
|
if words[7] == 'the':
|
||||||
# to foundation
|
# to foundation
|
||||||
if words[4] == 'stack':
|
|
||||||
# from rows
|
|
||||||
card = pboard[sn][-1]
|
|
||||||
else:
|
|
||||||
# from reserves
|
|
||||||
card = pboard['FC'][sn]
|
|
||||||
suit = 'CSHD'.index(card[1])
|
|
||||||
##dest = self.game.s.foundations[suit]
|
|
||||||
dest = None
|
dest = None
|
||||||
for f in self.game.s.foundations:
|
|
||||||
if f.cap.base_suit == suit:
|
|
||||||
dest = f
|
|
||||||
break
|
|
||||||
assert dest is not None
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# to rows or reserves
|
# to rows or reserves
|
||||||
dt = stack_types[words[7]]
|
dt = stack_types[words[7]]
|
||||||
dn = int(words[8])
|
dn = int(words[8])
|
||||||
dest = dt[dn]
|
dest = dt[dn]
|
||||||
|
else: # move sequence
|
||||||
|
ncards = 13
|
||||||
|
st = stack_types['stack']
|
||||||
|
sn = int(words[7])
|
||||||
|
src = st[sn]
|
||||||
|
dest = None
|
||||||
|
|
||||||
my_hints.append([ncards, src, dest])
|
hints.append([ncards, src, dest])
|
||||||
##print src, dest, ncards
|
##print src, dest, ncards
|
||||||
|
|
||||||
pboard = {}
|
#
|
||||||
pboard_n = 0
|
##print 'time:', time.time()-start_time
|
||||||
|
##print perr.read(),
|
||||||
|
|
||||||
|
self.hints = hints
|
||||||
|
self.hints.append(None) # XXX
|
||||||
|
|
||||||
my_hints.reverse()
|
|
||||||
hint = None
|
|
||||||
for i in my_hints:
|
|
||||||
hint = (999999, 0, i[0], i[1], i[2], None, hint)
|
|
||||||
if hint:
|
|
||||||
self.hints.append(hint)
|
|
||||||
##print self.hints
|
##print self.hints
|
||||||
|
|
||||||
|
pout.close()
|
||||||
|
perr.close()
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
os.wait()
|
os.wait()
|
||||||
|
|
||||||
|
|
||||||
def computeHints_mod(self):
|
class FreeCellSolverWrapper:
|
||||||
board = ""
|
|
||||||
#
|
|
||||||
b = ""
|
|
||||||
for s in self.game.s.foundations:
|
|
||||||
if s.cards:
|
|
||||||
b = b + " " + self.str2(s.cards[-1])
|
|
||||||
if b:
|
|
||||||
board = board + "Founds:" + b + "\n"
|
|
||||||
#
|
|
||||||
b = ""
|
|
||||||
for s in self.game.s.reserves:
|
|
||||||
if s.cards:
|
|
||||||
b = b + " " + self.str1(s.cards[-1])
|
|
||||||
else:
|
|
||||||
b = b + " -"
|
|
||||||
if b:
|
|
||||||
board = board + "FC:" + b + "\n"
|
|
||||||
#
|
|
||||||
for s in self.game.s.rows:
|
|
||||||
b = ""
|
|
||||||
for c in s.cards:
|
|
||||||
b = b + self.str1(c) + " "
|
|
||||||
board = board + b.strip() + "\n"
|
|
||||||
#
|
|
||||||
##print board
|
|
||||||
# solver = apply(FreecellSolver.FCSolver, self.fcs_args)
|
|
||||||
solver = FreecellSolver.alloc()
|
|
||||||
solver.config(["-l", "good-intentions"]);
|
|
||||||
solver.config(["--decks-num", self.fcs_args[0],
|
|
||||||
"--stacks-num", self.fcs_args[1],
|
|
||||||
"--freecells-num", self.fcs_args[2],
|
|
||||||
])
|
|
||||||
|
|
||||||
game_type = self.fcs_args[3]
|
def __init__(self, **game_type):
|
||||||
game_type_defaults = {'sbb' : 'alternate_color', 'sm' : 'limited', 'esf': 'all'}
|
self.game_type = game_type
|
||||||
for k,v in game_type_defaults.items():
|
|
||||||
if k not in game_type:
|
|
||||||
game_type[k] = v
|
|
||||||
|
|
||||||
solver.config(["--sequences-are-built-by", game_type['sbb'],
|
def __call__(self, game, dialog):
|
||||||
"--sequence-move", game_type['sm'],
|
hint = FreeCellSolver_Hint(game, dialog, **self.game_type)
|
||||||
"--empty-stacks-filled-by", game_type['esf'],
|
|
||||||
])
|
|
||||||
|
|
||||||
solver.limit_iterations(200000)
|
|
||||||
|
|
||||||
h = solver.solve(board)
|
|
||||||
if (h == "solved"):
|
|
||||||
move = solver.get_next_move()
|
|
||||||
hint = None
|
|
||||||
founds_map = [2,0,3,1,6,4,7,5]
|
|
||||||
my_hints = []
|
|
||||||
while (move):
|
|
||||||
print move
|
|
||||||
|
|
||||||
if (move['type'] == "s2s"):
|
|
||||||
ncards = move['num_cards']
|
|
||||||
else:
|
|
||||||
ncards = 1
|
|
||||||
|
|
||||||
src_idx = move['src']
|
|
||||||
if move['type'] in ("s2s", "s2found", "s2f"):
|
|
||||||
src = self.game.s.rows[src_idx]
|
|
||||||
else:
|
|
||||||
src = self.game.s.reserves[src_idx]
|
|
||||||
|
|
||||||
d_idx = move['dest']
|
|
||||||
if move['type'] in ("s2s", "f2s"):
|
|
||||||
dest = self.game.s.rows[d_idx]
|
|
||||||
elif move['type'] in ("s2f", "f2f"):
|
|
||||||
dest = self.game.s.reserves[d_idx]
|
|
||||||
else:
|
|
||||||
dest = self.game.s.foundations[founds_map[d_idx]]
|
|
||||||
|
|
||||||
# hint = (999999, 0, ncards, src, dest, None, 0)
|
|
||||||
my_hints.append([ncards, src, dest])
|
|
||||||
# self.hints.append(hint)
|
|
||||||
move = solver.get_next_move();
|
|
||||||
hint = None
|
|
||||||
my_hints.reverse()
|
|
||||||
for i in my_hints:
|
|
||||||
hint = (999999, 0, i[0], i[1], i[2], None, hint)
|
|
||||||
self.hints.append(hint)
|
|
||||||
#i = len(h)
|
|
||||||
#assert i % 3 == 0
|
|
||||||
#hint = None
|
|
||||||
#map = self.game.s.foundations + self.game.s.rows + self.game.s.reserves
|
|
||||||
#while i > 0:
|
|
||||||
# i = i - 3
|
|
||||||
# v = struct.unpack("<BBB", h[i:i+3])
|
|
||||||
# hint = (999999, 0, v[0], map[v[1]], map[v[2]], None, hint)
|
|
||||||
#self.hints.append(hint)
|
|
||||||
|
|
||||||
def __init__(self, Fallback_Class, *args):
|
|
||||||
self.Fallback_Class = Fallback_Class
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
def __call__(self, game, level):
|
|
||||||
if FreecellSolver is None:
|
|
||||||
hint = self.Fallback_Class(game, level)
|
|
||||||
else:
|
|
||||||
hint = self.FreeCellSolver_Hint(game, level)
|
|
||||||
hint.fcs_args = (game.gameinfo.decks, len(game.s.rows), len(game.s.reserves)) + self.args
|
|
||||||
return hint
|
return hint
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ class Images:
|
||||||
pass
|
pass
|
||||||
if progress: progress.update(step=pstep)
|
if progress: progress.update(step=pstep)
|
||||||
# shadow
|
# shadow
|
||||||
if TOOLKIT == 'tk' and Image:
|
if 0 and TOOLKIT == 'tk' and Image:
|
||||||
fn = self.d.findImage('shadow', 'images')
|
fn = self.d.findImage('shadow', 'images')
|
||||||
self._pil_shadow_image = Image.open(fn).convert('RGBA')
|
self._pil_shadow_image = Image.open(fn).convert('RGBA')
|
||||||
else:
|
else:
|
||||||
|
@ -302,7 +302,6 @@ class Images:
|
||||||
y0, y1 = min(y1, y0), max(y1, y0)
|
y0, y1 = min(y1, y0), max(y1, y0)
|
||||||
x1 = x1 + self.CARDW
|
x1 = x1 + self.CARDW
|
||||||
y1 = y1 + self.CARDH
|
y1 = y1 + self.CARDH
|
||||||
#xx0, yy0 = x0, y0
|
|
||||||
w, h = x1-x0, y1-y0
|
w, h = x1-x0, y1-y0
|
||||||
if (w,h) in self._pil_shadow:
|
if (w,h) in self._pil_shadow:
|
||||||
return self._pil_shadow[(w,h)]
|
return self._pil_shadow[(w,h)]
|
||||||
|
|
|
@ -76,7 +76,7 @@ def init():
|
||||||
if settings.TOOLKIT == 'tk':
|
if settings.TOOLKIT == 'tk':
|
||||||
import Tkinter
|
import Tkinter
|
||||||
from Tkinter import TclError
|
from Tkinter import TclError
|
||||||
root = Tkinter.Tk()
|
root = Tkinter.Tk(className='PySol')
|
||||||
settings.WIN_SYSTEM = root.tk.call('tk', 'windowingsystem')
|
settings.WIN_SYSTEM = root.tk.call('tk', 'windowingsystem')
|
||||||
if settings.WIN_SYSTEM == 'aqua':
|
if settings.WIN_SYSTEM == 'aqua':
|
||||||
# TkAqua displays the console automatically in application
|
# TkAqua displays the console automatically in application
|
||||||
|
@ -97,7 +97,35 @@ def init():
|
||||||
# "can't invoke event <<ThemeChanged>>: application has been destroyed"
|
# "can't invoke event <<ThemeChanged>>: application has been destroyed"
|
||||||
#root.destroy()
|
#root.destroy()
|
||||||
Tkinter._default_root = None
|
Tkinter._default_root = None
|
||||||
#
|
|
||||||
|
# check FreeCell-Solver
|
||||||
|
settings.USE_FREECELL_SOLVER = False
|
||||||
|
if os.name == 'nt':
|
||||||
|
if sys.path[0] and not os.path.isdir(sys.path[0]): # i.e. library.zip
|
||||||
|
d = os.path.dirname(sys.path[0])
|
||||||
|
##d = os.path.join(d, 'freecell-solver')
|
||||||
|
fcs_command = os.path.join('freecell-solver', 'fc-solve.exe')
|
||||||
|
##fcs_command = '"%s"' % fcs_command # quote command
|
||||||
|
settings.FCS_COMMAND = fcs_command
|
||||||
|
f = os.path.join(d, 'freecell-solver', 'presetrc')
|
||||||
|
os.environ['FREECELL_SOLVER_PRESETRC'] = f
|
||||||
|
os.chdir(d) # for read presets
|
||||||
|
##print >> file('/fcs.log', 'a'), d
|
||||||
|
##print >> file('/fcs.log', 'a'), f
|
||||||
|
if os.name in ('posix', 'nt'):
|
||||||
|
try:
|
||||||
|
pin, pout, perr = os.popen3(settings.FCS_COMMAND+' --help')
|
||||||
|
if pout.readline().startswith('fc-solve'):
|
||||||
|
settings.USE_FREECELL_SOLVER = True
|
||||||
|
del pin, pout, perr
|
||||||
|
if os.name == 'posix':
|
||||||
|
os.wait() # kill zombi
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
pass
|
||||||
|
os.environ['FREECELL_SOLVER_QUIET'] = '1'
|
||||||
|
|
||||||
|
# run app without games menus (more fast start)
|
||||||
if '--no-games-menu' in sys.argv:
|
if '--no-games-menu' in sys.argv:
|
||||||
sys.argv.remove('--no-games-menu')
|
sys.argv.remove('--no-games-menu')
|
||||||
settings.SELECT_GAME_MENU = False
|
settings.SELECT_GAME_MENU = False
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
import os, time, types
|
import os, time, types
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cPickle import Pickler, Unpickler, UnpicklingError
|
from cPickle import Pickler, Unpickler, UnpicklingError
|
||||||
|
@ -319,10 +320,10 @@ def unpickle(filename):
|
||||||
|
|
||||||
def openURL(url):
|
def openURL(url):
|
||||||
try:
|
try:
|
||||||
import webbrowser
|
|
||||||
webbrowser.open(url)
|
webbrowser.open(url)
|
||||||
return 1
|
except OSError: # raised on windows if link is unreadable
|
||||||
except ImportError: # FIXME
|
pass
|
||||||
|
except:
|
||||||
return 0
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
|
@ -79,25 +79,30 @@ class AMoveMove(AtomicMove):
|
||||||
self.shadow = shadow
|
self.shadow = shadow
|
||||||
|
|
||||||
# do the actual move
|
# do the actual move
|
||||||
def __doMove(self, game, ncards, from_stack, to_stack):
|
def _doMove(self, game, ncards, from_stack, to_stack):
|
||||||
if game.moves.state == game.S_PLAY:
|
if game.moves.state == game.S_PLAY:
|
||||||
assert to_stack.acceptsCards(from_stack, from_stack.cards[-ncards:])
|
assert to_stack.acceptsCards(from_stack, from_stack.cards[-ncards:])
|
||||||
|
frames = self.frames
|
||||||
|
if frames == -2 and game.moves.state not in (game.S_UNDO, game.S_REDO):
|
||||||
|
# don't use animation for drag-move
|
||||||
|
frames = 0
|
||||||
cards = from_stack.cards[-ncards:]
|
cards = from_stack.cards[-ncards:]
|
||||||
if self.frames != 0:
|
if frames != 0:
|
||||||
|
from_stack.unshadeStack()
|
||||||
x, y = to_stack.getPositionForNextCard()
|
x, y = to_stack.getPositionForNextCard()
|
||||||
game.animatedMoveTo(from_stack, to_stack, cards, x, y,
|
game.animatedMoveTo(from_stack, to_stack, cards, x, y,
|
||||||
frames=self.frames, shadow=self.shadow)
|
frames=frames, shadow=self.shadow)
|
||||||
for i in range(ncards):
|
for i in range(ncards):
|
||||||
from_stack.removeCard()
|
from_stack.removeCard()
|
||||||
for c in cards:
|
for c in cards:
|
||||||
to_stack.addCard(c)
|
to_stack.addCard(c)
|
||||||
|
|
||||||
def redo(self, game):
|
def redo(self, game):
|
||||||
self.__doMove(game, self.ncards, game.allstacks[self.from_stack_id],
|
self._doMove(game, self.ncards, game.allstacks[self.from_stack_id],
|
||||||
game.allstacks[self.to_stack_id])
|
game.allstacks[self.to_stack_id])
|
||||||
|
|
||||||
def undo(self, game):
|
def undo(self, game):
|
||||||
self.__doMove(game, self.ncards, game.allstacks[self.to_stack_id],
|
self._doMove(game, self.ncards, game.allstacks[self.to_stack_id],
|
||||||
game.allstacks[self.from_stack_id])
|
game.allstacks[self.from_stack_id])
|
||||||
|
|
||||||
def cmpForRedo(self, other):
|
def cmpForRedo(self, other):
|
||||||
|
@ -115,7 +120,26 @@ class AFlipMove(AtomicMove):
|
||||||
self.stack_id = stack.id
|
self.stack_id = stack.id
|
||||||
|
|
||||||
# do the actual move
|
# do the actual move
|
||||||
def __doMove(self, game, stack):
|
def _doMove(self, game, stack):
|
||||||
|
card = stack.cards[-1]
|
||||||
|
##game.animatedFlip(stack)
|
||||||
|
if card.face_up:
|
||||||
|
card.showBack()
|
||||||
|
else:
|
||||||
|
card.showFace()
|
||||||
|
|
||||||
|
def redo(self, game):
|
||||||
|
self._doMove(game, game.allstacks[self.stack_id])
|
||||||
|
|
||||||
|
def undo(self, game):
|
||||||
|
self._doMove(game, game.allstacks[self.stack_id])
|
||||||
|
|
||||||
|
def cmpForRedo(self, other):
|
||||||
|
return cmp(self.stack_id, other.stack_id)
|
||||||
|
|
||||||
|
# flip with animation
|
||||||
|
class ASingleFlipMove(AFlipMove):
|
||||||
|
def _doMove(self, game, stack):
|
||||||
card = stack.cards[-1]
|
card = stack.cards[-1]
|
||||||
game.animatedFlip(stack)
|
game.animatedFlip(stack)
|
||||||
if card.face_up:
|
if card.face_up:
|
||||||
|
@ -123,14 +147,46 @@ class AFlipMove(AtomicMove):
|
||||||
else:
|
else:
|
||||||
card.showFace()
|
card.showFace()
|
||||||
|
|
||||||
|
# flip and move one card
|
||||||
|
class AFlipAndMoveMove(AtomicMove):
|
||||||
|
|
||||||
|
def __init__(self, from_stack, to_stack, frames):
|
||||||
|
assert from_stack is not to_stack
|
||||||
|
self.from_stack_id = from_stack.id
|
||||||
|
self.to_stack_id = to_stack.id
|
||||||
|
self.frames = frames
|
||||||
|
|
||||||
|
def _doMove(self, game, from_stack, to_stack):
|
||||||
|
if game.moves.state == game.S_PLAY:
|
||||||
|
assert to_stack.acceptsCards(from_stack, from_stack.cards[-1])
|
||||||
|
if self.frames == 0:
|
||||||
|
moved = True
|
||||||
|
else:
|
||||||
|
moved = game.animatedFlipAndMove(from_stack, to_stack, self.frames)
|
||||||
|
c = from_stack.cards[-1]
|
||||||
|
if c.face_up:
|
||||||
|
c.showBack()
|
||||||
|
else:
|
||||||
|
c.showFace()
|
||||||
|
if not moved:
|
||||||
|
cards = from_stack.cards[-1:]
|
||||||
|
x, y = to_stack.getPositionForNextCard()
|
||||||
|
game.animatedMoveTo(from_stack, to_stack, cards, x, y,
|
||||||
|
frames=self.frames, shadow=0)
|
||||||
|
c = from_stack.removeCard()
|
||||||
|
to_stack.addCard(c)
|
||||||
|
|
||||||
def redo(self, game):
|
def redo(self, game):
|
||||||
self.__doMove(game, game.allstacks[self.stack_id])
|
self._doMove(game, game.allstacks[self.from_stack_id],
|
||||||
|
game.allstacks[self.to_stack_id])
|
||||||
|
|
||||||
def undo(self, game):
|
def undo(self, game):
|
||||||
self.__doMove(game, game.allstacks[self.stack_id])
|
self._doMove(game, game.allstacks[self.to_stack_id],
|
||||||
|
game.allstacks[self.from_stack_id])
|
||||||
|
|
||||||
def cmpForRedo(self, other):
|
def cmpForRedo(self, other):
|
||||||
return cmp(self.stack_id, other.stack_id)
|
return (cmp(self.from_stack_id, other.from_stack_id) or
|
||||||
|
cmp(self.to_stack_id, other.to_stack_id))
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -246,7 +302,7 @@ class NEW_ATurnStackMove(AtomicMove):
|
||||||
self.update_flags = update_flags
|
self.update_flags = update_flags
|
||||||
|
|
||||||
# do the actual turning move
|
# do the actual turning move
|
||||||
def __doMove(self, from_stack, to_stack, show_face):
|
def _doMove(self, from_stack, to_stack, show_face):
|
||||||
assert len(from_stack.cards) > 0
|
assert len(from_stack.cards) > 0
|
||||||
assert len(to_stack.cards) == 0
|
assert len(to_stack.cards) == 0
|
||||||
for card in from_stack.cards:
|
for card in from_stack.cards:
|
||||||
|
@ -272,7 +328,7 @@ class NEW_ATurnStackMove(AtomicMove):
|
||||||
assert to_stack is game.s.talon
|
assert to_stack is game.s.talon
|
||||||
assert to_stack.round < to_stack.max_rounds or to_stack.max_rounds < 0
|
assert to_stack.round < to_stack.max_rounds or to_stack.max_rounds < 0
|
||||||
to_stack.round = to_stack.round + 1
|
to_stack.round = to_stack.round + 1
|
||||||
self.__doMove(from_stack, to_stack, 0)
|
self._doMove(from_stack, to_stack, 0)
|
||||||
|
|
||||||
def undo(self, game):
|
def undo(self, game):
|
||||||
from_stack = game.allstacks[self.from_stack_id]
|
from_stack = game.allstacks[self.from_stack_id]
|
||||||
|
@ -281,7 +337,7 @@ class NEW_ATurnStackMove(AtomicMove):
|
||||||
assert to_stack is game.s.talon
|
assert to_stack is game.s.talon
|
||||||
assert to_stack.round > 1
|
assert to_stack.round > 1
|
||||||
to_stack.round = to_stack.round - 1
|
to_stack.round = to_stack.round - 1
|
||||||
self.__doMove(to_stack, from_stack, 1)
|
self._doMove(to_stack, from_stack, 1)
|
||||||
|
|
||||||
def cmpForRedo(self, other):
|
def cmpForRedo(self, other):
|
||||||
return (cmp(self.from_stack_id, other.from_stack_id) or
|
return (cmp(self.from_stack_id, other.from_stack_id) or
|
||||||
|
@ -300,7 +356,7 @@ class AUpdateStackMove(AtomicMove):
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
|
|
||||||
# do the actual move
|
# do the actual move
|
||||||
def __doMove(self, game, stack, undo):
|
def _doMove(self, game, stack, undo):
|
||||||
if self.flags & 64:
|
if self.flags & 64:
|
||||||
# model
|
# model
|
||||||
stack.updateModel(undo, self.flags)
|
stack.updateModel(undo, self.flags)
|
||||||
|
@ -313,11 +369,11 @@ class AUpdateStackMove(AtomicMove):
|
||||||
|
|
||||||
def redo(self, game):
|
def redo(self, game):
|
||||||
if (self.flags & 3) in (1, 3):
|
if (self.flags & 3) in (1, 3):
|
||||||
self.__doMove(game, game.allstacks[self.stack_id], 0)
|
self._doMove(game, game.allstacks[self.stack_id], 0)
|
||||||
|
|
||||||
def undo(self, game):
|
def undo(self, game):
|
||||||
if (self.flags & 3) in (2, 3):
|
if (self.flags & 3) in (2, 3):
|
||||||
self.__doMove(game, game.allstacks[self.stack_id], 1)
|
self._doMove(game, game.allstacks[self.stack_id], 1)
|
||||||
|
|
||||||
def cmpForRedo(self, other):
|
def cmpForRedo(self, other):
|
||||||
return cmp(self.stack_id, other.stack_id) or cmp(self.flags, other.flags)
|
return cmp(self.stack_id, other.stack_id) or cmp(self.flags, other.flags)
|
||||||
|
|
|
@ -59,8 +59,6 @@ class ColorsDialog:
|
||||||
self._setColor(n, app.opt.colors[n])
|
self._setColor(n, app.opt.colors[n])
|
||||||
button = self.widgets_tree.get_widget(n+'_button')
|
button = self.widgets_tree.get_widget(n+'_button')
|
||||||
button.connect('clicked', self._changeColor, n)
|
button.connect('clicked', self._changeColor, n)
|
||||||
checkbutton = self.widgets_tree.get_widget('use_default_checkbutton')
|
|
||||||
checkbutton.set_active(not app.opt.use_default_text_color)
|
|
||||||
|
|
||||||
self._translateLabels()
|
self._translateLabels()
|
||||||
|
|
||||||
|
@ -79,7 +77,6 @@ class ColorsDialog:
|
||||||
w = self.widgets_tree.get_widget(n+'_label')
|
w = self.widgets_tree.get_widget(n+'_label')
|
||||||
c = w.get_data('user_data')
|
c = w.get_data('user_data')
|
||||||
setattr(self, n+'_color', c)
|
setattr(self, n+'_color', c)
|
||||||
self.use_default_color = not checkbutton.get_active()
|
|
||||||
|
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
||||||
|
@ -125,9 +122,8 @@ class ColorsDialog:
|
||||||
'label51',
|
'label51',
|
||||||
'label52',
|
'label52',
|
||||||
'label53',
|
'label53',
|
||||||
|
'label79',
|
||||||
):
|
):
|
||||||
w = self.widgets_tree.get_widget(n)
|
w = self.widgets_tree.get_widget(n)
|
||||||
w.set_text(gettext(w.get_text()))
|
w.set_text(gettext(w.get_text()))
|
||||||
w = self.widgets_tree.get_widget('use_default_checkbutton')
|
|
||||||
w.set_label(gettext(w.get_label()))
|
|
||||||
|
|
||||||
|
|
|
@ -289,10 +289,11 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
#
|
#
|
||||||
animations_entries = (
|
animations_entries = (
|
||||||
('animationnone', None, ltk2gtk('&None'), None, None, 0),
|
('animationnone', None, ltk2gtk('&None'), None, None, 0),
|
||||||
('animationfast', None, ltk2gtk('&Fast'), None, None, 1),
|
('animationveryfast', None, ltk2gtk('&Very fast'), None, None, 1),
|
||||||
('animationtimer', None, ltk2gtk('&Timer based'), None, None, 2),
|
('animationfast', None, ltk2gtk('&Fast'), None, None, 2),
|
||||||
('animationslow', None, ltk2gtk('&Slow'), None, None, 3),
|
('animationmedium', None, ltk2gtk('&Medium'), None, None, 3),
|
||||||
('animationveryslow', None, ltk2gtk('&Very slow'), None, None, 4),
|
('animationslow', None, ltk2gtk('&Slow'), None, None, 4),
|
||||||
|
('animationveryslow', None, ltk2gtk('V&ery slow'), None, None, 5),
|
||||||
)
|
)
|
||||||
mouse_entries = (
|
mouse_entries = (
|
||||||
('draganddrop', None, ltk2gtk('&Drag-and-Drop'), None, None, 0),
|
('draganddrop', None, ltk2gtk('&Drag-and-Drop'), None, None, 0),
|
||||||
|
@ -388,8 +389,9 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
<menuitem action='tabletile'/>
|
<menuitem action='tabletile'/>
|
||||||
<menu action='animations'>
|
<menu action='animations'>
|
||||||
<menuitem action='animationnone'/>
|
<menuitem action='animationnone'/>
|
||||||
<menuitem action='animationtimer'/>
|
<menuitem action='animationveryfast'/>
|
||||||
<menuitem action='animationfast'/>
|
<menuitem action='animationfast'/>
|
||||||
|
<menuitem action='animationmedium'/>
|
||||||
<menuitem action='animationslow'/>
|
<menuitem action='animationslow'/>
|
||||||
<menuitem action='animationveryslow'/>
|
<menuitem action='animationveryslow'/>
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -831,7 +833,6 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
self._cancelDrag()
|
self._cancelDrag()
|
||||||
self.game.endGame(bookmark=1)
|
self.game.endGame(bookmark=1)
|
||||||
self.game.quitGame(bookmark=1)
|
self.game.quitGame(bookmark=1)
|
||||||
self.app.opt.games_geometry = {} # clear saved games geometry
|
|
||||||
|
|
||||||
|
|
||||||
def mOptToggle(self, w, opt_name, update_game):
|
def mOptToggle(self, w, opt_name, update_game):
|
||||||
|
|
|
@ -389,7 +389,7 @@ class SelectGameDialogWithPreview(MfxDialog):
|
||||||
destruct(self.preview_app)
|
destruct(self.preview_app)
|
||||||
self.preview_app = None
|
self.preview_app = None
|
||||||
|
|
||||||
def updatePreview(self, gameid, animations=5):
|
def updatePreview(self, gameid, animations=10):
|
||||||
if gameid == self.preview_key:
|
if gameid == self.preview_key:
|
||||||
return
|
return
|
||||||
self.deletePreview()
|
self.deletePreview()
|
||||||
|
@ -456,7 +456,7 @@ class SelectGameDialogWithPreview(MfxDialog):
|
||||||
#
|
#
|
||||||
self.preview_app.audio = self.app.audio
|
self.preview_app.audio = self.app.audio
|
||||||
if self.app.opt.animations:
|
if self.app.opt.animations:
|
||||||
self.preview_app.opt.animations = 5
|
self.preview_app.opt.animations = 10
|
||||||
else:
|
else:
|
||||||
self.preview_app.opt.animations = 0
|
self.preview_app.opt.animations = 0
|
||||||
# save seed
|
# save seed
|
||||||
|
@ -514,14 +514,13 @@ class SelectGameDialogWithPreview(MfxDialog):
|
||||||
('percent', percent),
|
('percent', percent),
|
||||||
):
|
):
|
||||||
title_label, text_label = self.info_labels[n]
|
title_label, text_label = self.info_labels[n]
|
||||||
if t == '':
|
if t in ('', None):
|
||||||
title_label.hide()
|
title_label.hide()
|
||||||
text_label.hide()
|
text_label.hide()
|
||||||
else:
|
else:
|
||||||
title_label.show()
|
title_label.show()
|
||||||
text_label.show()
|
text_label.show()
|
||||||
text_label.set_text(str(t))
|
text_label.set_text(str(t))
|
||||||
#self.info_labels[n].config(text=t)
|
|
||||||
|
|
||||||
def done(self, button):
|
def done(self, button):
|
||||||
button = button.get_data("user_data")
|
button = button.get_data("user_data")
|
||||||
|
|
42
pysollib/pysolgtk/solverdialog.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
##
|
||||||
|
## PySol -- a Python Solitaire game
|
||||||
|
##
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with this program; see the file COPYING.
|
||||||
|
## If not, write to the Free Software Foundation, Inc.,
|
||||||
|
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
##
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
#'SolverDialog',
|
||||||
|
'create_solver_dialog',
|
||||||
|
'connect_game_solver_dialog',
|
||||||
|
'destroy_solver_dialog',
|
||||||
|
'reset_solver_dialog',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
solver_dialog = None
|
||||||
|
|
||||||
|
def create_solver_dialog(parent, game):
|
||||||
|
pass
|
||||||
|
def connect_game_solver_dialog(game):
|
||||||
|
pass
|
||||||
|
def destroy_solver_dialog():
|
||||||
|
pass
|
||||||
|
solver_dialog = None
|
||||||
|
def reset_solver_dialog():
|
||||||
|
pass
|
||||||
|
|
|
@ -445,15 +445,10 @@ class MfxCanvas(gnomecanvas.Canvas):
|
||||||
self.setBackgroundImage(None)
|
self.setBackgroundImage(None)
|
||||||
self.configure(bg=tile.color)
|
self.configure(bg=tile.color)
|
||||||
##app.top.config(bg=tile.color)
|
##app.top.config(bg=tile.color)
|
||||||
color = None
|
|
||||||
else:
|
else:
|
||||||
self._setTile()
|
self._setTile()
|
||||||
self.configure(bg=self.top_bg)
|
self.configure(bg=self.top_bg)
|
||||||
color = tile.text_color
|
|
||||||
|
|
||||||
if app.opt.use_default_text_color:
|
|
||||||
self.setTextColor(color)
|
|
||||||
else:
|
|
||||||
self.setTextColor(app.opt.colors['text'])
|
self.setTextColor(app.opt.colors['text'])
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -566,7 +566,9 @@ class Status_StatsDialog(MfxMessageDialog): #MfxDialog
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressionDialog:
|
||||||
|
# FIXME
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ if TOOLKIT == 'tk':
|
||||||
from tile.colorsdialog import *
|
from tile.colorsdialog import *
|
||||||
from tile.fontsdialog import *
|
from tile.fontsdialog import *
|
||||||
from tile.findcarddialog import *
|
from tile.findcarddialog import *
|
||||||
|
from tile.solverdialog import *
|
||||||
from tile.gameinfodialog import *
|
from tile.gameinfodialog import *
|
||||||
from tile.toolbar import *
|
from tile.toolbar import *
|
||||||
from tile.statusbar import *
|
from tile.statusbar import *
|
||||||
|
@ -60,6 +61,7 @@ if TOOLKIT == 'tk':
|
||||||
from tk.colorsdialog import *
|
from tk.colorsdialog import *
|
||||||
from tk.fontsdialog import *
|
from tk.fontsdialog import *
|
||||||
from tk.findcarddialog import *
|
from tk.findcarddialog import *
|
||||||
|
from tk.solverdialog import *
|
||||||
from tk.gameinfodialog import *
|
from tk.gameinfodialog import *
|
||||||
from tk.toolbar import *
|
from tk.toolbar import *
|
||||||
from tk.statusbar import *
|
from tk.statusbar import *
|
||||||
|
@ -84,6 +86,7 @@ else: # gtk
|
||||||
from pysolgtk.colorsdialog import *
|
from pysolgtk.colorsdialog import *
|
||||||
from pysolgtk.fontsdialog import *
|
from pysolgtk.fontsdialog import *
|
||||||
from pysolgtk.findcarddialog import *
|
from pysolgtk.findcarddialog import *
|
||||||
|
from pysolgtk.solverdialog import *
|
||||||
from pysolgtk.gameinfodialog import *
|
from pysolgtk.gameinfodialog import *
|
||||||
from pysolgtk.toolbar import *
|
from pysolgtk.toolbar import *
|
||||||
from pysolgtk.statusbar import *
|
from pysolgtk.statusbar import *
|
||||||
|
|
|
@ -497,7 +497,6 @@ class CardsetManager(ResourceManager):
|
||||||
class Tile(Resource):
|
class Tile(Resource):
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
kw['color'] = None
|
kw['color'] = None
|
||||||
kw['text_color'] = "#000000"
|
|
||||||
kw['stretch'] = 0
|
kw['stretch'] = 0
|
||||||
Resource.__init__(self, **kw)
|
Resource.__init__(self, **kw)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ PACKAGE = 'PySol'
|
||||||
PACKAGE_URL = 'http://sourceforge.net/projects/pysolfc/'
|
PACKAGE_URL = 'http://sourceforge.net/projects/pysolfc/'
|
||||||
|
|
||||||
VERSION = '4.82'
|
VERSION = '4.82'
|
||||||
FC_VERSION = '0.9.5'
|
FC_VERSION = '1.0'
|
||||||
VERSION_TUPLE = (4, 82)
|
VERSION_TUPLE = (4, 82)
|
||||||
|
|
||||||
# Tk windowing system (auto determine in init.py)
|
# Tk windowing system (auto determine in init.py)
|
||||||
|
@ -48,6 +48,11 @@ USE_TILE = 'auto' # or True or False
|
||||||
# 'none' - disable
|
# 'none' - disable
|
||||||
SOUND_MOD = 'auto'
|
SOUND_MOD = 'auto'
|
||||||
|
|
||||||
|
# freecell-solver
|
||||||
|
USE_FREECELL_SOLVER = True
|
||||||
|
FCS_COMMAND = 'fc-solve'
|
||||||
|
##FCS_HOME = None # path to fcs presets files
|
||||||
|
|
||||||
# data dirs
|
# data dirs
|
||||||
DATA_DIRS = []
|
DATA_DIRS = []
|
||||||
# you can add your extra directories here
|
# you can add your extra directories here
|
||||||
|
|
|
@ -57,7 +57,7 @@ __all__ = ['cardsFaceUp',
|
||||||
'SS_FoundationStack',
|
'SS_FoundationStack',
|
||||||
'RK_FoundationStack',
|
'RK_FoundationStack',
|
||||||
'AC_FoundationStack',
|
'AC_FoundationStack',
|
||||||
'SequenceStack_StackMethods',
|
#'SequenceStack_StackMethods',
|
||||||
'BasicRowStack',
|
'BasicRowStack',
|
||||||
'SequenceRowStack',
|
'SequenceRowStack',
|
||||||
'AC_RowStack',
|
'AC_RowStack',
|
||||||
|
@ -71,6 +71,7 @@ __all__ = ['cardsFaceUp',
|
||||||
'UD_RK_RowStack',
|
'UD_RK_RowStack',
|
||||||
'FreeCell_AC_RowStack',
|
'FreeCell_AC_RowStack',
|
||||||
'FreeCell_SS_RowStack',
|
'FreeCell_SS_RowStack',
|
||||||
|
'FreeCell_RK_RowStack',
|
||||||
'Spider_AC_RowStack',
|
'Spider_AC_RowStack',
|
||||||
'Spider_SS_RowStack',
|
'Spider_SS_RowStack',
|
||||||
'Yukon_AC_RowStack',
|
'Yukon_AC_RowStack',
|
||||||
|
@ -83,6 +84,10 @@ __all__ = ['cardsFaceUp',
|
||||||
'FaceUpWasteTalonStack',
|
'FaceUpWasteTalonStack',
|
||||||
'OpenTalonStack',
|
'OpenTalonStack',
|
||||||
'ReserveStack',
|
'ReserveStack',
|
||||||
|
'SuperMoveStack_StackMethods',
|
||||||
|
'SuperMoveSS_RowStack',
|
||||||
|
'SuperMoveAC_RowStack',
|
||||||
|
'SuperMoveRK_RowStack',
|
||||||
'InvisibleStack',
|
'InvisibleStack',
|
||||||
'StackWrapper',
|
'StackWrapper',
|
||||||
'WeakStackWrapper',
|
'WeakStackWrapper',
|
||||||
|
@ -342,6 +347,7 @@ class Stack:
|
||||||
bind(group, "<3>", self.__rightclickEventHandler)
|
bind(group, "<3>", self.__rightclickEventHandler)
|
||||||
bind(group, "<2>", self.__middleclickEventHandler)
|
bind(group, "<2>", self.__middleclickEventHandler)
|
||||||
bind(group, "<Control-3>", self.__middleclickEventHandler)
|
bind(group, "<Control-3>", self.__middleclickEventHandler)
|
||||||
|
##bind(group, "<Control-2>", self.__controlmiddleclickEventHandler)
|
||||||
##bind(group, "<Shift-3>", self.__shiftrightclickEventHandler)
|
##bind(group, "<Shift-3>", self.__shiftrightclickEventHandler)
|
||||||
##bind(group, "<Double-2>", "")
|
##bind(group, "<Double-2>", "")
|
||||||
bind(group, "<Enter>", self.__enterEventHandler)
|
bind(group, "<Enter>", self.__enterEventHandler)
|
||||||
|
@ -489,8 +495,7 @@ class Stack:
|
||||||
|
|
||||||
if update:
|
if update:
|
||||||
view.updateText()
|
view.updateText()
|
||||||
if self.is_filled:
|
self.unshadeStack()
|
||||||
self._unshadeStack()
|
|
||||||
self.is_filled = False
|
self.is_filled = False
|
||||||
return card
|
return card
|
||||||
|
|
||||||
|
@ -652,8 +657,11 @@ class Stack:
|
||||||
# Atomic move actions {model -> view}
|
# Atomic move actions {model -> view}
|
||||||
#
|
#
|
||||||
|
|
||||||
def flipMove(self):
|
def flipMove(self, animation=False):
|
||||||
# Flip the top card.
|
# Flip the top card.
|
||||||
|
if animation:
|
||||||
|
self.game.singleFlipMove(self)
|
||||||
|
else:
|
||||||
self.game.flipMove(self)
|
self.game.flipMove(self)
|
||||||
|
|
||||||
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
|
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
|
||||||
|
@ -671,10 +679,10 @@ class Stack:
|
||||||
# Playing move actions. Better not override.
|
# Playing move actions. Better not override.
|
||||||
#
|
#
|
||||||
|
|
||||||
def playFlipMove(self, sound=1):
|
def playFlipMove(self, sound=1, animation=False):
|
||||||
if sound:
|
if sound:
|
||||||
self.game.playSample("flip", 5)
|
self.game.playSample("flip", 5)
|
||||||
self.flipMove()
|
self.flipMove(animation=animation)
|
||||||
if not self.game.checkForWin():
|
if not self.game.checkForWin():
|
||||||
self.game.autoPlay()
|
self.game.autoPlay()
|
||||||
self.game.finishMove()
|
self.game.finishMove()
|
||||||
|
@ -917,6 +925,32 @@ class Stack:
|
||||||
self.game.canvas.update_idletasks()
|
self.game.canvas.update_idletasks()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def controlmiddleclickHandler(self, event):
|
||||||
|
# cheating: show face-down card
|
||||||
|
if not self.is_open:
|
||||||
|
return 0
|
||||||
|
i = self._findCard(event)
|
||||||
|
positions = len(self.cards) - i - 1
|
||||||
|
if i < 0 or positions < 0:
|
||||||
|
return 0
|
||||||
|
##print self.cards[i]
|
||||||
|
face_up = self.cards[i].face_up
|
||||||
|
if not face_up:
|
||||||
|
self.cards[i].showFace()
|
||||||
|
self.cards[i].item.tkraise()
|
||||||
|
self.game.canvas.update_idletasks()
|
||||||
|
self.game.sleep(self.game.app.opt.timeouts['raise_card'])
|
||||||
|
if not face_up:
|
||||||
|
self.cards[i].showBack()
|
||||||
|
if TOOLKIT == 'tk':
|
||||||
|
if positions > 0:
|
||||||
|
self.cards[i].item.lower(self.cards[i+1].item)
|
||||||
|
elif TOOLKIT == 'gtk':
|
||||||
|
for c in self.cards[i+1:]:
|
||||||
|
c.tkraise()
|
||||||
|
self.game.canvas.update_idletasks()
|
||||||
|
return 1
|
||||||
|
|
||||||
def rightclickHandler(self, event):
|
def rightclickHandler(self, event):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -946,8 +980,25 @@ class Stack:
|
||||||
self.moveCardsBackHandler(event, drag)
|
self.moveCardsBackHandler(event, drag)
|
||||||
|
|
||||||
def moveCardsBackHandler(self, event, drag):
|
def moveCardsBackHandler(self, event, drag):
|
||||||
|
if self.game.app.opt.animations:
|
||||||
|
if drag.cards:
|
||||||
|
c = drag.cards[0]
|
||||||
|
x0, y0 = drag.stack.getPositionFor(c)
|
||||||
|
x1, y1 = c.x, c.y
|
||||||
|
dx, dy = abs(x0-x1), abs(y0-y1)
|
||||||
|
w = self.game.app.images.CARDW
|
||||||
|
h = self.game.app.images.CARDH
|
||||||
|
if dx > 2*w or dy > 2*h:
|
||||||
|
self.game.animatedMoveTo(drag.stack, drag.stack,
|
||||||
|
drag.cards, x0, y0, frames=-1)
|
||||||
|
elif dx > w or dy > h:
|
||||||
|
self.game.animatedMoveTo(drag.stack, drag.stack,
|
||||||
|
drag.cards, x0, y0, frames=4)
|
||||||
for card in drag.cards:
|
for card in drag.cards:
|
||||||
self._position(card)
|
self._position(card)
|
||||||
|
if self.is_filled and self.items.shade_item:
|
||||||
|
self.items.shade_item.show()
|
||||||
|
self.items.shade_item.tkraise()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -993,6 +1044,9 @@ class Stack:
|
||||||
def __middleclickEventHandler(self, event):
|
def __middleclickEventHandler(self, event):
|
||||||
return self.__defaultClickEventHandler(event, self.middleclickHandler)
|
return self.__defaultClickEventHandler(event, self.middleclickHandler)
|
||||||
|
|
||||||
|
def __controlmiddleclickEventHandler(self, event):
|
||||||
|
return self.__defaultClickEventHandler(event, self.controlmiddleclickHandler)
|
||||||
|
|
||||||
def __rightclickEventHandler(self, event):
|
def __rightclickEventHandler(self, event):
|
||||||
return self.__defaultClickEventHandler(event, self.rightclickHandler)
|
return self.__defaultClickEventHandler(event, self.rightclickHandler)
|
||||||
|
|
||||||
|
@ -1049,8 +1103,11 @@ class Stack:
|
||||||
self.current_cursor = CURSOR_DOWN_ARROW
|
self.current_cursor = CURSOR_DOWN_ARROW
|
||||||
self.cursor_changed = True
|
self.cursor_changed = True
|
||||||
else:
|
else:
|
||||||
|
help = self.getHelp() ##+' '+self.getBaseCard(),
|
||||||
|
if DEBUG >= 5:
|
||||||
|
help = repr(self)
|
||||||
after_idle(self.canvas, self.game.showHelp,
|
after_idle(self.canvas, self.game.showHelp,
|
||||||
'help', self.getHelp(), ##+' '+self.getBaseCard(),
|
'help', help,
|
||||||
'info', self.getNumCards())
|
'info', self.getNumCards())
|
||||||
return EVENT_HANDLED
|
return EVENT_HANDLED
|
||||||
|
|
||||||
|
@ -1173,7 +1230,7 @@ class Stack:
|
||||||
images = self.game.app.images
|
images = self.game.app.images
|
||||||
cx, cy = cards[0].x, cards[0].y
|
cx, cy = cards[0].x, cards[0].y
|
||||||
ddx, ddy = cx-cards[-1].x, cy-cards[-1].y
|
ddx, ddy = cx-cards[-1].x, cy-cards[-1].y
|
||||||
if TOOLKIT == 'tk' and Image: # use PIL
|
if 0 and TOOLKIT == 'tk' and Image: # use PIL
|
||||||
c0 = cards[-1]
|
c0 = cards[-1]
|
||||||
if self.CARD_XOFFSET[0] < 0: c0 = cards[0]
|
if self.CARD_XOFFSET[0] < 0: c0 = cards[0]
|
||||||
if self.CARD_YOFFSET[0] < 0: c0 = cards[0]
|
if self.CARD_YOFFSET[0] < 0: c0 = cards[0]
|
||||||
|
@ -1303,7 +1360,7 @@ class Stack:
|
||||||
#item.tkraise()
|
#item.tkraise()
|
||||||
self.items.shade_item = item
|
self.items.shade_item = item
|
||||||
|
|
||||||
def _unshadeStack(self):
|
def unshadeStack(self):
|
||||||
if self.items.shade_item:
|
if self.items.shade_item:
|
||||||
self.items.shade_item.delete()
|
self.items.shade_item.delete()
|
||||||
self.items.shade_item = None
|
self.items.shade_item = None
|
||||||
|
@ -1350,19 +1407,19 @@ class Stack:
|
||||||
group=self.group)
|
group=self.group)
|
||||||
drag.shadows.append(im)
|
drag.shadows.append(im)
|
||||||
|
|
||||||
def _setMotionCursor(self, event):
|
## def _setMotionCursor(self, event):
|
||||||
if not event:
|
## if not event:
|
||||||
return
|
## return
|
||||||
self.cursor_changed = True
|
## self.cursor_changed = True
|
||||||
i = self._findCard(event)
|
## i = self._findCard(event)
|
||||||
if i < 0 or not self.canMoveCards(self.cards[i:]):
|
## if i < 0 or not self.canMoveCards(self.cards[i:]):
|
||||||
if self.current_cursor != CURSOR_NO_MOVE:
|
## if self.current_cursor != CURSOR_NO_MOVE:
|
||||||
self.game.canvas.config(cursor=CURSOR_NO_MOVE)
|
## self.game.canvas.config(cursor=CURSOR_NO_MOVE)
|
||||||
self.current_cursor = CURSOR_NO_MOVE
|
## self.current_cursor = CURSOR_NO_MOVE
|
||||||
else:
|
## else:
|
||||||
if self.current_cursor != CURSOR_CAN_MOVE:
|
## if self.current_cursor != CURSOR_CAN_MOVE:
|
||||||
self.game.canvas.config(cursor=CURSOR_CAN_MOVE)
|
## self.game.canvas.config(cursor=CURSOR_CAN_MOVE)
|
||||||
self.current_cursor = CURSOR_CAN_MOVE
|
## self.current_cursor = CURSOR_CAN_MOVE
|
||||||
|
|
||||||
def _stopDrag(self):
|
def _stopDrag(self):
|
||||||
drag = self.game.drag
|
drag = self.game.drag
|
||||||
|
@ -1376,15 +1433,15 @@ class Stack:
|
||||||
drag.shadows = []
|
drag.shadows = []
|
||||||
drag.stack = None
|
drag.stack = None
|
||||||
drag.cards = []
|
drag.cards = []
|
||||||
if self.is_filled and self.items.shade_item:
|
|
||||||
self.items.shade_item.show()
|
|
||||||
self.items.shade_item.tkraise()
|
|
||||||
|
|
||||||
# finish a drag operation
|
# finish a drag operation
|
||||||
def finishDrag(self, event=None):
|
def finishDrag(self, event=None):
|
||||||
if self.game.app.opt.dragcursor:
|
if self.game.app.opt.dragcursor:
|
||||||
self.game.canvas.config(cursor='')
|
self.game.canvas.config(cursor='')
|
||||||
drag = self.game.drag.copy()
|
drag = self.game.drag.copy()
|
||||||
|
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||||
|
drag.stack._stopDrag()
|
||||||
|
else:
|
||||||
self._stopDrag()
|
self._stopDrag()
|
||||||
if drag.cards:
|
if drag.cards:
|
||||||
if self.game.app.opt.mouse_type == 'point-n-click':
|
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||||
|
@ -1398,6 +1455,9 @@ class Stack:
|
||||||
if self.game.app.opt.dragcursor:
|
if self.game.app.opt.dragcursor:
|
||||||
self.game.canvas.config(cursor='')
|
self.game.canvas.config(cursor='')
|
||||||
drag = self.game.drag.copy()
|
drag = self.game.drag.copy()
|
||||||
|
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||||
|
drag.stack._stopDrag()
|
||||||
|
else:
|
||||||
self._stopDrag()
|
self._stopDrag()
|
||||||
if drag.cards:
|
if drag.cards:
|
||||||
assert drag.stack is self
|
assert drag.stack is self
|
||||||
|
@ -1410,6 +1470,7 @@ class Stack:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _getBaseCard(self):
|
def _getBaseCard(self):
|
||||||
|
# FIXME: no-french games
|
||||||
if self.cap.max_accept == 0:
|
if self.cap.max_accept == 0:
|
||||||
return ''
|
return ''
|
||||||
br = self.cap.base_rank
|
br = self.cap.base_rank
|
||||||
|
@ -1424,14 +1485,10 @@ class Stack:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def getNumCards(self):
|
def getNumCards(self):
|
||||||
if DEBUG >= 5:
|
|
||||||
t = repr(self)+' '
|
|
||||||
else:
|
|
||||||
t = ''
|
|
||||||
n = len(self.cards)
|
n = len(self.cards)
|
||||||
if n == 0 : return t+_('No cards')
|
if n == 0 : return _('No cards')
|
||||||
elif n == 1 : return t+_('1 card')
|
elif n == 1 : return _('1 card')
|
||||||
else : return t+str(n)+_(' cards')
|
else : return str(n)+_(' cards')
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -1831,8 +1888,9 @@ class OpenStack(Stack):
|
||||||
def clickHandler(self, event):
|
def clickHandler(self, event):
|
||||||
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
||||||
if self in flipstacks and self.canFlipCard():
|
if self in flipstacks and self.canFlipCard():
|
||||||
self.playFlipMove()
|
self.playFlipMove(animation=True)
|
||||||
return -1 # continue this event (start a drag)
|
##return -1 # continue this event (start a drag)
|
||||||
|
return 1 # break
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def rightclickHandler(self, event):
|
def rightclickHandler(self, event):
|
||||||
|
@ -1850,7 +1908,7 @@ class OpenStack(Stack):
|
||||||
# flip or drop a card
|
# flip or drop a card
|
||||||
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
||||||
if self in flipstacks and self.canFlipCard():
|
if self in flipstacks and self.canFlipCard():
|
||||||
self.playFlipMove()
|
self.playFlipMove(animation=True)
|
||||||
return -1 # continue this event (start a drag)
|
return -1 # continue this event (start a drag)
|
||||||
if self in dropstacks:
|
if self in dropstacks:
|
||||||
to_stack, ncards = self.canDropCards(self.game.s.foundations)
|
to_stack, ncards = self.canDropCards(self.game.s.foundations)
|
||||||
|
@ -1870,7 +1928,8 @@ class OpenStack(Stack):
|
||||||
if self.game.app.opt.mouse_type == 'point-n-click':
|
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||||
self.playMoveMove(len(drag.cards), stack, sound=sound)
|
self.playMoveMove(len(drag.cards), stack, sound=sound)
|
||||||
else:
|
else:
|
||||||
self.playMoveMove(len(drag.cards), stack, frames=0, sound=sound)
|
#self.playMoveMove(len(drag.cards), stack, frames=0, sound=sound)
|
||||||
|
self.playMoveMove(len(drag.cards), stack, frames=-2, sound=sound)
|
||||||
|
|
||||||
def releaseHandler(self, event, drag, sound=1):
|
def releaseHandler(self, event, drag, sound=1):
|
||||||
cards = drag.cards
|
cards = drag.cards
|
||||||
|
@ -2168,6 +2227,12 @@ class FreeCell_SS_RowStack(SS_RowStack):
|
||||||
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
|
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
|
||||||
return len(cards) <= max_move and SS_RowStack.canMoveCards(self, cards)
|
return len(cards) <= max_move and SS_RowStack.canMoveCards(self, cards)
|
||||||
|
|
||||||
|
# A Freecell_Rank_RowStack
|
||||||
|
class FreeCell_RK_RowStack(RK_RowStack):
|
||||||
|
def canMoveCards(self, cards):
|
||||||
|
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
|
||||||
|
return len(cards) <= max_move and RK_RowStack.canMoveCards(self, cards)
|
||||||
|
|
||||||
# A Spider_AlternateColor_RowStack builds down by rank and alternate color,
|
# A Spider_AlternateColor_RowStack builds down by rank and alternate color,
|
||||||
# but accepts sequences that match by rank only.
|
# but accepts sequences that match by rank only.
|
||||||
class Spider_AC_RowStack(AC_RowStack):
|
class Spider_AC_RowStack(AC_RowStack):
|
||||||
|
@ -2291,6 +2356,73 @@ class UD_RK_RowStack(SequenceRowStack):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# To simplify playing we also consider the number of free rows.
|
||||||
|
# Note that this only is legal if the game.s.rows have a
|
||||||
|
# cap.base_rank == ANY_RANK.
|
||||||
|
# See also the "SuperMove" section in the FreeCell FAQ.
|
||||||
|
class SuperMoveStack_StackMethods:
|
||||||
|
def _getMaxMove(self, to_stack_ncards):
|
||||||
|
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
|
||||||
|
if self.cap.base_rank != ANY_RANK:
|
||||||
|
return max_move
|
||||||
|
n = getNumberOfFreeStacks(self.game.s.rows)
|
||||||
|
if to_stack_ncards == 0:
|
||||||
|
n = n - 1
|
||||||
|
max_move = max_move * (2 ** n)
|
||||||
|
return max_move
|
||||||
|
def _getNumSSSeq(self, cards):
|
||||||
|
# num of same-suit sequences (for SuperMoveSpider_RowStack)
|
||||||
|
if not cards:
|
||||||
|
return 0
|
||||||
|
mod = self.cap.mod
|
||||||
|
dir = self.cap.dir
|
||||||
|
n = 1
|
||||||
|
rank = cards[-1].rank
|
||||||
|
suit = cards[-1].suit
|
||||||
|
for c in cards[-2::-1]:
|
||||||
|
if c.suit != suit:
|
||||||
|
suit = c.suit
|
||||||
|
n += 1
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
class SuperMoveSS_RowStack(SuperMoveStack_StackMethods, SS_RowStack):
|
||||||
|
def canMoveCards(self, cards):
|
||||||
|
if not SS_RowStack.canMoveCards(self, cards):
|
||||||
|
return False
|
||||||
|
max_move = self._getMaxMove(1)
|
||||||
|
return len(cards) <= max_move
|
||||||
|
def acceptsCards(self, from_stack, cards):
|
||||||
|
if not SS_RowStack.acceptsCards(self, from_stack, cards):
|
||||||
|
return False
|
||||||
|
max_move = self._getMaxMove(len(self.cards))
|
||||||
|
return len(cards) <= max_move
|
||||||
|
|
||||||
|
class SuperMoveAC_RowStack(SuperMoveStack_StackMethods, AC_RowStack):
|
||||||
|
def canMoveCards(self, cards):
|
||||||
|
if not AC_RowStack.canMoveCards(self, cards):
|
||||||
|
return False
|
||||||
|
max_move = self._getMaxMove(1)
|
||||||
|
return len(cards) <= max_move
|
||||||
|
def acceptsCards(self, from_stack, cards):
|
||||||
|
if not AC_RowStack.acceptsCards(self, from_stack, cards):
|
||||||
|
return False
|
||||||
|
max_move = self._getMaxMove(len(self.cards))
|
||||||
|
return len(cards) <= max_move
|
||||||
|
|
||||||
|
class SuperMoveRK_RowStack(SuperMoveStack_StackMethods, RK_RowStack):
|
||||||
|
def canMoveCards(self, cards):
|
||||||
|
if not RK_RowStack.canMoveCards(self, cards):
|
||||||
|
return False
|
||||||
|
max_move = self._getMaxMove(1)
|
||||||
|
return len(cards) <= max_move
|
||||||
|
def acceptsCards(self, from_stack, cards):
|
||||||
|
if not RK_RowStack.acceptsCards(self, from_stack, cards):
|
||||||
|
return False
|
||||||
|
max_move = self._getMaxMove(len(self.cards))
|
||||||
|
return len(cards) <= max_move
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // WasteStack (a helper stack for the Talon, e.g. in Klondike)
|
# // WasteStack (a helper stack for the Talon, e.g. in Klondike)
|
||||||
|
@ -2334,8 +2466,13 @@ class WasteTalonStack(TalonStack):
|
||||||
assert len(waste.cards) + num_cards <= waste.cap.max_cards
|
assert len(waste.cards) + num_cards <= waste.cap.max_cards
|
||||||
for i in range(num_cards):
|
for i in range(num_cards):
|
||||||
if not self.cards[-1].face_up:
|
if not self.cards[-1].face_up:
|
||||||
|
if 1:
|
||||||
|
self.game.flipAndMoveMove(self, waste)
|
||||||
|
else:
|
||||||
self.game.flipMove(self)
|
self.game.flipMove(self)
|
||||||
self.game.moveMove(1, self, waste, frames=4, shadow=0)
|
self.game.moveMove(1, self, waste, frames=4, shadow=0)
|
||||||
|
else:
|
||||||
|
self.game.moveMove(1, self, waste, frames=4, shadow=0)
|
||||||
self.fillStack()
|
self.fillStack()
|
||||||
elif waste.cards and self.round != self.max_rounds:
|
elif waste.cards and self.round != self.max_rounds:
|
||||||
if sound:
|
if sound:
|
||||||
|
@ -2355,6 +2492,11 @@ class FaceUpWasteTalonStack(WasteTalonStack):
|
||||||
self.game.flipMove(self)
|
self.game.flipMove(self)
|
||||||
self.game.fillStack(self)
|
self.game.fillStack(self)
|
||||||
|
|
||||||
|
def dealCards(self, sound=0):
|
||||||
|
WasteTalonStack.dealCards(self, sound=sound)
|
||||||
|
if self.canFlipCard():
|
||||||
|
self.flipMove()
|
||||||
|
|
||||||
|
|
||||||
class OpenTalonStack(TalonStack, OpenStack):
|
class OpenTalonStack(TalonStack, OpenStack):
|
||||||
canMoveCards = OpenStack.canMoveCards
|
canMoveCards = OpenStack.canMoveCards
|
||||||
|
@ -2460,7 +2602,7 @@ class ArbitraryStack(OpenStack):
|
||||||
# flip or drop a card
|
# flip or drop a card
|
||||||
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
||||||
if self in flipstacks and self.canFlipCard():
|
if self in flipstacks and self.canFlipCard():
|
||||||
self.playFlipMove()
|
self.playFlipMove(animation=True)
|
||||||
return -1 # continue this event (start a drag)
|
return -1 # continue this event (start a drag)
|
||||||
if self in dropstacks:
|
if self in dropstacks:
|
||||||
i = self._findCard(event)
|
i = self._findCard(event)
|
||||||
|
|
|
@ -243,3 +243,126 @@ class FileStatsFormatter(PysolStatsFormatter):
|
||||||
prev_games = self.app.stats.session_games.get(player)
|
prev_games = self.app.stats.session_games.get(player)
|
||||||
return self.writeLog(player, header, prev_games)
|
return self.writeLog(player, header, prev_games)
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# //
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class ProgressionFormatter:
|
||||||
|
|
||||||
|
def __init__(self, app, player, gameid):
|
||||||
|
|
||||||
|
all_results = {} # key: (year, month, day); value: [played, won]
|
||||||
|
self.all_results = all_results
|
||||||
|
game_results = {}
|
||||||
|
self.game_results = game_results
|
||||||
|
games = app.stats.prev_games.get(player)
|
||||||
|
if not games:
|
||||||
|
return
|
||||||
|
for g in games:
|
||||||
|
id = g[0]
|
||||||
|
status = g[2]
|
||||||
|
start_time = g[3]
|
||||||
|
t = time.localtime(start_time)[:3]
|
||||||
|
if t not in all_results:
|
||||||
|
all_results[t] = [0,0]
|
||||||
|
all_results[t][0] += 1
|
||||||
|
if status > 0:
|
||||||
|
all_results[t][1] += 1
|
||||||
|
if id == gameid:
|
||||||
|
if t not in game_results:
|
||||||
|
game_results[t] = [0,0]
|
||||||
|
game_results[t][0] += 1
|
||||||
|
if status > 0:
|
||||||
|
game_results[t][1] += 1
|
||||||
|
##from pprint import pprint; pprint(all_results)
|
||||||
|
|
||||||
|
def norm_time(self, t):
|
||||||
|
if len(t) == 3:
|
||||||
|
t = list(t)+[0,0,0,-1,-1,-1]
|
||||||
|
return list(time.localtime(time.mktime((t))))
|
||||||
|
|
||||||
|
def getResults(self, interval, all_games=True):
|
||||||
|
if all_games:
|
||||||
|
results = self.all_results
|
||||||
|
else:
|
||||||
|
results = self.game_results
|
||||||
|
t = list(time.localtime())
|
||||||
|
if interval == 'week':
|
||||||
|
t[2] -= 7
|
||||||
|
lt = self.norm_time(t)
|
||||||
|
marks = None
|
||||||
|
delta = 1
|
||||||
|
format = '%d.%m'
|
||||||
|
elif interval == 'month':
|
||||||
|
tt = t[:]
|
||||||
|
t[1] -= 1
|
||||||
|
lt = self.norm_time(t)
|
||||||
|
marks = [lt[:3], tt[:3]]
|
||||||
|
tt[2] -= 10
|
||||||
|
marks.append(self.norm_time(tt)[:3])
|
||||||
|
tt[2] -= 10
|
||||||
|
marks.append(self.norm_time(tt)[:3])
|
||||||
|
delta = 1
|
||||||
|
format = '%d.%m'
|
||||||
|
elif interval == 'year':
|
||||||
|
tt = t[:]
|
||||||
|
t[0] -= 1
|
||||||
|
lt = self.norm_time(t)
|
||||||
|
marks = [lt[:3], tt[:3]]
|
||||||
|
for i in xrange(5):
|
||||||
|
tt[1] -= 2
|
||||||
|
marks.append(self.norm_time(tt)[:3])
|
||||||
|
delta = 7
|
||||||
|
format = '%d.%m.%y'
|
||||||
|
else: # all
|
||||||
|
tt = t[:]
|
||||||
|
tt[1] -= 1
|
||||||
|
tt = self.norm_time(tt)
|
||||||
|
if results:
|
||||||
|
lt = self.norm_time(min(results.keys()))
|
||||||
|
lt = min(lt, tt) # min 1 month
|
||||||
|
else:
|
||||||
|
lt = tt
|
||||||
|
dt = time.time()-time.mktime(lt)
|
||||||
|
if dt > 63072000: # 2 years
|
||||||
|
d = 6
|
||||||
|
elif dt > 31536000: # 1 year
|
||||||
|
d = 4
|
||||||
|
elif dt > 10512000: # 4 month
|
||||||
|
d = 2
|
||||||
|
else:
|
||||||
|
d = 1
|
||||||
|
marks = [lt[:3], t[:3]]
|
||||||
|
while t > lt:
|
||||||
|
t[1] -= d
|
||||||
|
t = self.norm_time(t)
|
||||||
|
marks.append(t[:3])
|
||||||
|
delta = 7
|
||||||
|
format = '%d.%m.%y'
|
||||||
|
|
||||||
|
res = []
|
||||||
|
ct = list(time.localtime())
|
||||||
|
while lt <= ct:
|
||||||
|
##assert type(lt) is type(ct)
|
||||||
|
sum = [0,0]
|
||||||
|
played = 0
|
||||||
|
won = 0
|
||||||
|
text = None
|
||||||
|
for i in xrange(delta):
|
||||||
|
if marks:
|
||||||
|
if ct[:3] in marks:
|
||||||
|
text = time.strftime(format, ct)
|
||||||
|
else:
|
||||||
|
text = time.strftime(format, ct)
|
||||||
|
t = tuple(ct[:3])
|
||||||
|
if t in results:
|
||||||
|
played += results[t][0]
|
||||||
|
won += results[t][1]
|
||||||
|
ct[2] -= 1
|
||||||
|
ct = self.norm_time(ct)
|
||||||
|
res.append((text, played, won))
|
||||||
|
res.reverse()
|
||||||
|
##from pprint import pprint; pprint(res)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ Message = Tkinter.Message
|
||||||
Listbox = Tkinter.Listbox
|
Listbox = Tkinter.Listbox
|
||||||
Text = Tkinter.Text
|
Text = Tkinter.Text
|
||||||
Canvas = Tkinter.Canvas
|
Canvas = Tkinter.Canvas
|
||||||
|
Spinbox = Tkinter.Spinbox
|
||||||
|
|
||||||
PhotoImage = Tkinter.PhotoImage
|
PhotoImage = Tkinter.PhotoImage
|
||||||
Event = Tkinter.Event
|
Event = Tkinter.Event
|
||||||
|
|
|
@ -49,8 +49,6 @@ class ColorsDialog(MfxDialog):
|
||||||
frame.pack(expand=True, fill='both', padx=5, pady=10)
|
frame.pack(expand=True, fill='both', padx=5, pady=10)
|
||||||
frame.columnconfigure(0, weight=1)
|
frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
self.use_default_var = Tkinter.BooleanVar()
|
|
||||||
self.use_default_var.set(not app.opt.use_default_text_color)
|
|
||||||
self.text_var = Tkinter.StringVar()
|
self.text_var = Tkinter.StringVar()
|
||||||
self.text_var.set(app.opt.colors['text'])
|
self.text_var.set(app.opt.colors['text'])
|
||||||
self.piles_var = Tkinter.StringVar()
|
self.piles_var = Tkinter.StringVar()
|
||||||
|
@ -68,17 +66,9 @@ class ColorsDialog(MfxDialog):
|
||||||
self.not_matching_var = Tkinter.StringVar()
|
self.not_matching_var = Tkinter.StringVar()
|
||||||
self.not_matching_var.set(app.opt.colors['not_matching'])
|
self.not_matching_var.set(app.opt.colors['not_matching'])
|
||||||
#
|
#
|
||||||
c = Tkinter.Checkbutton(frame, variable=self.use_default_var,
|
row = 0
|
||||||
text=_("Text foreground:"))
|
|
||||||
c.grid(row=0, column=0, sticky='we')
|
|
||||||
l = Tk.Label(frame, width=10, height=2,
|
|
||||||
bg=self.text_var.get(), textvariable=self.text_var)
|
|
||||||
l.grid(row=0, column=1, padx=5)
|
|
||||||
b = Tkinter.Button(frame, text=_('Change...'), width=10,
|
|
||||||
command=lambda l=l: self.selectColor(l))
|
|
||||||
b.grid(row=0, column=2)
|
|
||||||
row = 1
|
|
||||||
for title, var in (
|
for title, var in (
|
||||||
|
(_('Text foreground:'), self.text_var),
|
||||||
(_('Highlight piles:'), self.piles_var),
|
(_('Highlight piles:'), self.piles_var),
|
||||||
(_('Highlight cards 1:'), self.cards_1_var),
|
(_('Highlight cards 1:'), self.cards_1_var),
|
||||||
(_('Highlight cards 2:'), self.cards_2_var),
|
(_('Highlight cards 2:'), self.cards_2_var),
|
||||||
|
@ -100,7 +90,6 @@ class ColorsDialog(MfxDialog):
|
||||||
focus = self.createButtons(bottom_frame, kw)
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
self.mainloop(focus, kw.timeout)
|
self.mainloop(focus, kw.timeout)
|
||||||
#
|
#
|
||||||
self.use_default_color = not self.use_default_var.get()
|
|
||||||
self.text_color = self.text_var.get()
|
self.text_color = self.text_var.get()
|
||||||
self.piles_color = self.piles_var.get()
|
self.piles_color = self.piles_var.get()
|
||||||
self.cards_1_color = self.cards_1_var.get()
|
self.cards_1_color = self.cards_1_var.get()
|
||||||
|
|
|
@ -114,6 +114,7 @@ class FindCardDialog(Tkinter.Toplevel):
|
||||||
self.groups.append(group)
|
self.groups.append(group)
|
||||||
|
|
||||||
def connectGame(self, game):
|
def connectGame(self, game):
|
||||||
|
self.canvas.delete('all')
|
||||||
self.game = game
|
self.game = game
|
||||||
suits = game.gameinfo.suits
|
suits = game.gameinfo.suits
|
||||||
ranks = game.gameinfo.ranks
|
ranks = game.gameinfo.ranks
|
||||||
|
@ -133,6 +134,7 @@ class FindCardDialog(Tkinter.Toplevel):
|
||||||
w, h = dx*j+2, dy*i+2
|
w, h = dx*j+2, dy*i+2
|
||||||
self.canvas.config(width=w, height=h)
|
self.canvas.config(width=w, height=h)
|
||||||
self.wm_iconname(PACKAGE + " - " + game.getTitleName())
|
self.wm_iconname(PACKAGE + " - " + game.getTitleName())
|
||||||
|
self.wm_geometry('') # cancel user-specified geometry
|
||||||
|
|
||||||
def enterEvent(self, suit, rank, rect, group):
|
def enterEvent(self, suit, rank, rect, group):
|
||||||
##print 'enterEvent', suit, rank, self.busy
|
##print 'enterEvent', suit, rank, self.busy
|
||||||
|
|
|
@ -48,6 +48,7 @@ from pysollib.util import CARDSET
|
||||||
from pysollib.settings import PACKAGE, WIN_SYSTEM
|
from pysollib.settings import PACKAGE, WIN_SYSTEM
|
||||||
from pysollib.settings import TOP_TITLE
|
from pysollib.settings import TOP_TITLE
|
||||||
from pysollib.settings import SELECT_GAME_MENU
|
from pysollib.settings import SELECT_GAME_MENU
|
||||||
|
from pysollib.settings import USE_FREECELL_SOLVER
|
||||||
from pysollib.gamedb import GI
|
from pysollib.gamedb import GI
|
||||||
from pysollib.actions import PysolMenubarActions
|
from pysollib.actions import PysolMenubarActions
|
||||||
|
|
||||||
|
@ -59,6 +60,7 @@ from soundoptionsdialog import SoundOptionsDialog
|
||||||
from selectcardset import SelectCardsetDialogWithPreview
|
from selectcardset import SelectCardsetDialogWithPreview
|
||||||
from selecttile import SelectTileDialogWithPreview
|
from selecttile import SelectTileDialogWithPreview
|
||||||
from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog
|
from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog
|
||||||
|
from solverdialog import connect_game_solver_dialog
|
||||||
from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar
|
from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar
|
||||||
from tkwidget import MfxMessageDialog
|
from tkwidget import MfxMessageDialog
|
||||||
|
|
||||||
|
@ -139,25 +141,18 @@ class MfxMenubar(Tkinter.Menu):
|
||||||
#print label, type(label)
|
#print label, type(label)
|
||||||
name = re.sub(r"[^0-9a-zA-Z]", "", label).lower()
|
name = re.sub(r"[^0-9a-zA-Z]", "", label).lower()
|
||||||
label = gettext(label)
|
label = gettext(label)
|
||||||
underline = -1
|
underline = label.find('&')
|
||||||
m = re.search(r"^(.*)\&([^\&].*)$", label)
|
if underline >= 0:
|
||||||
if m:
|
label = label.replace('&', '')
|
||||||
l1, l2 = m.group(1), m.group(2)
|
|
||||||
l1 = re.sub(r"\&\&", "&", l1)
|
|
||||||
l2 = re.sub(r"\&\&", "&", l2)
|
|
||||||
label = l1 + l2
|
|
||||||
underline = len(l1)
|
|
||||||
return name, label, underline
|
return name, label, underline
|
||||||
|
|
||||||
def add(self, itemType, cnf={}):
|
def add(self, itemType, cnf={}):
|
||||||
label = cnf.get("label")
|
label = cnf.get("label")
|
||||||
if label:
|
if label:
|
||||||
name = cnf.get('name')
|
name = cnf.get('name')
|
||||||
try:
|
if name:
|
||||||
del cnf['name'] # TclError: unknown option "-name"
|
del cnf['name'] # TclError: unknown option "-name"
|
||||||
except KeyError:
|
else:
|
||||||
pass
|
|
||||||
if not name:
|
|
||||||
name, label, underline = self.labeltoname(label)
|
name, label, underline = self.labeltoname(label)
|
||||||
cnf["underline"] = cnf.get("underline", underline)
|
cnf["underline"] = cnf.get("underline", underline)
|
||||||
cnf["label"] = label
|
cnf["label"] = label
|
||||||
|
@ -323,6 +318,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
connect_game_find_card_dialog(game)
|
connect_game_find_card_dialog(game)
|
||||||
else:
|
else:
|
||||||
destroy_find_card_dialog()
|
destroy_find_card_dialog()
|
||||||
|
connect_game_solver_dialog(game)
|
||||||
|
|
||||||
# create a GTK-like path
|
# create a GTK-like path
|
||||||
def _addPath(self, path, menu, index, submenu):
|
def _addPath(self, path, menu, index, submenu):
|
||||||
|
@ -371,7 +367,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
submenu = MfxMenu(menu, label=n_("Fa&vorite games"))
|
submenu = MfxMenu(menu, label=n_("Fa&vorite games"))
|
||||||
menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor)
|
menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor)
|
||||||
menu.add_command(label=n_("R&emove from favorites"), command=self.mDelFavor)
|
menu.add_command(label=n_("Remove &from favorites"), command=self.mDelFavor)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O")
|
menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O")
|
||||||
menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S")
|
menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S")
|
||||||
|
@ -414,7 +410,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P")
|
menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P")
|
||||||
#menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P")
|
#menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P")
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("S&tatus..."), command=self.mStatus, accelerator="T")
|
menu.add_command(label=n_("S&tatus..."), command=self.mStatus, accelerator=m+"Y")
|
||||||
menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment)
|
menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
submenu = MfxMenu(menu, label=n_("&Statistics"))
|
submenu = MfxMenu(menu, label=n_("&Statistics"))
|
||||||
|
@ -425,6 +421,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
submenu.add_command(label=n_("Full log..."), command=lambda self=self: self.mPlayerStats(mode=103))
|
submenu.add_command(label=n_("Full log..."), command=lambda self=self: self.mPlayerStats(mode=103))
|
||||||
submenu.add_separator()
|
submenu.add_separator()
|
||||||
submenu.add_command(label=TOP_TITLE+"...", command=self.mTop10, accelerator=m+"T")
|
submenu.add_command(label=TOP_TITLE+"...", command=self.mTop10, accelerator=m+"T")
|
||||||
|
submenu.add_command(label=n_("Progression..."), command=lambda self=self: self.mPlayerStats(mode=107))
|
||||||
submenu = MfxMenu(menu, label=n_("D&emo statistics"))
|
submenu = MfxMenu(menu, label=n_("D&emo statistics"))
|
||||||
submenu.add_command(label=n_("Current game..."), command=lambda self=self: self.mPlayerStats(mode=1101))
|
submenu.add_command(label=n_("Current game..."), command=lambda self=self: self.mPlayerStats(mode=1101))
|
||||||
submenu.add_command(label=n_("All games..."), command=lambda self=self: self.mPlayerStats(mode=1102))
|
submenu.add_command(label=n_("All games..."), command=lambda self=self: self.mPlayerStats(mode=1102))
|
||||||
|
@ -432,12 +429,16 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu = MfxMenu(self.__menubar, label=n_("&Assist"))
|
menu = MfxMenu(self.__menubar, label=n_("&Assist"))
|
||||||
menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H")
|
menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H")
|
||||||
menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I")
|
menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I")
|
||||||
menu.add_command(label=n_("Find card"), command=self.mFindCard, accelerator="F")
|
menu.add_command(label=n_("&Find card"), command=self.mFindCard, accelerator="F3")
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D")
|
menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D")
|
||||||
menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo)
|
menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo)
|
||||||
|
if USE_FREECELL_SOLVER:
|
||||||
|
menu.add_command(label=n_("&Solver (experimental)"), command=self.mSolver)
|
||||||
|
else:
|
||||||
|
menu.add_command(label=n_("&Solver (experimental)"), command=self.mSolver, state=Tkinter.DISABLED)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("Piles description"), command=self.mStackDesk, accelerator="F2")
|
menu.add_command(label=n_("&Piles description"), command=self.mStackDesk, accelerator="F2")
|
||||||
|
|
||||||
if self.progress: self.progress.update(step=1)
|
if self.progress: self.progress.update(step=1)
|
||||||
|
|
||||||
|
@ -481,10 +482,11 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks)
|
submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks)
|
||||||
submenu = MfxMenu(menu, label=n_("A&nimations"))
|
submenu = MfxMenu(menu, label=n_("A&nimations"))
|
||||||
submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Timer based"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Very fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Medium"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Very slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations)
|
||||||
|
submenu.add_radiobutton(label=n_("V&ery slow"), variable=self.tkopt.animations, value=5, command=self.mOptAnimations)
|
||||||
submenu.add_separator()
|
submenu.add_separator()
|
||||||
submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation)
|
submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation)
|
||||||
if Image:
|
if Image:
|
||||||
|
@ -531,15 +533,13 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
ctrl = "Control-"
|
ctrl = "Control-"
|
||||||
if sys.platform == "darwin": ctrl = "Command-"
|
if sys.platform == "darwin": ctrl = "Command-"
|
||||||
self._bindKey("", "n", self.mNewGame)
|
self._bindKey("", "n", self.mNewGame)
|
||||||
self._bindKey("", "g", self.mSelectGameDialog)
|
self._bindKey(ctrl, "w", self.mSelectGameDialog)
|
||||||
self._bindKey("", "v", self.mSelectGameDialogWithPreview)
|
self._bindKey(ctrl, "v", self.mSelectGameDialogWithPreview)
|
||||||
self._bindKey(ctrl, "r", lambda e, self=self: self.mSelectRandomGame())
|
self._bindKey(ctrl, "r", lambda e, self=self: self.mSelectRandomGame())
|
||||||
self._bindKey(ctrl, "m", self.mSelectGameById)
|
self._bindKey(ctrl, "m", self.mSelectGameById)
|
||||||
self._bindKey(ctrl, "n", self.mNewGameWithNextId)
|
self._bindKey(ctrl, "n", self.mNewGameWithNextId)
|
||||||
self._bindKey(ctrl, "o", self.mOpen)
|
self._bindKey(ctrl, "o", self.mOpen)
|
||||||
##self._bindKey("", "F3", self.mOpen) # undocumented
|
|
||||||
self._bindKey(ctrl, "s", self.mSave)
|
self._bindKey(ctrl, "s", self.mSave)
|
||||||
##self._bindKey("", "F2", self.mSaveAs) # undocumented
|
|
||||||
self._bindKey(ctrl, "q", self.mQuit)
|
self._bindKey(ctrl, "q", self.mQuit)
|
||||||
self._bindKey("", "z", self.mUndo)
|
self._bindKey("", "z", self.mUndo)
|
||||||
self._bindKey("", "BackSpace", self.mUndo) # undocumented
|
self._bindKey("", "BackSpace", self.mUndo) # undocumented
|
||||||
|
@ -547,14 +547,14 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
self._bindKey("", "r", self.mRedo)
|
self._bindKey("", "r", self.mRedo)
|
||||||
self._bindKey(ctrl, "g", self.mRestart)
|
self._bindKey(ctrl, "g", self.mRestart)
|
||||||
self._bindKey("", "space", self.mDeal) # undocumented
|
self._bindKey("", "space", self.mDeal) # undocumented
|
||||||
self._bindKey("", "t", self.mStatus)
|
self._bindKey(ctrl, "y", self.mStatus)
|
||||||
self._bindKey(ctrl, "t", self.mTop10)
|
self._bindKey(ctrl, "t", self.mTop10)
|
||||||
self._bindKey("", "h", self.mHint)
|
self._bindKey("", "h", self.mHint)
|
||||||
self._bindKey(ctrl, "h", self.mHint1) # undocumented
|
self._bindKey(ctrl, "h", self.mHint1) # undocumented
|
||||||
##self._bindKey("", "Shift_L", self.mHighlightPiles)
|
##self._bindKey("", "Shift_L", self.mHighlightPiles)
|
||||||
##self._bindKey("", "Shift_R", self.mHighlightPiles)
|
##self._bindKey("", "Shift_R", self.mHighlightPiles)
|
||||||
self._bindKey("", "i", self.mHighlightPiles)
|
self._bindKey("", "i", self.mHighlightPiles)
|
||||||
self._bindKey("", "f", self.mFindCard)
|
self._bindKey("", "F3", self.mFindCard)
|
||||||
self._bindKey(ctrl, "d", self.mDemo)
|
self._bindKey(ctrl, "d", self.mDemo)
|
||||||
self._bindKey(ctrl, "e", self.mSelectCardsetDialog)
|
self._bindKey(ctrl, "e", self.mSelectCardsetDialog)
|
||||||
self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented
|
self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented
|
||||||
|
@ -597,19 +597,19 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
#
|
#
|
||||||
|
|
||||||
def _bindKey(self, modifier, key, func):
|
def _bindKey(self, modifier, key, func):
|
||||||
if 0 and not modifier and len(key) == 1:
|
## if 0 and not modifier and len(key) == 1:
|
||||||
self.__keybindings[key.lower()] = func
|
## self.__keybindings[key.lower()] = func
|
||||||
self.__keybindings[key.upper()] = func
|
## self.__keybindings[key.upper()] = func
|
||||||
return
|
## return
|
||||||
|
if not modifier and len(key) == 1:
|
||||||
|
# ignore Ctrl/Shift/Alt
|
||||||
|
func = lambda e, func=func: e.state == 0 and func(e)
|
||||||
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
||||||
try:
|
|
||||||
bind(self.top, sequence, func)
|
bind(self.top, sequence, func)
|
||||||
if len(key) == 1 and key != key.upper():
|
if len(key) == 1 and key != key.upper():
|
||||||
key = key.upper()
|
key = key.upper()
|
||||||
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
||||||
bind(self.top, sequence, func)
|
bind(self.top, sequence, func)
|
||||||
except:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def _keyPressHandler(self, event):
|
def _keyPressHandler(self, event):
|
||||||
|
@ -621,10 +621,10 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
if event.char: # ignore Ctrl/Shift/etc.
|
if event.char: # ignore Ctrl/Shift/etc.
|
||||||
self.game.demo.keypress = event.char
|
self.game.demo.keypress = event.char
|
||||||
r = EVENT_HANDLED
|
r = EVENT_HANDLED
|
||||||
func = self.__keybindings.get(event.char)
|
## func = self.__keybindings.get(event.char)
|
||||||
if func and (event.state & ~2) == 0:
|
## if func and (event.state & ~2) == 0:
|
||||||
func(event)
|
## func(event)
|
||||||
r = EVENT_HANDLED
|
## r = EVENT_HANDLED
|
||||||
return r
|
return r
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -636,9 +636,11 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName())
|
games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName())
|
||||||
##games = tuple(games)
|
##games = tuple(games)
|
||||||
###menu = MfxMenu(menu, label="Select &game")
|
###menu = MfxMenu(menu, label="Select &game")
|
||||||
menu.add_command(label=n_("All &games..."), accelerator="G",
|
m = "Ctrl-"
|
||||||
|
if sys.platform == "darwin": m = "Cmd-"
|
||||||
|
menu.add_command(label=n_("All &games..."), accelerator=m+"W",
|
||||||
command=self.mSelectGameDialog)
|
command=self.mSelectGameDialog)
|
||||||
menu.add_command(label=n_("Playable pre&view..."), accelerator="V",
|
menu.add_command(label=n_("Playable pre&view..."), accelerator=m+"V",
|
||||||
command=self.mSelectGameDialogWithPreview)
|
command=self.mSelectGameDialogWithPreview)
|
||||||
if not SELECT_GAME_MENU:
|
if not SELECT_GAME_MENU:
|
||||||
return
|
return
|
||||||
|
@ -783,13 +785,19 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
gi = games[i]
|
gi = games[i]
|
||||||
columnbreak = i > 0 and (i % cb) == 0
|
columnbreak = i > 0 and (i % cb) == 0
|
||||||
if short_name:
|
if short_name:
|
||||||
label = gi.short_name
|
label = gettext(gi.short_name)
|
||||||
else:
|
else:
|
||||||
label = gi.name
|
label = gettext(gi.name)
|
||||||
menu.add_radiobutton(command=command, variable=variable,
|
## menu.add_radiobutton(command=command, variable=variable,
|
||||||
columnbreak=columnbreak,
|
## columnbreak=columnbreak,
|
||||||
value=gi.id, label=label, name=None)
|
## value=gi.id, label=label, name=None)
|
||||||
|
# optimized by inlining
|
||||||
|
menu.tk.call((menu._w, 'add', 'radiobutton') +
|
||||||
|
menu._options({'command': command,
|
||||||
|
'variable': variable,
|
||||||
|
'columnbreak': columnbreak,
|
||||||
|
'value': gi.id,
|
||||||
|
'label': label}))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Select Game menu actions
|
# Select Game menu actions
|
||||||
|
@ -1148,7 +1156,6 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
self._cancelDrag()
|
self._cancelDrag()
|
||||||
self.game.endGame(bookmark=1)
|
self.game.endGame(bookmark=1)
|
||||||
self.game.quitGame(bookmark=1)
|
self.game.quitGame(bookmark=1)
|
||||||
self.app.opt.games_geometry = {} # clear saved games geometry
|
|
||||||
|
|
||||||
def _mOptCardback(self, index):
|
def _mOptCardback(self, index):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
|
@ -1328,13 +1335,13 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
|
|
||||||
def mOptTheme(self, *event):
|
def mOptTheme(self, *event):
|
||||||
theme = self.tkopt.theme.get()
|
theme = self.tkopt.theme.get()
|
||||||
|
self.app.opt.tile_theme = theme
|
||||||
d = MfxMessageDialog(self.top, title=_("Change theme"),
|
d = MfxMessageDialog(self.top, title=_("Change theme"),
|
||||||
text=_("""\
|
text=_("""\
|
||||||
This settings will take effect
|
This settings will take effect
|
||||||
the next time you restart """)+PACKAGE,
|
the next time you restart """)+PACKAGE,
|
||||||
bitmap="warning",
|
bitmap="warning",
|
||||||
default=0, strings=(_("&OK"),))
|
default=0, strings=(_("&OK"),))
|
||||||
self.app.opt.tile_theme = theme
|
|
||||||
|
|
||||||
def createThemesMenu(self, menu):
|
def createThemesMenu(self, menu):
|
||||||
submenu = MfxMenu(menu, label=n_("Set t&heme"))
|
submenu = MfxMenu(menu, label=n_("Set t&heme"))
|
||||||
|
@ -1343,12 +1350,12 @@ the next time you restart """)+PACKAGE,
|
||||||
all_themes.sort()
|
all_themes.sort()
|
||||||
#
|
#
|
||||||
tn = {
|
tn = {
|
||||||
'default': _('Default'),
|
'default': n_('Default'),
|
||||||
'classic': _('Classic'),
|
'classic': n_('Classic'),
|
||||||
'alt': _('Revitalized'),
|
'alt': n_('Revitalized'),
|
||||||
'winnative': _('Windows native'),
|
'winnative': n_('Windows native'),
|
||||||
'xpnative': _('XP Native'),
|
'xpnative': n_('XP Native'),
|
||||||
'aqua': _('Aqua'),
|
'aqua': n_('Aqua'),
|
||||||
}
|
}
|
||||||
for t in all_themes:
|
for t in all_themes:
|
||||||
try:
|
try:
|
||||||
|
@ -1357,4 +1364,3 @@ the next time you restart """)+PACKAGE,
|
||||||
n = t.capitalize()
|
n = t.capitalize()
|
||||||
submenu.add_radiobutton(label=n, variable=self.tkopt.theme,
|
submenu.add_radiobutton(label=n, variable=self.tkopt.theme,
|
||||||
value=t, command=self.mOptTheme)
|
value=t, command=self.mOptTheme)
|
||||||
|
|
||||||
|
|
|
@ -428,7 +428,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
destruct(self.preview_app)
|
destruct(self.preview_app)
|
||||||
self.preview_app = None
|
self.preview_app = None
|
||||||
|
|
||||||
def updatePreview(self, gameid, animations=5):
|
def updatePreview(self, gameid, animations=10):
|
||||||
if gameid == self.preview_key:
|
if gameid == self.preview_key:
|
||||||
return
|
return
|
||||||
self.deletePreview()
|
self.deletePreview()
|
||||||
|
@ -495,7 +495,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
#
|
#
|
||||||
self.preview_app.audio = self.app.audio
|
self.preview_app.audio = self.app.audio
|
||||||
if self.app.opt.animations:
|
if self.app.opt.animations:
|
||||||
self.preview_app.opt.animations = 5
|
self.preview_app.opt.animations = 10
|
||||||
else:
|
else:
|
||||||
self.preview_app.opt.animations = 0
|
self.preview_app.opt.animations = 0
|
||||||
# save seed
|
# save seed
|
||||||
|
@ -553,13 +553,12 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
('percent', percent),
|
('percent', percent),
|
||||||
):
|
):
|
||||||
title_label, text_label = self.info_labels[n]
|
title_label, text_label = self.info_labels[n]
|
||||||
if t == '':
|
if t in ('', None):
|
||||||
title_label.grid_remove()
|
title_label.grid_remove()
|
||||||
text_label.grid_remove()
|
text_label.grid_remove()
|
||||||
else:
|
else:
|
||||||
title_label.grid()
|
title_label.grid()
|
||||||
text_label.grid()
|
text_label.grid()
|
||||||
text_label.config(text=t)
|
text_label.config(text=t)
|
||||||
#self.info_labels[n].config(text=t)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
330
pysollib/tile/solverdialog.py
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
##
|
||||||
|
## PySol -- a Python Solitaire game
|
||||||
|
##
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with this program; see the file COPYING.
|
||||||
|
## If not, write to the Free Software Foundation, Inc.,
|
||||||
|
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
##
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
#'SolverDialog',
|
||||||
|
'create_solver_dialog',
|
||||||
|
'connect_game_solver_dialog',
|
||||||
|
'destroy_solver_dialog',
|
||||||
|
'reset_solver_dialog',
|
||||||
|
]
|
||||||
|
|
||||||
|
# imports
|
||||||
|
import os, sys
|
||||||
|
import Tile as Tkinter
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
# PySol imports
|
||||||
|
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct
|
||||||
|
from pysollib.settings import PACKAGE
|
||||||
|
|
||||||
|
# Toolkit imports
|
||||||
|
from tkconst import EVENT_HANDLED, EVENT_PROPAGATE
|
||||||
|
from tkwidget import MfxDialog
|
||||||
|
from tkwidget import PysolScale
|
||||||
|
from tkutil import bind, unbind_destroy
|
||||||
|
|
||||||
|
gettext = _
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# //
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class SolverDialog(MfxDialog):
|
||||||
|
|
||||||
|
def __init__(self, parent, app, **kw):
|
||||||
|
self.parent = parent
|
||||||
|
self.app = app
|
||||||
|
title = PACKAGE+' - FreeCell Solver'
|
||||||
|
kw = self.initKw(kw)
|
||||||
|
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
|
||||||
|
top_frame, bottom_frame = self.createFrames(kw)
|
||||||
|
self.createBitmaps(top_frame, kw)
|
||||||
|
#
|
||||||
|
self.solving_methods = {
|
||||||
|
'A*': 'a-star',
|
||||||
|
'Breadth-First Search': 'bfs',
|
||||||
|
'Depth-First Search': 'dfs', # default
|
||||||
|
'A randomized DFS': 'random-dfs',
|
||||||
|
'"Soft" DFS': 'soft-dfs',
|
||||||
|
}
|
||||||
|
self.games = {} # key: gamename; value: gameid
|
||||||
|
|
||||||
|
#
|
||||||
|
frame = Tkinter.Frame(top_frame)
|
||||||
|
frame.pack(expand=True, fill='both', padx=4, pady=4)
|
||||||
|
frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
#
|
||||||
|
row = 0
|
||||||
|
Tkinter.Label(frame, text=_('Game:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
games = app.getGamesForSolver()
|
||||||
|
gamenames = ['']
|
||||||
|
for id in games:
|
||||||
|
name = app.getGameTitleName(id)
|
||||||
|
name = gettext(name)
|
||||||
|
gamenames.append(name)
|
||||||
|
self.games[name] = id
|
||||||
|
gamenames.sort()
|
||||||
|
self.gamenames = gamenames
|
||||||
|
cb = Tkinter.Combobox(frame, values=tuple(gamenames),
|
||||||
|
state='readonly', width=40)
|
||||||
|
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
bind(cb, '<<ComboboxSelected>>', self.gameSelected)
|
||||||
|
self.games_var = cb
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
Tkinter.Label(frame, text=_('Solving method:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
##sm = self.solving_methods.values()
|
||||||
|
##sm.sort()
|
||||||
|
sm = ['A*', 'Breadth-First Search', 'Depth-First Search',
|
||||||
|
'A randomized DFS', '"Soft" DFS']
|
||||||
|
cb = Tkinter.Combobox(frame, values=tuple(sm), state='readonly')
|
||||||
|
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
cb.current(sm.index('Depth-First Search'))
|
||||||
|
self.solving_method_var = cb
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
Tkinter.Label(frame, text=_('Preset:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
presets = [
|
||||||
|
'none',
|
||||||
|
'abra-kadabra',
|
||||||
|
'cool-jives',
|
||||||
|
'crooked-nose',
|
||||||
|
'fools-gold',
|
||||||
|
'good-intentions',
|
||||||
|
'hello-world',
|
||||||
|
'john-galt-line',
|
||||||
|
'rin-tin-tin',
|
||||||
|
'yellow-brick-road',
|
||||||
|
]
|
||||||
|
self.presets = presets
|
||||||
|
cb = Tkinter.Combobox(frame, values=tuple(presets), state='readonly')
|
||||||
|
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
cb.current(0)
|
||||||
|
self.preset_var = cb
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
self.max_iters_var = Tkinter.IntVar()
|
||||||
|
self.max_iters_var.set(10e4)
|
||||||
|
Tkinter.Label(frame, text=_('Max iterations:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
spin = Tkinter.Spinbox(frame, bg='white', from_=1000, to=10e6,
|
||||||
|
increment=1000, textvariable=self.max_iters_var)
|
||||||
|
spin.grid(row=row, column=1, sticky='w', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
self.max_depth_var = Tkinter.IntVar()
|
||||||
|
self.max_depth_var.set(1000)
|
||||||
|
Tkinter.Label(frame, text=_('Max depth:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
spin = Tkinter.Spinbox(frame, bg='white', from_=100, to=10000,
|
||||||
|
increment=100, textvariable=self.max_depth_var)
|
||||||
|
spin.grid(row=row, column=1, sticky='w', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
self.progress_var = Tkinter.BooleanVar()
|
||||||
|
self.progress_var.set(True)
|
||||||
|
w = Tkinter.Checkbutton(frame, variable=self.progress_var,
|
||||||
|
text=_('Show progress'))
|
||||||
|
w.grid(row=row, column=0, columnspan=2, sticky='ew', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
label_frame = Tkinter.LabelFrame(top_frame, text=_('Progress'))
|
||||||
|
label_frame.pack(expand=True, fill='both', padx=6, pady=2)
|
||||||
|
#label_frame.columnconfigure(0, weight=1)
|
||||||
|
label_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
#
|
||||||
|
frow = 0
|
||||||
|
Tkinter.Label(label_frame, text=_('Iteration:'), anchor='w'
|
||||||
|
).grid(row=frow, column=0, sticky='ew', padx=4, pady=2)
|
||||||
|
lb = Tkinter.Label(label_frame, anchor='w')
|
||||||
|
lb.grid(row=frow, column=1, sticky='ew', padx=4, pady=2)
|
||||||
|
self.iter_label = lb
|
||||||
|
frow += 1
|
||||||
|
Tkinter.Label(label_frame, text=_('Depth:'), anchor='w'
|
||||||
|
).grid(row=frow, column=0, sticky='ew', padx=4, pady=2)
|
||||||
|
lb = Tkinter.Label(label_frame, anchor='w')
|
||||||
|
lb.grid(row=frow, column=1, sticky='ew', padx=4, pady=2)
|
||||||
|
self.depth_label = lb
|
||||||
|
frow += 1
|
||||||
|
Tkinter.Label(label_frame, text=_('Stored-States:'), anchor='w'
|
||||||
|
).grid(row=frow, column=0, sticky='ew', padx=4, pady=2)
|
||||||
|
lb = Tkinter.Label(label_frame, anchor='w')
|
||||||
|
lb.grid(row=frow, column=1, sticky='ew', padx=4, pady=2)
|
||||||
|
self.states_label = lb
|
||||||
|
|
||||||
|
#
|
||||||
|
lb = Tkinter.Label(top_frame, anchor='w')
|
||||||
|
lb.pack(expand=True, fill='x', padx=6, pady=4)
|
||||||
|
self.result_label = lb
|
||||||
|
|
||||||
|
#
|
||||||
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
|
self.mainloop(focus, kw.timeout, transient=False)
|
||||||
|
|
||||||
|
self.start_button = self.buttons[0]
|
||||||
|
self.play_button = self.buttons[1]
|
||||||
|
|
||||||
|
#
|
||||||
|
self._reset()
|
||||||
|
self.connectGame(self.app.game)
|
||||||
|
|
||||||
|
def initKw(self, kw):
|
||||||
|
strings=[_('&Start'), _('&Play'), _('&New'), 'sep', _('&Close'),]
|
||||||
|
kw = KwStruct(kw,
|
||||||
|
strings=strings,
|
||||||
|
default=0,
|
||||||
|
)
|
||||||
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
def mDone(self, button):
|
||||||
|
if button == 0:
|
||||||
|
self.startSolving()
|
||||||
|
elif button == 1:
|
||||||
|
self.startPlay()
|
||||||
|
elif button == 2:
|
||||||
|
self.app.menubar.mNewGame()
|
||||||
|
elif button == 3:
|
||||||
|
global solver_dialog
|
||||||
|
solver_dialog = None
|
||||||
|
self.destroy()
|
||||||
|
return EVENT_HANDLED
|
||||||
|
|
||||||
|
def mCancel(self, *event):
|
||||||
|
return self.mDone(3)
|
||||||
|
|
||||||
|
def wmDeleteWindow(self, *event):
|
||||||
|
return self.mDone(3)
|
||||||
|
|
||||||
|
def gameSelected(self, *event):
|
||||||
|
name = self.games_var.get()
|
||||||
|
if not name:
|
||||||
|
return
|
||||||
|
id = self.games[name]
|
||||||
|
self.app.menubar._mSelectGame(id)
|
||||||
|
|
||||||
|
def connectGame(self, game):
|
||||||
|
name = self.app.getGameTitleName(game.id)
|
||||||
|
name = gettext(name)
|
||||||
|
if name in self.gamenames:
|
||||||
|
self.start_button.config(state='normal')
|
||||||
|
i = self.gamenames.index(name)
|
||||||
|
self.games_var.current(i)
|
||||||
|
else:
|
||||||
|
self.start_button.config(state='disabled')
|
||||||
|
self.games_var.current(0)
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
self.setText(iter='', depth='', states='')
|
||||||
|
self.result_label['text'] = ''
|
||||||
|
self.top.update_idletasks()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
|
||||||
|
def startSolving(self):
|
||||||
|
self._reset()
|
||||||
|
game = self.app.game
|
||||||
|
solver = game.Solver_Class(game, self) # create solver instance
|
||||||
|
game.solver = solver
|
||||||
|
method = self.solving_method_var.get()
|
||||||
|
method = self.solving_methods[method]
|
||||||
|
preset = self.preset_var.get()
|
||||||
|
max_iters = self.max_iters_var.get()
|
||||||
|
max_depth = self.max_depth_var.get()
|
||||||
|
progress = self.progress_var.get()
|
||||||
|
solver.config(method=method, preset=preset, max_iters=max_iters,
|
||||||
|
max_depth=max_depth, progress=progress)
|
||||||
|
solver.computeHints()
|
||||||
|
hints_len = len(solver.hints)-1
|
||||||
|
if hints_len > 0:
|
||||||
|
self.result_label['text'] = _('This game is solveable in %s moves.') % hints_len
|
||||||
|
self.play_button.config(state='normal')
|
||||||
|
else:
|
||||||
|
self.result_label['text'] = _('I could not solve this game.')
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
|
||||||
|
def startPlay(self):
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
self.app.top.tkraise()
|
||||||
|
self.app.top.update_idletasks()
|
||||||
|
self.app.top.update()
|
||||||
|
self.app.game.startDemo(level=3)
|
||||||
|
|
||||||
|
def setText(self, **kw):
|
||||||
|
if 'iter' in kw:
|
||||||
|
self.iter_label['text'] = kw['iter']
|
||||||
|
if 'depth' in kw:
|
||||||
|
self.depth_label['text'] = kw['depth']
|
||||||
|
if 'states' in kw:
|
||||||
|
self.states_label['text'] = kw['states']
|
||||||
|
self.top.update_idletasks()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
solver_dialog = None
|
||||||
|
|
||||||
|
def create_solver_dialog(parent, game):
|
||||||
|
global solver_dialog
|
||||||
|
try:
|
||||||
|
solver_dialog.top.wm_deiconify()
|
||||||
|
solver_dialog.top.tkraise()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
solver_dialog = SolverDialog(parent, game)
|
||||||
|
|
||||||
|
def connect_game_solver_dialog(game):
|
||||||
|
try:
|
||||||
|
solver_dialog.connectGame(game)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def destroy_solver_dialog():
|
||||||
|
global solver_dialog
|
||||||
|
try:
|
||||||
|
solver_dialog.destroy()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
pass
|
||||||
|
solver_dialog = None
|
||||||
|
|
||||||
|
|
||||||
|
def reset_solver_dialog():
|
||||||
|
if solver_dialog:
|
||||||
|
try:
|
||||||
|
solver_dialog.reset()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
pass
|
||||||
|
|
|
@ -102,8 +102,11 @@ class MfxStatusbar:
|
||||||
def updateText(self, **kw):
|
def updateText(self, **kw):
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
label = getattr(self, k + "_label")
|
label = getattr(self, k + "_label")
|
||||||
#label["text"] = str(v)
|
text = unicode(v)
|
||||||
label["text"] = unicode(v)
|
width = label['width']
|
||||||
|
if width and len(text) > width:
|
||||||
|
label['width'] = len(text)
|
||||||
|
label["text"] = text
|
||||||
|
|
||||||
def configLabel(self, name, **kw):
|
def configLabel(self, name, **kw):
|
||||||
if 'fg' in kw:
|
if 'fg' in kw:
|
||||||
|
|
|
@ -371,21 +371,14 @@ class MfxCanvas(Tkinter.Canvas):
|
||||||
|
|
||||||
def _substitute(self, *args):
|
def _substitute(self, *args):
|
||||||
e = Tkinter.Event()
|
e = Tkinter.Event()
|
||||||
|
try:
|
||||||
|
# Tk changed behavior in 8.4.2, returning "??" rather more often.
|
||||||
e.x = int(args[0])
|
e.x = int(args[0])
|
||||||
|
except ValueError:
|
||||||
|
e.x = args[0]
|
||||||
|
try:
|
||||||
e.y = int(args[1])
|
e.y = int(args[1])
|
||||||
|
except ValueError:
|
||||||
|
e.y = args[1]
|
||||||
return (e,)
|
return (e,)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# debug
|
|
||||||
#
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
##import mfxutil; print mfxutil.callername()
|
|
||||||
# ??????
|
|
||||||
Tkinter.Canvas.update(self)
|
|
||||||
|
|
||||||
def update_idletasks(self):
|
|
||||||
##import mfxutil; print mfxutil.callername()
|
|
||||||
Tkinter.Canvas.update_idletasks(self)
|
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,12 @@ __all__ = ['SingleGame_StatsDialog',
|
||||||
'FullLog_StatsDialog',
|
'FullLog_StatsDialog',
|
||||||
'SessionLog_StatsDialog',
|
'SessionLog_StatsDialog',
|
||||||
'Status_StatsDialog',
|
'Status_StatsDialog',
|
||||||
'Top_StatsDialog']
|
'Top_StatsDialog',
|
||||||
|
'ProgressionDialog',
|
||||||
|
]
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
import os, string, sys, types
|
import os
|
||||||
import time
|
import time
|
||||||
import Tile as Tkinter
|
import Tile as Tkinter
|
||||||
import tkFont
|
import tkFont
|
||||||
|
@ -50,7 +52,7 @@ import tkFont
|
||||||
from pysollib.mfxutil import destruct, Struct, kwdefault, KwStruct
|
from pysollib.mfxutil import destruct, Struct, kwdefault, KwStruct
|
||||||
from pysollib.mfxutil import format_time
|
from pysollib.mfxutil import format_time
|
||||||
##from pysollib.util import *
|
##from pysollib.util import *
|
||||||
from pysollib.stats import PysolStatsFormatter
|
from pysollib.stats import PysolStatsFormatter, ProgressionFormatter
|
||||||
from pysollib.settings import TOP_TITLE
|
from pysollib.settings import TOP_TITLE
|
||||||
|
|
||||||
# Toolkit imports
|
# Toolkit imports
|
||||||
|
@ -233,6 +235,7 @@ class TreeFormatter(PysolStatsFormatter):
|
||||||
self.tree = tree
|
self.tree = tree
|
||||||
self.parent_window = parent_window
|
self.parent_window = parent_window
|
||||||
self.font = font
|
self.font = font
|
||||||
|
self.tkfont = tkFont.Font(tree, font)
|
||||||
self.gameid = None
|
self.gameid = None
|
||||||
self.gamenumber = None
|
self.gamenumber = None
|
||||||
self._tabs = None
|
self._tabs = None
|
||||||
|
@ -246,7 +249,8 @@ class TreeFormatter(PysolStatsFormatter):
|
||||||
tw = 20*self.w
|
tw = 20*self.w
|
||||||
##tw = 160
|
##tw = 160
|
||||||
self._tabs = [tw]
|
self._tabs = [tw]
|
||||||
font = tkFont.Font(self.tree, self.font)
|
#font = tkFont.Font(self.tree, self.font)
|
||||||
|
font = self.tkfont
|
||||||
for t in arg[1:]:
|
for t in arg[1:]:
|
||||||
tw = font.measure(t)+20
|
tw = font.measure(t)+20
|
||||||
self._tabs.append(tw)
|
self._tabs.append(tw)
|
||||||
|
@ -604,7 +608,7 @@ class Top_StatsDialog(MfxDialog):
|
||||||
self.createBitmaps(top_frame, kw)
|
self.createBitmaps(top_frame, kw)
|
||||||
|
|
||||||
frame = Tkinter.Frame(top_frame)
|
frame = Tkinter.Frame(top_frame)
|
||||||
frame.pack(expand=Tkinter.YES, fill=Tkinter.BOTH, padx=5, pady=10)
|
frame.pack(expand=Tkinter.YES, fill=Tkinter.BOTH, padx=10, pady=10)
|
||||||
frame.columnconfigure(0, weight=1)
|
frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
if (player in app.stats.games_stats and
|
if (player in app.stats.games_stats and
|
||||||
|
@ -681,3 +685,255 @@ class Top_StatsDialog(MfxDialog):
|
||||||
separatorwidth=2,
|
separatorwidth=2,
|
||||||
)
|
)
|
||||||
return MfxDialog.initKw(self, kw)
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# //
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class ProgressionDialog(MfxDialog):
|
||||||
|
def __init__(self, parent, title, app, player, gameid, **kw):
|
||||||
|
|
||||||
|
font_name = app.getFont('default')
|
||||||
|
font = tkFont.Font(parent, font_name)
|
||||||
|
tkfont = tkFont.Font(parent, font)
|
||||||
|
font_metrics = font.metrics()
|
||||||
|
measure = tkfont.measure
|
||||||
|
self.text_height = font_metrics['linespace']
|
||||||
|
self.text_width = measure('XX.XX.XX')
|
||||||
|
|
||||||
|
self.items = []
|
||||||
|
self.formatter = ProgressionFormatter(app, player, gameid)
|
||||||
|
|
||||||
|
kw = self.initKw(kw)
|
||||||
|
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
|
||||||
|
top_frame, bottom_frame = self.createFrames(kw)
|
||||||
|
self.createBitmaps(top_frame, kw)
|
||||||
|
|
||||||
|
frame = Tkinter.Frame(top_frame)
|
||||||
|
frame.pack(expand=True, fill='both', padx=5, pady=10)
|
||||||
|
frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
# constants
|
||||||
|
self.canvas_width, self.canvas_height = 600, 250
|
||||||
|
if parent.winfo_screenwidth() < 800 or \
|
||||||
|
parent.winfo_screenheight() < 600:
|
||||||
|
self.canvas_width, self.canvas_height = 400, 200
|
||||||
|
self.xmargin, self.ymargin = 10, 10
|
||||||
|
self.graph_dx, self.graph_dy = 10, 10
|
||||||
|
self.played_color = '#ff7ee9'
|
||||||
|
self.won_color = '#00dc28'
|
||||||
|
self.percent_color = 'blue'
|
||||||
|
# create canvas
|
||||||
|
self.canvas = canvas = Tkinter.Canvas(frame, bg='#dfe8ff', bd=0,
|
||||||
|
highlightthickness=1,
|
||||||
|
highlightbackground='black',
|
||||||
|
width=self.canvas_width,
|
||||||
|
height=self.canvas_height)
|
||||||
|
canvas.pack(side='left', padx=5)
|
||||||
|
#
|
||||||
|
dir = os.path.join('images', 'stats')
|
||||||
|
try:
|
||||||
|
fn = app.dataloader.findImage('progression', dir)
|
||||||
|
self.bg_image = loadImage(fn)
|
||||||
|
canvas.create_image(0, 0, image=self.bg_image, anchor='nw')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
#
|
||||||
|
tw = max(measure(_('Games/day')),
|
||||||
|
measure(_('Games/week')),
|
||||||
|
measure(_('% won')))
|
||||||
|
self.left_margin = self.xmargin+tw/2
|
||||||
|
self.right_margin = self.xmargin+tw/2
|
||||||
|
self.top_margin = 15+self.text_height
|
||||||
|
self.bottom_margin = 15+self.text_height+10+self.text_height
|
||||||
|
#
|
||||||
|
x0, y0 = self.left_margin, self.canvas_height-self.bottom_margin
|
||||||
|
x1, y1 = self.canvas_width-self.right_margin, self.top_margin
|
||||||
|
canvas.create_rectangle(x0, y0, x1, y1, fill='white')
|
||||||
|
# horizontal axis
|
||||||
|
canvas.create_line(x0, y0, x1, y0, width=3)
|
||||||
|
|
||||||
|
# left vertical axis
|
||||||
|
canvas.create_line(x0, y0, x0, y1, width=3)
|
||||||
|
t = _('Games/day')
|
||||||
|
self.games_text_id = canvas.create_text(x0-4, y1-4, anchor='s', text=t)
|
||||||
|
|
||||||
|
# right vertical axis
|
||||||
|
canvas.create_line(x1, y0, x1, y1, width=3)
|
||||||
|
canvas.create_text(x1+4, y1-4, anchor='s', text=_('% won'))
|
||||||
|
|
||||||
|
# caption
|
||||||
|
d = self.text_height
|
||||||
|
x, y = self.xmargin, self.canvas_height-self.ymargin
|
||||||
|
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
|
||||||
|
fill=self.played_color)
|
||||||
|
x += d+5
|
||||||
|
canvas.create_text(x, y, anchor='sw', text=_('Played'))
|
||||||
|
x += measure(_('Played'))+20
|
||||||
|
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
|
||||||
|
fill=self.won_color)
|
||||||
|
x += d+5
|
||||||
|
canvas.create_text(x, y, anchor='sw', text=_('Won'))
|
||||||
|
x += measure(_('Won'))+20
|
||||||
|
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
|
||||||
|
fill=self.percent_color)
|
||||||
|
x += d+5
|
||||||
|
canvas.create_text(x, y, anchor='sw', text=_('% won'))
|
||||||
|
|
||||||
|
# right frame
|
||||||
|
right_frame = Tkinter.Frame(frame)
|
||||||
|
right_frame.pack(side='left', fill='x', padx=5)
|
||||||
|
self.all_games_variable = var = Tkinter.StringVar()
|
||||||
|
var.set('all')
|
||||||
|
b = Tkinter.Radiobutton(right_frame, text=_('All games'),
|
||||||
|
variable=var, value='all',
|
||||||
|
command=self.updateGraph,
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
b = Tkinter.Radiobutton(right_frame, text=_('Current game'),
|
||||||
|
variable=var, value='current',
|
||||||
|
command=self.updateGraph,
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
label_frame = Tkinter.LabelFrame(right_frame, text=_('Statistics for'))
|
||||||
|
label_frame.pack(side='top', fill='x', pady=10)
|
||||||
|
self.variable = var = Tkinter.StringVar()
|
||||||
|
var.set('week')
|
||||||
|
for v, t in (
|
||||||
|
('week', _('Last 7 days')),
|
||||||
|
('month', _('Last month')),
|
||||||
|
('year', _('Last year')),
|
||||||
|
('all', _('All time')),
|
||||||
|
):
|
||||||
|
b = Tkinter.Radiobutton(label_frame, text=t, variable=var, value=v,
|
||||||
|
command=self.updateGraph,
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
label_frame = Tkinter.LabelFrame(right_frame, text=_('Show graphs'))
|
||||||
|
label_frame.pack(side='top', fill='x')
|
||||||
|
self.played_graph_var = Tkinter.BooleanVar()
|
||||||
|
self.played_graph_var.set(True)
|
||||||
|
b = Tkinter.Checkbutton(label_frame, text=_('Played'),
|
||||||
|
command=self.updateGraph,
|
||||||
|
variable=self.played_graph_var,
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
self.won_graph_var = Tkinter.BooleanVar()
|
||||||
|
self.won_graph_var.set(True)
|
||||||
|
b = Tkinter.Checkbutton(label_frame, text=_('Won'),
|
||||||
|
command=self.updateGraph,
|
||||||
|
variable=self.won_graph_var,
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
self.percent_graph_var = Tkinter.BooleanVar()
|
||||||
|
self.percent_graph_var.set(True)
|
||||||
|
b = Tkinter.Checkbutton(label_frame, text=_('% won'),
|
||||||
|
command=self.updateGraph,
|
||||||
|
variable=self.percent_graph_var,
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
|
||||||
|
self.updateGraph()
|
||||||
|
|
||||||
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
|
self.mainloop(focus, kw.timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def initKw(self, kw):
|
||||||
|
kw = KwStruct(kw, strings=(_('&OK'),), default=0, separatorwidth=2)
|
||||||
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
|
||||||
|
def updateGraph(self, *args):
|
||||||
|
interval = self.variable.get()
|
||||||
|
canvas = self.canvas
|
||||||
|
if self.items:
|
||||||
|
canvas.delete(*self.items)
|
||||||
|
self.items = []
|
||||||
|
|
||||||
|
all_games = (self.all_games_variable.get() == 'all')
|
||||||
|
result = self.formatter.getResults(interval, all_games)
|
||||||
|
|
||||||
|
if interval in ('week', 'month'):
|
||||||
|
t = _('Games/day')
|
||||||
|
else:
|
||||||
|
t = _('Games/week')
|
||||||
|
canvas.itemconfig(self.games_text_id, text=t)
|
||||||
|
|
||||||
|
graph_width = self.canvas_width-self.left_margin-self.right_margin
|
||||||
|
graph_height = self.canvas_height-self.top_margin-self.bottom_margin
|
||||||
|
dx = (graph_width-2*self.graph_dx)/(len(result)-1)
|
||||||
|
graph_dx = (graph_width-(len(result)-1)*dx)/2
|
||||||
|
dy = (graph_height-self.graph_dy)/5
|
||||||
|
x0, y0 = self.left_margin, self.canvas_height-self.bottom_margin
|
||||||
|
x1, y1 = self.canvas_width-self.right_margin, self.top_margin
|
||||||
|
td = self.text_height/2
|
||||||
|
|
||||||
|
# vertical scale
|
||||||
|
x = x0+graph_dx
|
||||||
|
xx = -100 # coord. of prev. text
|
||||||
|
for res in result:
|
||||||
|
if res[0] is not None and x > xx+self.text_width+4:
|
||||||
|
##id = canvas.create_line(x, y0, x, y0-5, width=3)
|
||||||
|
##self.items.append(id)
|
||||||
|
id = canvas.create_line(x, y0, x, y1, stipple='gray50')
|
||||||
|
self.items.append(id)
|
||||||
|
id = canvas.create_text(x, y0+td, anchor='n', text=res[0])
|
||||||
|
self.items.append(id)
|
||||||
|
xx = x
|
||||||
|
else:
|
||||||
|
id = canvas.create_line(x, y0, x, y0-3, width=1)
|
||||||
|
self.items.append(id)
|
||||||
|
x += dx
|
||||||
|
|
||||||
|
# horizontal scale
|
||||||
|
max_games = max([i[1] for i in result])
|
||||||
|
games_delta = max_games/5+1
|
||||||
|
percent = 0
|
||||||
|
games = 0
|
||||||
|
for y in range(y0, y1, -dy):
|
||||||
|
if y != y0:
|
||||||
|
id = canvas.create_line(x0, y, x1, y, stipple='gray50')
|
||||||
|
self.items.append(id)
|
||||||
|
id = canvas.create_text(x0-td, y, anchor='e', text=str(games))
|
||||||
|
self.items.append(id)
|
||||||
|
id = canvas.create_text(x1+td, y, anchor='w', text=str(percent))
|
||||||
|
self.items.append(id)
|
||||||
|
games += games_delta
|
||||||
|
percent += 20
|
||||||
|
|
||||||
|
# draw result
|
||||||
|
games_resolution = float(dy)/games_delta
|
||||||
|
percent_resolution = float(dy)/20
|
||||||
|
played_coords = []
|
||||||
|
won_coords = []
|
||||||
|
percent_coords = []
|
||||||
|
x = x0+graph_dx
|
||||||
|
for res in result:
|
||||||
|
played, won = res[1], res[2]
|
||||||
|
y = y0 - int(games_resolution*played)
|
||||||
|
played_coords += [x,y]
|
||||||
|
y = y0 - int(games_resolution*won)
|
||||||
|
won_coords += [x,y]
|
||||||
|
if played > 0:
|
||||||
|
percent = int(100.*won/played)
|
||||||
|
else:
|
||||||
|
percent = 0
|
||||||
|
y = y0 - int(percent_resolution*percent)
|
||||||
|
percent_coords += [x,y]
|
||||||
|
x += dx
|
||||||
|
if self.played_graph_var.get():
|
||||||
|
id = canvas.create_line(fill=self.played_color, width=3,
|
||||||
|
*played_coords)
|
||||||
|
self.items.append(id)
|
||||||
|
if self.won_graph_var.get():
|
||||||
|
id = canvas.create_line(fill=self.won_color, width=3,
|
||||||
|
*won_coords)
|
||||||
|
self.items.append(id)
|
||||||
|
if self.percent_graph_var.get():
|
||||||
|
id = canvas.create_line(fill=self.percent_color, width=3,
|
||||||
|
*percent_coords)
|
||||||
|
self.items.append(id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -507,15 +507,10 @@ class MfxScrolledCanvas:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
self.canvas.config(bg=tile.color)
|
self.canvas.config(bg=tile.color)
|
||||||
##app.top.config(bg=tile.color)
|
##app.top.config(bg=tile.color)
|
||||||
color = None
|
|
||||||
else:
|
else:
|
||||||
self.canvas.config(bg=app.top_bg)
|
self.canvas.config(bg=app.top_bg)
|
||||||
##app.top.config(bg=app.top_bg)
|
##app.top.config(bg=app.top_bg)
|
||||||
color = tile.text_color
|
|
||||||
|
|
||||||
if app.opt.use_default_text_color:
|
|
||||||
self.canvas.setTextColor(color)
|
|
||||||
else:
|
|
||||||
self.canvas.setTextColor(app.opt.colors['text'])
|
self.canvas.setTextColor(app.opt.colors['text'])
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -533,7 +528,7 @@ class MfxScrolledCanvas:
|
||||||
def createFrame(self, kw):
|
def createFrame(self, kw):
|
||||||
width = kw.get("width")
|
width = kw.get("width")
|
||||||
height = kw.get("height")
|
height = kw.get("height")
|
||||||
self.frame = Tkinter.Frame(self.parent, width=width, height=height, bg=None)
|
self.frame = Tkinter.Frame(self.parent, width=width, height=height)
|
||||||
|
|
||||||
def createCanvas(self, kw):
|
def createCanvas(self, kw):
|
||||||
self.canvas = MfxCanvas(self.frame, **kw)
|
self.canvas = MfxCanvas(self.frame, **kw)
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
##
|
##
|
||||||
##---------------------------------------------------------------------------##
|
##---------------------------------------------------------------------------##
|
||||||
|
|
||||||
__all__ = ['PysolToolbar'] #, 'TOOLBAR_BUTTONS']
|
__all__ = ['PysolToolbar']
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
import os
|
import os
|
||||||
|
@ -240,6 +240,7 @@ class PysolToolbar(PysolToolbarActions):
|
||||||
widget.hide()
|
widget.hide()
|
||||||
#
|
#
|
||||||
prev_visible = None
|
prev_visible = None
|
||||||
|
last_visible = None
|
||||||
for w in self._widgets:
|
for w in self._widgets:
|
||||||
if isinstance(w, ToolbarSeparator):
|
if isinstance(w, ToolbarSeparator):
|
||||||
if prev_visible is None or isinstance(prev_visible, ToolbarSeparator):
|
if prev_visible is None or isinstance(prev_visible, ToolbarSeparator):
|
||||||
|
@ -248,6 +249,10 @@ class PysolToolbar(PysolToolbarActions):
|
||||||
w.show(orient=self.orient)
|
w.show(orient=self.orient)
|
||||||
if w.visible:
|
if w.visible:
|
||||||
prev_visible = w
|
prev_visible = w
|
||||||
|
if not isinstance(w, ToolbarLabel):
|
||||||
|
last_visible = w
|
||||||
|
if isinstance(last_visible, ToolbarSeparator):
|
||||||
|
last_visible.hide()
|
||||||
|
|
||||||
# util
|
# util
|
||||||
def _loadImage(self, name):
|
def _loadImage(self, name):
|
||||||
|
|
|
@ -48,8 +48,6 @@ class ColorsDialog(MfxDialog):
|
||||||
frame.pack(expand=True, fill='both', padx=5, pady=10)
|
frame.pack(expand=True, fill='both', padx=5, pady=10)
|
||||||
frame.columnconfigure(0, weight=1)
|
frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
self.use_default_var = Tkinter.BooleanVar()
|
|
||||||
self.use_default_var.set(not app.opt.use_default_text_color)
|
|
||||||
self.text_var = Tkinter.StringVar()
|
self.text_var = Tkinter.StringVar()
|
||||||
self.text_var.set(app.opt.colors['text'])
|
self.text_var.set(app.opt.colors['text'])
|
||||||
self.piles_var = Tkinter.StringVar()
|
self.piles_var = Tkinter.StringVar()
|
||||||
|
@ -67,17 +65,9 @@ class ColorsDialog(MfxDialog):
|
||||||
self.not_matching_var = Tkinter.StringVar()
|
self.not_matching_var = Tkinter.StringVar()
|
||||||
self.not_matching_var.set(app.opt.colors['not_matching'])
|
self.not_matching_var.set(app.opt.colors['not_matching'])
|
||||||
#
|
#
|
||||||
c = Tkinter.Checkbutton(frame, variable=self.use_default_var,
|
row = 0
|
||||||
text=_("Text foreground:"), anchor='w')
|
|
||||||
c.grid(row=0, column=0, sticky='we')
|
|
||||||
l = Tkinter.Label(frame, width=10, height=2,
|
|
||||||
bg=self.text_var.get(), textvariable=self.text_var)
|
|
||||||
l.grid(row=0, column=1, padx=5)
|
|
||||||
b = Tkinter.Button(frame, text=_('Change...'), width=10,
|
|
||||||
command=lambda l=l: self.selectColor(l))
|
|
||||||
b.grid(row=0, column=2)
|
|
||||||
row = 1
|
|
||||||
for title, var in (
|
for title, var in (
|
||||||
|
(_('Text foreground:'), self.text_var),
|
||||||
(_('Highlight piles:'), self.piles_var),
|
(_('Highlight piles:'), self.piles_var),
|
||||||
(_('Highlight cards 1:'), self.cards_1_var),
|
(_('Highlight cards 1:'), self.cards_1_var),
|
||||||
(_('Highlight cards 2:'), self.cards_2_var),
|
(_('Highlight cards 2:'), self.cards_2_var),
|
||||||
|
@ -86,7 +76,7 @@ class ColorsDialog(MfxDialog):
|
||||||
(_('Hint arrow:'), self.hintarrow_var),
|
(_('Hint arrow:'), self.hintarrow_var),
|
||||||
(_('Highlight not matching:'), self.not_matching_var),
|
(_('Highlight not matching:'), self.not_matching_var),
|
||||||
):
|
):
|
||||||
Tkinter.Label(frame, text=title, anchor='w'
|
Tkinter.Label(frame, text=title, anchor='w',
|
||||||
).grid(row=row, column=0, sticky='we')
|
).grid(row=row, column=0, sticky='we')
|
||||||
l = Tkinter.Label(frame, width=10, height=2,
|
l = Tkinter.Label(frame, width=10, height=2,
|
||||||
bg=var.get(), textvariable=var)
|
bg=var.get(), textvariable=var)
|
||||||
|
@ -99,7 +89,6 @@ class ColorsDialog(MfxDialog):
|
||||||
focus = self.createButtons(bottom_frame, kw)
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
self.mainloop(focus, kw.timeout)
|
self.mainloop(focus, kw.timeout)
|
||||||
#
|
#
|
||||||
self.use_default_color = not self.use_default_var.get()
|
|
||||||
self.text_color = self.text_var.get()
|
self.text_color = self.text_var.get()
|
||||||
self.piles_color = self.piles_var.get()
|
self.piles_color = self.piles_var.get()
|
||||||
self.cards_1_color = self.cards_1_var.get()
|
self.cards_1_color = self.cards_1_var.get()
|
||||||
|
|
|
@ -114,6 +114,7 @@ class FindCardDialog(Tkinter.Toplevel):
|
||||||
self.groups.append(group)
|
self.groups.append(group)
|
||||||
|
|
||||||
def connectGame(self, game):
|
def connectGame(self, game):
|
||||||
|
self.canvas.delete('all')
|
||||||
self.game = game
|
self.game = game
|
||||||
suits = game.gameinfo.suits
|
suits = game.gameinfo.suits
|
||||||
ranks = game.gameinfo.ranks
|
ranks = game.gameinfo.ranks
|
||||||
|
@ -133,6 +134,7 @@ class FindCardDialog(Tkinter.Toplevel):
|
||||||
w, h = dx*j+2, dy*i+2
|
w, h = dx*j+2, dy*i+2
|
||||||
self.canvas.config(width=w, height=h)
|
self.canvas.config(width=w, height=h)
|
||||||
self.wm_iconname(PACKAGE + " - " + game.getTitleName())
|
self.wm_iconname(PACKAGE + " - " + game.getTitleName())
|
||||||
|
self.wm_geometry('') # cancel user-specified geometry
|
||||||
|
|
||||||
def enterEvent(self, suit, rank, rect, group):
|
def enterEvent(self, suit, rank, rect, group):
|
||||||
##print 'enterEvent', suit, rank, self.busy
|
##print 'enterEvent', suit, rank, self.busy
|
||||||
|
|
|
@ -47,6 +47,7 @@ from pysollib.util import CARDSET
|
||||||
from pysollib.settings import PACKAGE, WIN_SYSTEM
|
from pysollib.settings import PACKAGE, WIN_SYSTEM
|
||||||
from pysollib.settings import TOP_TITLE
|
from pysollib.settings import TOP_TITLE
|
||||||
from pysollib.settings import SELECT_GAME_MENU
|
from pysollib.settings import SELECT_GAME_MENU
|
||||||
|
from pysollib.settings import USE_FREECELL_SOLVER
|
||||||
from pysollib.gamedb import GI
|
from pysollib.gamedb import GI
|
||||||
from pysollib.actions import PysolMenubarActions
|
from pysollib.actions import PysolMenubarActions
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ from soundoptionsdialog import SoundOptionsDialog
|
||||||
from selectcardset import SelectCardsetDialogWithPreview
|
from selectcardset import SelectCardsetDialogWithPreview
|
||||||
from selecttile import SelectTileDialogWithPreview
|
from selecttile import SelectTileDialogWithPreview
|
||||||
from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog
|
from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog
|
||||||
|
from solverdialog import connect_game_solver_dialog
|
||||||
from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar
|
from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar
|
||||||
|
|
||||||
#from toolbar import TOOLBAR_BUTTONS
|
#from toolbar import TOOLBAR_BUTTONS
|
||||||
|
@ -138,25 +140,18 @@ class MfxMenubar(Tkinter.Menu):
|
||||||
#print label, type(label)
|
#print label, type(label)
|
||||||
name = re.sub(r"[^0-9a-zA-Z]", "", label).lower()
|
name = re.sub(r"[^0-9a-zA-Z]", "", label).lower()
|
||||||
label = gettext(label)
|
label = gettext(label)
|
||||||
underline = -1
|
underline = label.find('&')
|
||||||
m = re.search(r"^(.*)\&([^\&].*)$", label)
|
if underline >= 0:
|
||||||
if m:
|
label = label.replace('&', '')
|
||||||
l1, l2 = m.group(1), m.group(2)
|
|
||||||
l1 = re.sub(r"\&\&", "&", l1)
|
|
||||||
l2 = re.sub(r"\&\&", "&", l2)
|
|
||||||
label = l1 + l2
|
|
||||||
underline = len(l1)
|
|
||||||
return name, label, underline
|
return name, label, underline
|
||||||
|
|
||||||
def add(self, itemType, cnf={}):
|
def add(self, itemType, cnf={}):
|
||||||
label = cnf.get("label")
|
label = cnf.get("label")
|
||||||
if label:
|
if label:
|
||||||
name = cnf.get('name')
|
name = cnf.get('name')
|
||||||
try:
|
if name:
|
||||||
del cnf['name'] # TclError: unknown option "-name"
|
del cnf['name'] # TclError: unknown option "-name"
|
||||||
except KeyError:
|
else:
|
||||||
pass
|
|
||||||
if not name:
|
|
||||||
name, label, underline = self.labeltoname(label)
|
name, label, underline = self.labeltoname(label)
|
||||||
cnf["underline"] = cnf.get("underline", underline)
|
cnf["underline"] = cnf.get("underline", underline)
|
||||||
cnf["label"] = label
|
cnf["label"] = label
|
||||||
|
@ -320,6 +315,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
connect_game_find_card_dialog(game)
|
connect_game_find_card_dialog(game)
|
||||||
else:
|
else:
|
||||||
destroy_find_card_dialog()
|
destroy_find_card_dialog()
|
||||||
|
connect_game_solver_dialog(game)
|
||||||
|
|
||||||
# create a GTK-like path
|
# create a GTK-like path
|
||||||
def _addPath(self, path, menu, index, submenu):
|
def _addPath(self, path, menu, index, submenu):
|
||||||
|
@ -368,7 +364,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
submenu = MfxMenu(menu, label=n_("Fa&vorite games"))
|
submenu = MfxMenu(menu, label=n_("Fa&vorite games"))
|
||||||
menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor)
|
menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor)
|
||||||
menu.add_command(label=n_("R&emove from favorites"), command=self.mDelFavor)
|
menu.add_command(label=n_("Remove &from favorites"), command=self.mDelFavor)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O")
|
menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O")
|
||||||
menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S")
|
menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S")
|
||||||
|
@ -411,7 +407,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P")
|
menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P")
|
||||||
#menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P")
|
#menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P")
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("S&tatus..."), command=self.mStatus, accelerator="T")
|
menu.add_command(label=n_("S&tatus..."), command=self.mStatus, accelerator=m+"Y")
|
||||||
menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment)
|
menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
submenu = MfxMenu(menu, label=n_("&Statistics"))
|
submenu = MfxMenu(menu, label=n_("&Statistics"))
|
||||||
|
@ -422,6 +418,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
submenu.add_command(label=n_("Full log..."), command=lambda self=self: self.mPlayerStats(mode=103))
|
submenu.add_command(label=n_("Full log..."), command=lambda self=self: self.mPlayerStats(mode=103))
|
||||||
submenu.add_separator()
|
submenu.add_separator()
|
||||||
submenu.add_command(label=TOP_TITLE+"...", command=self.mTop10, accelerator=m+"T")
|
submenu.add_command(label=TOP_TITLE+"...", command=self.mTop10, accelerator=m+"T")
|
||||||
|
submenu.add_command(label=n_("Progression..."), command=lambda self=self: self.mPlayerStats(mode=107))
|
||||||
submenu = MfxMenu(menu, label=n_("D&emo statistics"))
|
submenu = MfxMenu(menu, label=n_("D&emo statistics"))
|
||||||
submenu.add_command(label=n_("Current game..."), command=lambda self=self: self.mPlayerStats(mode=1101))
|
submenu.add_command(label=n_("Current game..."), command=lambda self=self: self.mPlayerStats(mode=1101))
|
||||||
submenu.add_command(label=n_("All games..."), command=lambda self=self: self.mPlayerStats(mode=1102))
|
submenu.add_command(label=n_("All games..."), command=lambda self=self: self.mPlayerStats(mode=1102))
|
||||||
|
@ -429,12 +426,16 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu = MfxMenu(self.__menubar, label=n_("&Assist"))
|
menu = MfxMenu(self.__menubar, label=n_("&Assist"))
|
||||||
menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H")
|
menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H")
|
||||||
menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I")
|
menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I")
|
||||||
menu.add_command(label=n_("Find card"), command=self.mFindCard, accelerator="F")
|
menu.add_command(label=n_("&Find card"), command=self.mFindCard, accelerator="F3")
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D")
|
menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D")
|
||||||
menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo)
|
menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo)
|
||||||
|
if USE_FREECELL_SOLVER:
|
||||||
|
menu.add_command(label=n_("&Solver (experimental)"), command=self.mSolver)
|
||||||
|
else:
|
||||||
|
menu.add_command(label=n_("&Solver (experimental)"), command=self.mSolver, state=Tkinter.DISABLED)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("Piles description"), command=self.mStackDesk, accelerator="F2")
|
menu.add_command(label=n_("&Piles description"), command=self.mStackDesk, accelerator="F2")
|
||||||
|
|
||||||
if self.progress: self.progress.update(step=1)
|
if self.progress: self.progress.update(step=1)
|
||||||
|
|
||||||
|
@ -478,10 +479,11 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks)
|
submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks)
|
||||||
submenu = MfxMenu(menu, label=n_("A&nimations"))
|
submenu = MfxMenu(menu, label=n_("A&nimations"))
|
||||||
submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Timer based"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Very fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Medium"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations)
|
||||||
submenu.add_radiobutton(label=n_("&Very slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations)
|
submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations)
|
||||||
|
submenu.add_radiobutton(label=n_("V&ery slow"), variable=self.tkopt.animations, value=5, command=self.mOptAnimations)
|
||||||
submenu.add_separator()
|
submenu.add_separator()
|
||||||
submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation)
|
submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation)
|
||||||
if Image:
|
if Image:
|
||||||
|
@ -527,15 +529,13 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
ctrl = "Control-"
|
ctrl = "Control-"
|
||||||
if sys.platform == "darwin": ctrl = "Command-"
|
if sys.platform == "darwin": ctrl = "Command-"
|
||||||
self._bindKey("", "n", self.mNewGame)
|
self._bindKey("", "n", self.mNewGame)
|
||||||
self._bindKey("", "g", self.mSelectGameDialog)
|
self._bindKey(ctrl, "w", self.mSelectGameDialog)
|
||||||
self._bindKey("", "v", self.mSelectGameDialogWithPreview)
|
self._bindKey(ctrl, "v", self.mSelectGameDialogWithPreview)
|
||||||
self._bindKey(ctrl, "r", lambda e, self=self: self.mSelectRandomGame())
|
self._bindKey(ctrl, "r", lambda e, self=self: self.mSelectRandomGame())
|
||||||
self._bindKey(ctrl, "m", self.mSelectGameById)
|
self._bindKey(ctrl, "m", self.mSelectGameById)
|
||||||
self._bindKey(ctrl, "n", self.mNewGameWithNextId)
|
self._bindKey(ctrl, "n", self.mNewGameWithNextId)
|
||||||
self._bindKey(ctrl, "o", self.mOpen)
|
self._bindKey(ctrl, "o", self.mOpen)
|
||||||
##self._bindKey("", "F3", self.mOpen) # undocumented
|
|
||||||
self._bindKey(ctrl, "s", self.mSave)
|
self._bindKey(ctrl, "s", self.mSave)
|
||||||
##self._bindKey("", "F2", self.mSaveAs) # undocumented
|
|
||||||
self._bindKey(ctrl, "q", self.mQuit)
|
self._bindKey(ctrl, "q", self.mQuit)
|
||||||
self._bindKey("", "z", self.mUndo)
|
self._bindKey("", "z", self.mUndo)
|
||||||
self._bindKey("", "BackSpace", self.mUndo) # undocumented
|
self._bindKey("", "BackSpace", self.mUndo) # undocumented
|
||||||
|
@ -543,14 +543,14 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
self._bindKey("", "r", self.mRedo)
|
self._bindKey("", "r", self.mRedo)
|
||||||
self._bindKey(ctrl, "g", self.mRestart)
|
self._bindKey(ctrl, "g", self.mRestart)
|
||||||
self._bindKey("", "space", self.mDeal) # undocumented
|
self._bindKey("", "space", self.mDeal) # undocumented
|
||||||
self._bindKey("", "t", self.mStatus)
|
self._bindKey(ctrl, "y", self.mStatus)
|
||||||
self._bindKey(ctrl, "t", self.mTop10)
|
self._bindKey(ctrl, "t", self.mTop10)
|
||||||
self._bindKey("", "h", self.mHint)
|
self._bindKey("", "h", self.mHint)
|
||||||
self._bindKey(ctrl, "h", self.mHint1) # undocumented
|
self._bindKey(ctrl, "h", self.mHint1) # undocumented
|
||||||
##self._bindKey("", "Shift_L", self.mHighlightPiles)
|
##self._bindKey("", "Shift_L", self.mHighlightPiles)
|
||||||
##self._bindKey("", "Shift_R", self.mHighlightPiles)
|
##self._bindKey("", "Shift_R", self.mHighlightPiles)
|
||||||
self._bindKey("", "i", self.mHighlightPiles)
|
self._bindKey("", "i", self.mHighlightPiles)
|
||||||
self._bindKey("", "f", self.mFindCard)
|
self._bindKey("", "F3", self.mFindCard)
|
||||||
self._bindKey(ctrl, "d", self.mDemo)
|
self._bindKey(ctrl, "d", self.mDemo)
|
||||||
self._bindKey(ctrl, "e", self.mSelectCardsetDialog)
|
self._bindKey(ctrl, "e", self.mSelectCardsetDialog)
|
||||||
self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented
|
self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented
|
||||||
|
@ -593,19 +593,19 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
#
|
#
|
||||||
|
|
||||||
def _bindKey(self, modifier, key, func):
|
def _bindKey(self, modifier, key, func):
|
||||||
if 0 and not modifier and len(key) == 1:
|
## if 0 and not modifier and len(key) == 1:
|
||||||
self.__keybindings[key.lower()] = func
|
## self.__keybindings[key.lower()] = func
|
||||||
self.__keybindings[key.upper()] = func
|
## self.__keybindings[key.upper()] = func
|
||||||
return
|
## return
|
||||||
|
if not modifier and len(key) == 1:
|
||||||
|
# ignore Ctrl/Shift/Alt
|
||||||
|
func = lambda e, func=func: e.state == 0 and func(e)
|
||||||
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
||||||
try:
|
|
||||||
bind(self.top, sequence, func)
|
bind(self.top, sequence, func)
|
||||||
if len(key) == 1 and key != key.upper():
|
if len(key) == 1 and key != key.upper():
|
||||||
key = key.upper()
|
key = key.upper()
|
||||||
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
sequence = "<" + modifier + "KeyPress-" + key + ">"
|
||||||
bind(self.top, sequence, func)
|
bind(self.top, sequence, func)
|
||||||
except:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def _keyPressHandler(self, event):
|
def _keyPressHandler(self, event):
|
||||||
|
@ -617,10 +617,10 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
if event.char: # ignore Ctrl/Shift/etc.
|
if event.char: # ignore Ctrl/Shift/etc.
|
||||||
self.game.demo.keypress = event.char
|
self.game.demo.keypress = event.char
|
||||||
r = EVENT_HANDLED
|
r = EVENT_HANDLED
|
||||||
func = self.__keybindings.get(event.char)
|
## func = self.__keybindings.get(event.char)
|
||||||
if func and (event.state & ~2) == 0:
|
## if func and (event.state & ~2) == 0:
|
||||||
func(event)
|
## func(event)
|
||||||
r = EVENT_HANDLED
|
## r = EVENT_HANDLED
|
||||||
return r
|
return r
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -632,9 +632,11 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName())
|
games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName())
|
||||||
##games = tuple(games)
|
##games = tuple(games)
|
||||||
###menu = MfxMenu(menu, label="Select &game")
|
###menu = MfxMenu(menu, label="Select &game")
|
||||||
menu.add_command(label=n_("All &games..."), accelerator="G",
|
m = "Ctrl-"
|
||||||
|
if sys.platform == "darwin": m = "Cmd-"
|
||||||
|
menu.add_command(label=n_("All &games..."), accelerator=m+"W",
|
||||||
command=self.mSelectGameDialog)
|
command=self.mSelectGameDialog)
|
||||||
menu.add_command(label=n_("Playable pre&view..."), accelerator="V",
|
menu.add_command(label=n_("Playable pre&view..."), accelerator=m+"V",
|
||||||
command=self.mSelectGameDialogWithPreview)
|
command=self.mSelectGameDialogWithPreview)
|
||||||
if not SELECT_GAME_MENU:
|
if not SELECT_GAME_MENU:
|
||||||
return
|
return
|
||||||
|
@ -779,13 +781,19 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
gi = games[i]
|
gi = games[i]
|
||||||
columnbreak = i > 0 and (i % cb) == 0
|
columnbreak = i > 0 and (i % cb) == 0
|
||||||
if short_name:
|
if short_name:
|
||||||
label = gi.short_name
|
label = gettext(gi.short_name)
|
||||||
else:
|
else:
|
||||||
label = gi.name
|
label = gettext(gi.name)
|
||||||
menu.add_radiobutton(command=command, variable=variable,
|
## menu.add_radiobutton(command=command, variable=variable,
|
||||||
columnbreak=columnbreak,
|
## columnbreak=columnbreak,
|
||||||
value=gi.id, label=label, name=None)
|
## value=gi.id, label=label, name=None)
|
||||||
|
# optimized by inlining
|
||||||
|
menu.tk.call((menu._w, 'add', 'radiobutton') +
|
||||||
|
menu._options({'command': command,
|
||||||
|
'variable': variable,
|
||||||
|
'columnbreak': columnbreak,
|
||||||
|
'value': gi.id,
|
||||||
|
'label': label}))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Select Game menu actions
|
# Select Game menu actions
|
||||||
|
@ -1149,7 +1157,6 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
self._cancelDrag()
|
self._cancelDrag()
|
||||||
self.game.endGame(bookmark=1)
|
self.game.endGame(bookmark=1)
|
||||||
self.game.quitGame(bookmark=1)
|
self.game.quitGame(bookmark=1)
|
||||||
self.app.opt.games_geometry = {} # clear saved games geometry
|
|
||||||
|
|
||||||
def _mOptCardback(self, index):
|
def _mOptCardback(self, index):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
|
@ -1171,10 +1178,6 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
def mOptChangeCardback(self, *event):
|
def mOptChangeCardback(self, *event):
|
||||||
self._mOptCardback(self.app.cardset.backindex + 1)
|
self._mOptCardback(self.app.cardset.backindex + 1)
|
||||||
|
|
||||||
## def mOptTableTile(self, *event):
|
|
||||||
## if self._cancelDrag(break_pause=False): return
|
|
||||||
## self._mOptTableTile(self.tkopt.tabletile.get())
|
|
||||||
|
|
||||||
def mOptChangeTableTile(self, *event):
|
def mOptChangeTableTile(self, *event):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
n = self.app.tabletile_manager.len()
|
n = self.app.tabletile_manager.len()
|
||||||
|
@ -1337,4 +1340,3 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
else:
|
else:
|
||||||
if self._cancelDrag(break_pause=True): return
|
if self._cancelDrag(break_pause=True): return
|
||||||
self.game.showStackDesc()
|
self.game.showStackDesc()
|
||||||
|
|
||||||
|
|
|
@ -437,7 +437,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
destruct(self.preview_app)
|
destruct(self.preview_app)
|
||||||
self.preview_app = None
|
self.preview_app = None
|
||||||
|
|
||||||
def updatePreview(self, gameid, animations=5):
|
def updatePreview(self, gameid, animations=10):
|
||||||
if gameid == self.preview_key:
|
if gameid == self.preview_key:
|
||||||
return
|
return
|
||||||
self.deletePreview()
|
self.deletePreview()
|
||||||
|
@ -504,7 +504,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
#
|
#
|
||||||
self.preview_app.audio = self.app.audio
|
self.preview_app.audio = self.app.audio
|
||||||
if self.app.opt.animations:
|
if self.app.opt.animations:
|
||||||
self.preview_app.opt.animations = 5
|
self.preview_app.opt.animations = 10
|
||||||
else:
|
else:
|
||||||
self.preview_app.opt.animations = 0
|
self.preview_app.opt.animations = 0
|
||||||
# save seed
|
# save seed
|
||||||
|
@ -562,13 +562,12 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
('percent', percent),
|
('percent', percent),
|
||||||
):
|
):
|
||||||
title_label, text_label = self.info_labels[n]
|
title_label, text_label = self.info_labels[n]
|
||||||
if t == '':
|
if t in ('', None):
|
||||||
title_label.grid_remove()
|
title_label.grid_remove()
|
||||||
text_label.grid_remove()
|
text_label.grid_remove()
|
||||||
else:
|
else:
|
||||||
title_label.grid()
|
title_label.grid()
|
||||||
text_label.grid()
|
text_label.grid()
|
||||||
text_label.config(text=t)
|
text_label.config(text=t)
|
||||||
#self.info_labels[n].config(text=t)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
333
pysollib/tk/solverdialog.py
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
##
|
||||||
|
## PySol -- a Python Solitaire game
|
||||||
|
##
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with this program; see the file COPYING.
|
||||||
|
## If not, write to the Free Software Foundation, Inc.,
|
||||||
|
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
##
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
#'SolverDialog',
|
||||||
|
'create_solver_dialog',
|
||||||
|
'connect_game_solver_dialog',
|
||||||
|
'destroy_solver_dialog',
|
||||||
|
'reset_solver_dialog',
|
||||||
|
]
|
||||||
|
|
||||||
|
# imports
|
||||||
|
import os, sys
|
||||||
|
import Tkinter
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
# PySol imports
|
||||||
|
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct
|
||||||
|
from pysollib.settings import PACKAGE
|
||||||
|
|
||||||
|
# Toolkit imports
|
||||||
|
from tkconst import EVENT_HANDLED, EVENT_PROPAGATE
|
||||||
|
from tkwidget import MfxDialog
|
||||||
|
from tkutil import bind, unbind_destroy
|
||||||
|
|
||||||
|
gettext = _
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# //
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class SolverDialog(MfxDialog):
|
||||||
|
|
||||||
|
def __init__(self, parent, app, **kw):
|
||||||
|
self.parent = parent
|
||||||
|
self.app = app
|
||||||
|
title = PACKAGE+' - FreeCell Solver'
|
||||||
|
kw = self.initKw(kw)
|
||||||
|
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
|
||||||
|
top_frame, bottom_frame = self.createFrames(kw)
|
||||||
|
self.createBitmaps(top_frame, kw)
|
||||||
|
#
|
||||||
|
self.solving_methods = {
|
||||||
|
'A*': 'a-star',
|
||||||
|
'Breadth-First Search': 'bfs',
|
||||||
|
'Depth-First Search': 'dfs', # default
|
||||||
|
'A randomized DFS': 'random-dfs',
|
||||||
|
'"Soft" DFS': 'soft-dfs',
|
||||||
|
}
|
||||||
|
self.games = {} # key: gamename; value: gameid
|
||||||
|
|
||||||
|
#
|
||||||
|
frame = Tkinter.Frame(top_frame)
|
||||||
|
frame.pack(expand=True, fill='both', padx=4, pady=4)
|
||||||
|
frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
#
|
||||||
|
row = 0
|
||||||
|
Tkinter.Label(frame, text=_('Game:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
games = app.getGamesForSolver()
|
||||||
|
gamenames = ['']
|
||||||
|
for id in games:
|
||||||
|
name = app.getGameTitleName(id)
|
||||||
|
name = gettext(name)
|
||||||
|
gamenames.append(name)
|
||||||
|
self.games[name] = id
|
||||||
|
gamenames.sort()
|
||||||
|
self.gamenames = gamenames
|
||||||
|
self.games_var = var = Tkinter.StringVar()
|
||||||
|
om = Tkinter.OptionMenu(frame, var, command=self.gameSelected,
|
||||||
|
*gamenames)
|
||||||
|
om.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
n = len(gamenames)
|
||||||
|
cb_max = int(self.top.winfo_screenheight()/23)
|
||||||
|
cb_max = n / (n/cb_max+1)
|
||||||
|
for i in xrange(cb_max, n, cb_max):
|
||||||
|
om['menu'].entryconfig(i, columnbreak=True)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
Tkinter.Label(frame, text=_('Solving method:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
##sm = self.solving_methods.values()
|
||||||
|
##sm.sort()
|
||||||
|
sm = ['A*', 'Breadth-First Search', 'Depth-First Search',
|
||||||
|
'A randomized DFS', '"Soft" DFS']
|
||||||
|
self.solving_method_var = var = Tkinter.StringVar()
|
||||||
|
var.set('Depth-First Search')
|
||||||
|
om = Tkinter.OptionMenu(frame, var, *sm)
|
||||||
|
om.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
Tkinter.Label(frame, text=_('Preset:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
presets = [
|
||||||
|
'none',
|
||||||
|
'abra-kadabra',
|
||||||
|
'cool-jives',
|
||||||
|
'crooked-nose',
|
||||||
|
'fools-gold',
|
||||||
|
'good-intentions',
|
||||||
|
'hello-world',
|
||||||
|
'john-galt-line',
|
||||||
|
'rin-tin-tin',
|
||||||
|
'yellow-brick-road',
|
||||||
|
]
|
||||||
|
self.presets = presets
|
||||||
|
self.preset_var = var = Tkinter.StringVar()
|
||||||
|
var.set('none')
|
||||||
|
om = Tkinter.OptionMenu(frame, var, *presets)
|
||||||
|
om.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
self.max_iters_var = Tkinter.IntVar()
|
||||||
|
self.max_iters_var.set(10e4)
|
||||||
|
Tkinter.Label(frame, text=_('Max iterations:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
spin = Tkinter.Spinbox(frame, bg='white', from_=1000, to=10e6,
|
||||||
|
increment=1000, textvariable=self.max_iters_var)
|
||||||
|
spin.grid(row=row, column=1, sticky='w', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
self.max_depth_var = Tkinter.IntVar()
|
||||||
|
self.max_depth_var.set(1000)
|
||||||
|
Tkinter.Label(frame, text=_('Max depth:'), anchor='w'
|
||||||
|
).grid(row=row, column=0, sticky='ew', padx=2, pady=2)
|
||||||
|
spin = Tkinter.Spinbox(frame, bg='white', from_=100, to=10000,
|
||||||
|
increment=100, textvariable=self.max_depth_var)
|
||||||
|
spin.grid(row=row, column=1, sticky='w', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
row += 1
|
||||||
|
self.progress_var = Tkinter.BooleanVar()
|
||||||
|
self.progress_var.set(True)
|
||||||
|
w = Tkinter.Checkbutton(frame, variable=self.progress_var,
|
||||||
|
text=_('Show progress'), anchor='w')
|
||||||
|
w.grid(row=row, column=0, columnspan=2, sticky='ew', padx=2, pady=2)
|
||||||
|
|
||||||
|
#
|
||||||
|
label_frame = Tkinter.LabelFrame(top_frame, text=_('Progress'))
|
||||||
|
label_frame.pack(expand=True, fill='both', padx=6, pady=2)
|
||||||
|
#label_frame.columnconfigure(0, weight=1)
|
||||||
|
label_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
#
|
||||||
|
frow = 0
|
||||||
|
Tkinter.Label(label_frame, text=_('Iteration:'), anchor='w'
|
||||||
|
).grid(row=frow, column=0, sticky='ew', padx=4, pady=2)
|
||||||
|
lb = Tkinter.Label(label_frame, anchor='w')
|
||||||
|
lb.grid(row=frow, column=1, sticky='ew', padx=4, pady=2)
|
||||||
|
self.iter_label = lb
|
||||||
|
frow += 1
|
||||||
|
Tkinter.Label(label_frame, text=_('Depth:'), anchor='w'
|
||||||
|
).grid(row=frow, column=0, sticky='ew', padx=4, pady=2)
|
||||||
|
lb = Tkinter.Label(label_frame, anchor='w')
|
||||||
|
lb.grid(row=frow, column=1, sticky='ew', padx=4, pady=2)
|
||||||
|
self.depth_label = lb
|
||||||
|
frow += 1
|
||||||
|
Tkinter.Label(label_frame, text=_('Stored-States:'), anchor='w'
|
||||||
|
).grid(row=frow, column=0, sticky='ew', padx=4, pady=2)
|
||||||
|
lb = Tkinter.Label(label_frame, anchor='w')
|
||||||
|
lb.grid(row=frow, column=1, sticky='ew', padx=4, pady=2)
|
||||||
|
self.states_label = lb
|
||||||
|
|
||||||
|
#
|
||||||
|
lb = Tkinter.Label(top_frame, anchor='w')
|
||||||
|
lb.pack(expand=True, fill='x', padx=6, pady=4)
|
||||||
|
self.result_label = lb
|
||||||
|
|
||||||
|
#
|
||||||
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
|
self.mainloop(focus, kw.timeout, transient=False)
|
||||||
|
|
||||||
|
self.start_button = self.buttons[0]
|
||||||
|
self.play_button = self.buttons[1]
|
||||||
|
|
||||||
|
#
|
||||||
|
self._reset()
|
||||||
|
self.connectGame(self.app.game)
|
||||||
|
|
||||||
|
def initKw(self, kw):
|
||||||
|
strings=[_('&Start'), _('&Play'), _('&New'), _('&Close'),]
|
||||||
|
kw = KwStruct(kw,
|
||||||
|
strings=strings,
|
||||||
|
default=0,
|
||||||
|
)
|
||||||
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
def mDone(self, button):
|
||||||
|
if button == 0:
|
||||||
|
self.startSolving()
|
||||||
|
elif button == 1:
|
||||||
|
self.startPlay()
|
||||||
|
elif button == 2:
|
||||||
|
self.app.menubar.mNewGame()
|
||||||
|
elif button == 3:
|
||||||
|
global solver_dialog
|
||||||
|
solver_dialog = None
|
||||||
|
self.destroy()
|
||||||
|
return EVENT_HANDLED
|
||||||
|
|
||||||
|
def mCancel(self, *event):
|
||||||
|
return self.mDone(3)
|
||||||
|
|
||||||
|
def wmDeleteWindow(self, *event):
|
||||||
|
return self.mDone(3)
|
||||||
|
|
||||||
|
def gameSelected(self, *event):
|
||||||
|
name = self.games_var.get()
|
||||||
|
if not name:
|
||||||
|
return
|
||||||
|
id = self.games[name]
|
||||||
|
self.app.menubar._mSelectGame(id)
|
||||||
|
|
||||||
|
def connectGame(self, game):
|
||||||
|
name = self.app.getGameTitleName(game.id)
|
||||||
|
name = gettext(name)
|
||||||
|
if name in self.gamenames:
|
||||||
|
self.start_button.config(state='normal')
|
||||||
|
i = self.gamenames.index(name)
|
||||||
|
self.games_var.set(name)
|
||||||
|
else:
|
||||||
|
self.start_button.config(state='disabled')
|
||||||
|
self.games_var.set('')
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
self.setText(iter='', depth='', states='')
|
||||||
|
self.result_label['text'] = ''
|
||||||
|
self.top.update_idletasks()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
|
||||||
|
def startSolving(self):
|
||||||
|
self._reset()
|
||||||
|
game = self.app.game
|
||||||
|
solver = game.Solver_Class(game, self) # create solver instance
|
||||||
|
game.solver = solver
|
||||||
|
method = self.solving_method_var.get()
|
||||||
|
method = self.solving_methods[method]
|
||||||
|
preset = self.preset_var.get()
|
||||||
|
max_iters = self.max_iters_var.get()
|
||||||
|
max_depth = self.max_depth_var.get()
|
||||||
|
progress = self.progress_var.get()
|
||||||
|
solver.config(method=method, preset=preset, max_iters=max_iters,
|
||||||
|
max_depth=max_depth, progress=progress)
|
||||||
|
solver.computeHints()
|
||||||
|
hints_len = len(solver.hints)-1
|
||||||
|
if hints_len > 0:
|
||||||
|
self.result_label['text'] = _('This game is solveable in %s moves.') % hints_len
|
||||||
|
self.play_button.config(state='normal')
|
||||||
|
else:
|
||||||
|
self.result_label['text'] = _('I could not solve this game.')
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
|
||||||
|
def startPlay(self):
|
||||||
|
self.play_button.config(state='disabled')
|
||||||
|
self.app.top.tkraise()
|
||||||
|
self.app.top.update_idletasks()
|
||||||
|
self.app.top.update()
|
||||||
|
self.app.game.startDemo(level=3)
|
||||||
|
|
||||||
|
def setText(self, **kw):
|
||||||
|
if 'iter' in kw:
|
||||||
|
self.iter_label['text'] = kw['iter']
|
||||||
|
if 'depth' in kw:
|
||||||
|
self.depth_label['text'] = kw['depth']
|
||||||
|
if 'states' in kw:
|
||||||
|
self.states_label['text'] = kw['states']
|
||||||
|
self.top.update_idletasks()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
solver_dialog = None
|
||||||
|
|
||||||
|
def create_solver_dialog(parent, game):
|
||||||
|
global solver_dialog
|
||||||
|
try:
|
||||||
|
solver_dialog.top.wm_deiconify()
|
||||||
|
solver_dialog.top.tkraise()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
solver_dialog = SolverDialog(parent, game)
|
||||||
|
|
||||||
|
def connect_game_solver_dialog(game):
|
||||||
|
try:
|
||||||
|
solver_dialog.connectGame(game)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def destroy_solver_dialog():
|
||||||
|
global solver_dialog
|
||||||
|
try:
|
||||||
|
solver_dialog.destroy()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
pass
|
||||||
|
solver_dialog = None
|
||||||
|
|
||||||
|
|
||||||
|
def reset_solver_dialog():
|
||||||
|
if solver_dialog:
|
||||||
|
try:
|
||||||
|
solver_dialog.reset()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
pass
|
||||||
|
|
|
@ -121,7 +121,7 @@ class SoundOptionsDialog(MfxDialog):
|
||||||
if app.audio.CAN_PLAY_MUSIC: # and app.startup_opt.sound_mode > 0:
|
if app.audio.CAN_PLAY_MUSIC: # and app.startup_opt.sound_mode > 0:
|
||||||
row += 1
|
row += 1
|
||||||
w = Tkinter.Label(frame, text=_('Sample volume:'))
|
w = Tkinter.Label(frame, text=_('Sample volume:'))
|
||||||
w.grid(row=row, column=0, sticky='ew')
|
w.grid(row=row, column=0, sticky='w', padx=5)
|
||||||
w = Tkinter.Scale(frame, from_=0, to=128, resolution=1,
|
w = Tkinter.Scale(frame, from_=0, to=128, resolution=1,
|
||||||
orient='horizontal', takefocus=0,
|
orient='horizontal', takefocus=0,
|
||||||
length="3i", #label=_('Sample volume'),
|
length="3i", #label=_('Sample volume'),
|
||||||
|
@ -134,7 +134,7 @@ class SoundOptionsDialog(MfxDialog):
|
||||||
orient='horizontal', takefocus=0,
|
orient='horizontal', takefocus=0,
|
||||||
length="3i", #label=_('Music volume'),
|
length="3i", #label=_('Music volume'),
|
||||||
variable=self.music_volume)
|
variable=self.music_volume)
|
||||||
w.grid(row=row, column=1, sticky='w', padx=5)
|
w.grid(row=row, column=1, sticky='ew', padx=5)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# remove "Apply" button
|
# remove "Apply" button
|
||||||
|
|
|
@ -116,8 +116,11 @@ class MfxStatusbar:
|
||||||
def updateText(self, **kw):
|
def updateText(self, **kw):
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
label = getattr(self, k + "_label")
|
label = getattr(self, k + "_label")
|
||||||
#label["text"] = str(v)
|
text = unicode(v)
|
||||||
label["text"] = unicode(v)
|
width = label['width']
|
||||||
|
if width and len(text) > width:
|
||||||
|
label['width'] = len(text)
|
||||||
|
label["text"] = text
|
||||||
|
|
||||||
def configLabel(self, name, **kw):
|
def configLabel(self, name, **kw):
|
||||||
label = getattr(self, name + "_label")
|
label = getattr(self, name + "_label")
|
||||||
|
|
|
@ -370,21 +370,14 @@ class MfxCanvas(Tkinter.Canvas):
|
||||||
|
|
||||||
def _substitute(self, *args):
|
def _substitute(self, *args):
|
||||||
e = Tkinter.Event()
|
e = Tkinter.Event()
|
||||||
|
try:
|
||||||
|
# Tk changed behavior in 8.4.2, returning "??" rather more often.
|
||||||
e.x = int(args[0])
|
e.x = int(args[0])
|
||||||
|
except ValueError:
|
||||||
|
e.x = args[0]
|
||||||
|
try:
|
||||||
e.y = int(args[1])
|
e.y = int(args[1])
|
||||||
|
except ValueError:
|
||||||
|
e.y = args[1]
|
||||||
return (e,)
|
return (e,)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# debug
|
|
||||||
#
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
##import mfxutil; print mfxutil.callername()
|
|
||||||
# ??????
|
|
||||||
Tkinter.Canvas.update(self)
|
|
||||||
|
|
||||||
def update_idletasks(self):
|
|
||||||
##import mfxutil; print mfxutil.callername()
|
|
||||||
Tkinter.Canvas.update_idletasks(self)
|
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,9 @@ __all__ = ['SingleGame_StatsDialog',
|
||||||
'FullLog_StatsDialog',
|
'FullLog_StatsDialog',
|
||||||
'SessionLog_StatsDialog',
|
'SessionLog_StatsDialog',
|
||||||
'Status_StatsDialog',
|
'Status_StatsDialog',
|
||||||
'Top_StatsDialog']
|
'Top_StatsDialog',
|
||||||
|
'ProgressionDialog',
|
||||||
|
]
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
import os, string, sys, types
|
import os, string, sys, types
|
||||||
|
@ -49,7 +51,7 @@ import Tkinter, tkFont
|
||||||
from pysollib.mfxutil import destruct, Struct, kwdefault, KwStruct
|
from pysollib.mfxutil import destruct, Struct, kwdefault, KwStruct
|
||||||
from pysollib.mfxutil import format_time
|
from pysollib.mfxutil import format_time
|
||||||
##from pysollib.util import *
|
##from pysollib.util import *
|
||||||
from pysollib.stats import PysolStatsFormatter
|
from pysollib.stats import PysolStatsFormatter, ProgressionFormatter
|
||||||
from pysollib.settings import TOP_TITLE
|
from pysollib.settings import TOP_TITLE
|
||||||
|
|
||||||
# Toolkit imports
|
# Toolkit imports
|
||||||
|
@ -720,7 +722,7 @@ class Top_StatsDialog(MfxDialog):
|
||||||
self.createBitmaps(top_frame, kw)
|
self.createBitmaps(top_frame, kw)
|
||||||
|
|
||||||
frame = Tkinter.Frame(top_frame)
|
frame = Tkinter.Frame(top_frame)
|
||||||
frame.pack(expand=Tkinter.YES, fill=Tkinter.BOTH, padx=5, pady=10)
|
frame.pack(expand=Tkinter.YES, fill=Tkinter.BOTH, padx=10, pady=10)
|
||||||
frame.columnconfigure(0, weight=1)
|
frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
if (player in app.stats.games_stats and
|
if (player in app.stats.games_stats and
|
||||||
|
@ -797,3 +799,266 @@ class Top_StatsDialog(MfxDialog):
|
||||||
separatorwidth=2,
|
separatorwidth=2,
|
||||||
)
|
)
|
||||||
return MfxDialog.initKw(self, kw)
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# //
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class ProgressionDialog(MfxDialog):
|
||||||
|
def __init__(self, parent, title, app, player, gameid, **kw):
|
||||||
|
|
||||||
|
font_name = app.getFont('default')
|
||||||
|
font = tkFont.Font(parent, font_name)
|
||||||
|
tkfont = tkFont.Font(parent, font)
|
||||||
|
font_metrics = font.metrics()
|
||||||
|
measure = tkfont.measure
|
||||||
|
self.text_height = font_metrics['linespace']
|
||||||
|
self.text_width = measure('XX.XX.XX')
|
||||||
|
|
||||||
|
self.items = []
|
||||||
|
self.formatter = ProgressionFormatter(app, player, gameid)
|
||||||
|
|
||||||
|
kw = self.initKw(kw)
|
||||||
|
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
|
||||||
|
top_frame, bottom_frame = self.createFrames(kw)
|
||||||
|
self.createBitmaps(top_frame, kw)
|
||||||
|
|
||||||
|
frame = Tkinter.Frame(top_frame)
|
||||||
|
frame.pack(expand=True, fill='both', padx=5, pady=10)
|
||||||
|
frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
# constants
|
||||||
|
self.canvas_width, self.canvas_height = 600, 250
|
||||||
|
if parent.winfo_screenwidth() < 800 or \
|
||||||
|
parent.winfo_screenheight() < 600:
|
||||||
|
self.canvas_width, self.canvas_height = 400, 200
|
||||||
|
self.xmargin, self.ymargin = 10, 10
|
||||||
|
self.graph_dx, self.graph_dy = 10, 10
|
||||||
|
self.played_color = '#ff7ee9'
|
||||||
|
self.won_color = '#00dc28'
|
||||||
|
self.percent_color = 'blue'
|
||||||
|
# create canvas
|
||||||
|
self.canvas = canvas = Tkinter.Canvas(frame, bg='#dfe8ff',
|
||||||
|
highlightthickness=1,
|
||||||
|
highlightbackground='black',
|
||||||
|
width=self.canvas_width,
|
||||||
|
height=self.canvas_height)
|
||||||
|
canvas.pack(side='left', padx=5)
|
||||||
|
#
|
||||||
|
dir = os.path.join('images', 'stats')
|
||||||
|
try:
|
||||||
|
fn = app.dataloader.findImage('progression', dir)
|
||||||
|
self.bg_image = loadImage(fn)
|
||||||
|
canvas.create_image(0, 0, image=self.bg_image, anchor='nw')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
#
|
||||||
|
tw = max(measure(_('Games/day')),
|
||||||
|
measure(_('Games/week')),
|
||||||
|
measure(_('% won')))
|
||||||
|
self.left_margin = self.xmargin+tw/2
|
||||||
|
self.right_margin = self.xmargin+tw/2
|
||||||
|
self.top_margin = 15+self.text_height
|
||||||
|
self.bottom_margin = 15+self.text_height+10+self.text_height
|
||||||
|
#
|
||||||
|
x0, y0 = self.left_margin, self.canvas_height-self.bottom_margin
|
||||||
|
x1, y1 = self.canvas_width-self.right_margin, self.top_margin
|
||||||
|
canvas.create_rectangle(x0, y0, x1, y1, fill='white')
|
||||||
|
# horizontal axis
|
||||||
|
canvas.create_line(x0, y0, x1, y0, width=3)
|
||||||
|
|
||||||
|
# left vertical axis
|
||||||
|
canvas.create_line(x0, y0, x0, y1, width=3)
|
||||||
|
t = _('Games/day')
|
||||||
|
self.games_text_id = canvas.create_text(x0-4, y1-4, anchor='s', text=t)
|
||||||
|
|
||||||
|
# right vertical axis
|
||||||
|
canvas.create_line(x1, y0, x1, y1, width=3)
|
||||||
|
canvas.create_text(x1+4, y1-4, anchor='s', text=_('% won'))
|
||||||
|
|
||||||
|
# caption
|
||||||
|
d = self.text_height
|
||||||
|
x, y = self.xmargin, self.canvas_height-self.ymargin
|
||||||
|
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
|
||||||
|
fill=self.played_color)
|
||||||
|
x += d+5
|
||||||
|
canvas.create_text(x, y, anchor='sw', text=_('Played'))
|
||||||
|
x += measure(_('Played'))+20
|
||||||
|
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
|
||||||
|
fill=self.won_color)
|
||||||
|
x += d+5
|
||||||
|
canvas.create_text(x, y, anchor='sw', text=_('Won'))
|
||||||
|
x += measure(_('Won'))+20
|
||||||
|
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
|
||||||
|
fill=self.percent_color)
|
||||||
|
x += d+5
|
||||||
|
canvas.create_text(x, y, anchor='sw', text=_('% won'))
|
||||||
|
|
||||||
|
# right frame
|
||||||
|
right_frame = Tkinter.Frame(frame)
|
||||||
|
right_frame.pack(side='left', fill='x', padx=5)
|
||||||
|
self.all_games_variable = var = Tkinter.StringVar()
|
||||||
|
var.set('all')
|
||||||
|
b = Tkinter.Radiobutton(right_frame, text=_('All games'),
|
||||||
|
variable=var, value='all',
|
||||||
|
command=self.updateGraph,
|
||||||
|
justify='left', anchor='w'
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
b = Tkinter.Radiobutton(right_frame, text=_('Current game'),
|
||||||
|
variable=var, value='current',
|
||||||
|
command=self.updateGraph,
|
||||||
|
justify='left', anchor='w'
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
if Tkinter.TkVersion >= 8.4:
|
||||||
|
label_frame = Tkinter.LabelFrame(right_frame, text=_('Statistics for'))
|
||||||
|
else:
|
||||||
|
label_frame = Tkinter.Frame(right_frame)
|
||||||
|
label_frame.pack(side='top', fill='x', pady=10)
|
||||||
|
self.variable = var = Tkinter.StringVar()
|
||||||
|
var.set('week')
|
||||||
|
for v, t in (
|
||||||
|
('week', _('Last 7 days')),
|
||||||
|
('month', _('Last month')),
|
||||||
|
('year', _('Last year')),
|
||||||
|
('all', _('All time')),
|
||||||
|
):
|
||||||
|
b = Tkinter.Radiobutton(label_frame, text=t, variable=var, value=v,
|
||||||
|
command=self.updateGraph,
|
||||||
|
justify='left', anchor='w'
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
if Tkinter.TkVersion >= 8.4:
|
||||||
|
label_frame = Tkinter.LabelFrame(right_frame, text=_('Show graphs'))
|
||||||
|
else:
|
||||||
|
label_frame = Tkinter.Frame(right_frame)
|
||||||
|
label_frame.pack(side='top', fill='x')
|
||||||
|
self.played_graph_var = Tkinter.BooleanVar()
|
||||||
|
self.played_graph_var.set(True)
|
||||||
|
b = Tkinter.Checkbutton(label_frame, text=_('Played'),
|
||||||
|
command=self.updateGraph,
|
||||||
|
variable=self.played_graph_var,
|
||||||
|
justify='left', anchor='w'
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
self.won_graph_var = Tkinter.BooleanVar()
|
||||||
|
self.won_graph_var.set(True)
|
||||||
|
b = Tkinter.Checkbutton(label_frame, text=_('Won'),
|
||||||
|
command=self.updateGraph,
|
||||||
|
variable=self.won_graph_var,
|
||||||
|
justify='left', anchor='w'
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
self.percent_graph_var = Tkinter.BooleanVar()
|
||||||
|
self.percent_graph_var.set(True)
|
||||||
|
b = Tkinter.Checkbutton(label_frame, text=_('% won'),
|
||||||
|
command=self.updateGraph,
|
||||||
|
variable=self.percent_graph_var,
|
||||||
|
justify='left', anchor='w'
|
||||||
|
)
|
||||||
|
b.pack(fill='x', expand=True, padx=3, pady=1)
|
||||||
|
|
||||||
|
self.updateGraph()
|
||||||
|
|
||||||
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
|
self.mainloop(focus, kw.timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def initKw(self, kw):
|
||||||
|
kw = KwStruct(kw, strings=(_('&OK'),), default=0, separatorwidth=2)
|
||||||
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
|
||||||
|
def updateGraph(self, *args):
|
||||||
|
interval = self.variable.get()
|
||||||
|
canvas = self.canvas
|
||||||
|
if self.items:
|
||||||
|
canvas.delete(*self.items)
|
||||||
|
self.items = []
|
||||||
|
|
||||||
|
all_games = (self.all_games_variable.get() == 'all')
|
||||||
|
result = self.formatter.getResults(interval, all_games)
|
||||||
|
|
||||||
|
if interval in ('week', 'month'):
|
||||||
|
t = _('Games/day')
|
||||||
|
else:
|
||||||
|
t = _('Games/week')
|
||||||
|
canvas.itemconfig(self.games_text_id, text=t)
|
||||||
|
|
||||||
|
graph_width = self.canvas_width-self.left_margin-self.right_margin
|
||||||
|
graph_height = self.canvas_height-self.top_margin-self.bottom_margin
|
||||||
|
dx = (graph_width-2*self.graph_dx)/(len(result)-1)
|
||||||
|
graph_dx = (graph_width-(len(result)-1)*dx)/2
|
||||||
|
dy = (graph_height-self.graph_dy)/5
|
||||||
|
x0, y0 = self.left_margin, self.canvas_height-self.bottom_margin
|
||||||
|
x1, y1 = self.canvas_width-self.right_margin, self.top_margin
|
||||||
|
td = self.text_height/2
|
||||||
|
|
||||||
|
# vertical scale
|
||||||
|
x = x0+graph_dx
|
||||||
|
xx = -100
|
||||||
|
for res in result:
|
||||||
|
if res[0] is not None and x > xx+self.text_width+4:
|
||||||
|
##id = canvas.create_line(x, y0, x, y0-5, width=3)
|
||||||
|
##self.items.append(id)
|
||||||
|
id = canvas.create_line(x, y0, x, y1, stipple='gray50')
|
||||||
|
self.items.append(id)
|
||||||
|
id = canvas.create_text(x, y0+td, anchor='n', text=res[0])
|
||||||
|
self.items.append(id)
|
||||||
|
xx = x
|
||||||
|
else:
|
||||||
|
id = canvas.create_line(x, y0, x, y0-3, width=1)
|
||||||
|
self.items.append(id)
|
||||||
|
x += dx
|
||||||
|
|
||||||
|
# horizontal scale
|
||||||
|
max_games = max([i[1] for i in result])
|
||||||
|
games_delta = max_games/5+1
|
||||||
|
percent = 0
|
||||||
|
games = 0
|
||||||
|
for y in range(y0, y1, -dy):
|
||||||
|
if y != y0:
|
||||||
|
id = canvas.create_line(x0, y, x1, y, stipple='gray50')
|
||||||
|
self.items.append(id)
|
||||||
|
id = canvas.create_text(x0-td, y, anchor='e', text=str(games))
|
||||||
|
self.items.append(id)
|
||||||
|
id = canvas.create_text(x1+td, y, anchor='w', text=str(percent))
|
||||||
|
self.items.append(id)
|
||||||
|
games += games_delta
|
||||||
|
percent += 20
|
||||||
|
|
||||||
|
# draw result
|
||||||
|
games_resolution = float(dy)/games_delta
|
||||||
|
percent_resolution = float(dy)/20
|
||||||
|
played_coords = []
|
||||||
|
won_coords = []
|
||||||
|
percent_coords = []
|
||||||
|
x = x0+graph_dx
|
||||||
|
for res in result:
|
||||||
|
played, won = res[1], res[2]
|
||||||
|
y = y0 - int(games_resolution*played)
|
||||||
|
played_coords += [x,y]
|
||||||
|
y = y0 - int(games_resolution*won)
|
||||||
|
won_coords += [x,y]
|
||||||
|
if played > 0:
|
||||||
|
percent = int(100.*won/played)
|
||||||
|
else:
|
||||||
|
percent = 0
|
||||||
|
y = y0 - int(percent_resolution*percent)
|
||||||
|
percent_coords += [x,y]
|
||||||
|
x += dx
|
||||||
|
if self.played_graph_var.get():
|
||||||
|
id = canvas.create_line(fill=self.played_color, width=3,
|
||||||
|
*played_coords)
|
||||||
|
self.items.append(id)
|
||||||
|
if self.won_graph_var.get():
|
||||||
|
id = canvas.create_line(fill=self.won_color, width=3,
|
||||||
|
*won_coords)
|
||||||
|
self.items.append(id)
|
||||||
|
if self.percent_graph_var.get():
|
||||||
|
id = canvas.create_line(fill=self.percent_color, width=3,
|
||||||
|
*percent_coords)
|
||||||
|
self.items.append(id)
|
||||||
|
|
||||||
|
|
|
@ -507,15 +507,10 @@ class MfxScrolledCanvas:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
self.canvas.config(bg=tile.color)
|
self.canvas.config(bg=tile.color)
|
||||||
##app.top.config(bg=tile.color)
|
##app.top.config(bg=tile.color)
|
||||||
color = None
|
|
||||||
else:
|
else:
|
||||||
self.canvas.config(bg=app.top_bg)
|
self.canvas.config(bg=app.top_bg)
|
||||||
##app.top.config(bg=app.top_bg)
|
##app.top.config(bg=app.top_bg)
|
||||||
color = tile.text_color
|
|
||||||
|
|
||||||
if app.opt.use_default_text_color:
|
|
||||||
self.canvas.setTextColor(color)
|
|
||||||
else:
|
|
||||||
self.canvas.setTextColor(app.opt.colors['text'])
|
self.canvas.setTextColor(app.opt.colors['text'])
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
##
|
##
|
||||||
##---------------------------------------------------------------------------##
|
##---------------------------------------------------------------------------##
|
||||||
|
|
||||||
__all__ = ['PysolToolbar'] #, 'TOOLBAR_BUTTONS']
|
__all__ = ['PysolToolbar']
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
import os, sys, types, Tkinter
|
import os, sys, types, Tkinter
|
||||||
|
@ -245,6 +245,7 @@ class PysolToolbar(PysolToolbarActions):
|
||||||
widget.hide()
|
widget.hide()
|
||||||
#
|
#
|
||||||
prev_visible = None
|
prev_visible = None
|
||||||
|
last_visible = None
|
||||||
for w in self._widgets:
|
for w in self._widgets:
|
||||||
if w.__class__ is ToolbarSeparator:
|
if w.__class__ is ToolbarSeparator:
|
||||||
if prev_visible is None or prev_visible.__class__ is ToolbarSeparator:
|
if prev_visible is None or prev_visible.__class__ is ToolbarSeparator:
|
||||||
|
@ -256,6 +257,10 @@ class PysolToolbar(PysolToolbarActions):
|
||||||
prev_visible.hide()
|
prev_visible.hide()
|
||||||
if w.visible:
|
if w.visible:
|
||||||
prev_visible = w
|
prev_visible = w
|
||||||
|
if not isinstance(w, ToolbarLabel):
|
||||||
|
last_visible = w
|
||||||
|
if isinstance(last_visible, ToolbarSeparator):
|
||||||
|
last_visible.hide()
|
||||||
|
|
||||||
# util
|
# util
|
||||||
def _loadImage(self, name):
|
def _loadImage(self, name):
|
||||||
|
|
|
@ -42,13 +42,13 @@ def init_tile(app, top, theme):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_theme(top, theme):
|
def set_theme(app, top, theme):
|
||||||
# set theme
|
# set theme
|
||||||
style = Tile.Style(top)
|
style = Tile.Style(top)
|
||||||
all_themes = style.theme_names()
|
all_themes = style.theme_names()
|
||||||
if theme not in all_themes:
|
if theme not in all_themes:
|
||||||
print >> sys.stderr, 'WARNING: invalid theme name:', theme
|
print >> sys.stderr, 'WARNING: invalid theme name:', theme
|
||||||
theme = 'default'
|
theme = app.opt.default_tile_theme
|
||||||
style.theme_use(theme)
|
style.theme_use(theme)
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ class baseInitRootWindow:
|
||||||
elif USE_TILE:
|
elif USE_TILE:
|
||||||
theme = app.opt.tile_theme
|
theme = app.opt.tile_theme
|
||||||
init_tile(app, root, theme)
|
init_tile(app, root, theme)
|
||||||
set_theme(root, theme)
|
set_theme(app, root, theme)
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,8 @@ class initRootWindow(baseInitRootWindow):
|
||||||
app.opt.fonts['default'] = fn
|
app.opt.fonts['default'] = fn
|
||||||
root.option_add('*Menu.borderWidth', 1, 60)
|
root.option_add('*Menu.borderWidth', 1, 60)
|
||||||
root.option_add('*Menu.activeBorderWidth', 1, 60)
|
root.option_add('*Menu.activeBorderWidth', 1, 60)
|
||||||
|
if app.opt.tile_theme == 'clam':
|
||||||
|
root.wm_minsize(550, 360)
|
||||||
#
|
#
|
||||||
else:
|
else:
|
||||||
root.option_add('*Entry.background', 'white', 60)
|
root.option_add('*Entry.background', 'white', 60)
|
||||||
|
|
|
@ -140,8 +140,8 @@ def all_games(sort_by='id'):
|
||||||
gt = 'French (%s)' % GAME_BY_TYPE[gi.si.game_type]
|
gt = 'French (%s)' % GAME_BY_TYPE[gi.si.game_type]
|
||||||
name = gi.name.encode('utf-8')
|
name = gi.name.encode('utf-8')
|
||||||
altnames = '<br>'.join(gi.altnames).encode('utf-8')
|
altnames = '<br>'.join(gi.altnames).encode('utf-8')
|
||||||
if 1 and os.path.exists(os.path.join(rules_dir, rules_fn)):
|
fn = os.path.join(rules_dir, rules_fn)
|
||||||
fn = '../data/html/rules/'+rules_fn
|
if 1 and os.path.exists(fn):
|
||||||
print '''<tr><td>%s</td><td>
|
print '''<tr><td>%s</td><td>
|
||||||
<a href="%s" title="Rules for this game">%s</a>
|
<a href="%s" title="Rules for this game">%s</a>
|
||||||
</td><td>%s</td><td>%s</td></tr>
|
</td><td>%s</td><td>%s</td></tr>
|
||||||
|
@ -152,13 +152,19 @@ def all_games(sort_by='id'):
|
||||||
print '</table>'
|
print '</table>'
|
||||||
|
|
||||||
def create_html(sort_by):
|
def create_html(sort_by):
|
||||||
print '<html><body>'
|
print '''<html>
|
||||||
|
<head>
|
||||||
|
<title>PySolFC - List of solitaire games</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
'''
|
||||||
print '<b>Total games: %d</b>' % len(GAME_DB.getGamesIdSortedById())
|
print '<b>Total games: %d</b>' % len(GAME_DB.getGamesIdSortedById())
|
||||||
print '<h2>Categories</h2>'
|
print '<h2>Categories</h2>'
|
||||||
by_category()
|
by_category()
|
||||||
print '<h2>Types</h2>'
|
print '<h2>Types</h2>'
|
||||||
by_type()
|
by_type()
|
||||||
print '<h2>All games</h2>'
|
#print '<h2>All games</h2>'
|
||||||
all_games(sort_by)
|
all_games(sort_by)
|
||||||
print '</body></html>'
|
print '</body></html>'
|
||||||
|
|
||||||
|
@ -220,6 +226,9 @@ def plain_text():
|
||||||
gi = GAME_DB.get(id)
|
gi = GAME_DB.get(id)
|
||||||
if gi.category == GI.GC_FRENCH:
|
if gi.category == GI.GC_FRENCH:
|
||||||
##print str(gi.gameclass)
|
##print str(gi.gameclass)
|
||||||
|
##gc = gi.gameclass
|
||||||
|
##h = gc.Hint_Class is None and 'None' or gc.Hint_Class.__name__
|
||||||
|
##print gi.name.encode('utf-8'), h
|
||||||
print gi.name.encode('utf-8')
|
print gi.name.encode('utf-8')
|
||||||
for n in gi.altnames:
|
for n in gi.altnames:
|
||||||
print n.encode('utf-8')
|
print n.encode('utf-8')
|
||||||
|
@ -233,6 +242,8 @@ if len(sys.argv) < 2 or sys.argv[1] == 'html':
|
||||||
sort_by = 'id'
|
sort_by = 'id'
|
||||||
if len(sys.argv) > 2:
|
if len(sys.argv) > 2:
|
||||||
sort_by = sys.argv[2]
|
sort_by = sys.argv[2]
|
||||||
|
if len(sys.argv) > 3:
|
||||||
|
rules_dir = sys.argv[3]
|
||||||
create_html(sort_by)
|
create_html(sort_by)
|
||||||
elif sys.argv[1] == 'gettext':
|
elif sys.argv[1] == 'gettext':
|
||||||
get_text()
|
get_text()
|
||||||
|
|
|
@ -4,7 +4,7 @@ cd ..
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
mkdir dist
|
mkdir dist
|
||||||
cp -r locale dist
|
cp -r locale dist
|
||||||
cp fc-solve.exe dist
|
cp -r freecell-solver dist
|
||||||
cp smpeg.dll ogg.dll vorbis.dll vorbisfile.dll dist
|
cp smpeg.dll ogg.dll vorbis.dll vorbisfile.dll dist
|
||||||
python setup.py py2exe
|
python setup.py py2exe
|
||||||
cp -r d:\Python\tcl\tile0.7.8 dist\tcl
|
cp -r d:\Python\tcl\tile0.7.8 dist\tcl
|
||||||
|
|
9
setup.py
|
@ -4,6 +4,7 @@
|
||||||
import os
|
import os
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
from pysollib.settings import FC_VERSION as VERSION
|
from pysollib.settings import FC_VERSION as VERSION
|
||||||
|
from pysollib.settings import PACKAGE_URL
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
import py2exe
|
import py2exe
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ elif os.name == 'nt':
|
||||||
else:
|
else:
|
||||||
data_dir = 'data'
|
data_dir = 'data'
|
||||||
|
|
||||||
datas = [
|
ddirs = [
|
||||||
'html',
|
'html',
|
||||||
'images',
|
'images',
|
||||||
'sound',
|
'sound',
|
||||||
|
@ -25,11 +26,11 @@ datas = [
|
||||||
]
|
]
|
||||||
for s in file('MANIFEST.in'):
|
for s in file('MANIFEST.in'):
|
||||||
if s.startswith('graft data/cardset-'):
|
if s.startswith('graft data/cardset-'):
|
||||||
datas.append(s[11:].strip())
|
ddirs.append(s[11:].strip())
|
||||||
|
|
||||||
data_files = []
|
data_files = []
|
||||||
|
|
||||||
for d in datas:
|
for d in ddirs:
|
||||||
for root, dirs, files in os.walk(os.path.join('data', d)):
|
for root, dirs, files in os.walk(os.path.join('data', d)):
|
||||||
if root.find('.svn') >= 0:
|
if root.find('.svn') >= 0:
|
||||||
continue
|
continue
|
||||||
|
@ -57,7 +58,7 @@ integrated HTML help browser, and it\'s free Open Source software.
|
||||||
kw = {
|
kw = {
|
||||||
'name' : 'PySolFC',
|
'name' : 'PySolFC',
|
||||||
'version' : VERSION,
|
'version' : VERSION,
|
||||||
'url' : 'http://sourceforge.net/projects/pysolfc/',
|
'url' : PACKAGE_URL,
|
||||||
'author' : 'Skomoroh',
|
'author' : 'Skomoroh',
|
||||||
'author_email' : 'skomoroh@gmail.com',
|
'author_email' : 'skomoroh@gmail.com',
|
||||||
'description' : 'PySol - a solitaire game collection',
|
'description' : 'PySol - a solitaire game collection',
|
||||||
|
|