mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
flake 8
This commit is contained in:
parent
c4e7b1c8f3
commit
b62f600d34
3 changed files with 199 additions and 175 deletions
|
@ -1,31 +1,31 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- mode: python; coding: utf-8; -*-
|
# -*- mode: python; coding: utf-8; -*-
|
||||||
##---------------------------------------------------------------------------##
|
# ---------------------------------------------------------------------------##
|
||||||
##
|
#
|
||||||
## Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
||||||
## Copyright (C) 2003 Mt. Hood Playing Card Co.
|
# Copyright (C) 2003 Mt. Hood Playing Card Co.
|
||||||
## Copyright (C) 2005-2009 Skomoroh
|
# Copyright (C) 2005-2009 Skomoroh
|
||||||
##
|
#
|
||||||
## This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
## the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
## (at your option) any later version.
|
# (at your option) any later version.
|
||||||
##
|
#
|
||||||
## This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
||||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
## GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
##
|
#
|
||||||
## You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
##
|
#
|
||||||
##---------------------------------------------------------------------------##
|
# ---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
|
|
||||||
# PySol imports
|
# PySol imports
|
||||||
from pysollib.mygettext import _, n_
|
from pysollib.mygettext import _
|
||||||
from pysollib.settings import TITLE, PACKAGE_URL, TOOLKIT, VERSION
|
from pysollib.settings import TITLE, PACKAGE_URL, TOOLKIT, VERSION
|
||||||
from pysollib.pysoltk import make_help_toplevel
|
from pysollib.pysoltk import make_help_toplevel
|
||||||
from pysollib.pysoltk import MfxMessageDialog
|
from pysollib.pysoltk import MfxMessageDialog
|
||||||
|
@ -43,9 +43,9 @@ def help_about(app, timeout=0, sound=True):
|
||||||
t = _("A Python Solitaire Game Collection\n")
|
t = _("A Python Solitaire Game Collection\n")
|
||||||
if app.miscrandom.random() < 0.8:
|
if app.miscrandom.random() < 0.8:
|
||||||
t = _("A World Domination Project\n")
|
t = _("A World Domination Project\n")
|
||||||
strings=(_("&Nice"), _("&Credits..."))
|
strings = (_("&Nice"), _("&Credits..."))
|
||||||
if timeout:
|
if timeout:
|
||||||
strings=(_("&Enjoy"),)
|
strings = (_("&Enjoy"),)
|
||||||
version = _("Version %s") % VERSION
|
version = _("Version %s") % VERSION
|
||||||
d = PysolAboutDialog(app, app.top, title=_("About ") + TITLE,
|
d = PysolAboutDialog(app, app.top, title=_("About ") + TITLE,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
@ -74,12 +74,17 @@ def help_credits(app, timeout=0, sound=True):
|
||||||
if sound:
|
if sound:
|
||||||
app.audio.playSample("credits")
|
app.audio.playSample("credits")
|
||||||
t = ""
|
t = ""
|
||||||
if TOOLKIT == "tk" : t = "Tcl/Tk"
|
if TOOLKIT == "tk":
|
||||||
elif TOOLKIT == "gtk": t = "PyGTK"
|
t = "Tcl/Tk"
|
||||||
elif TOOLKIT == "kde": t = "pyKDE"
|
elif TOOLKIT == "gtk":
|
||||||
elif TOOLKIT == "wx" : t = "wxPython"
|
t = "PyGTK"
|
||||||
d = MfxMessageDialog(app.top, title=_("Credits"), timeout=timeout,
|
elif TOOLKIT == "kde":
|
||||||
text=TITLE+_(''' credits go to:
|
t = "pyKDE"
|
||||||
|
elif TOOLKIT == "wx":
|
||||||
|
t = "wxPython"
|
||||||
|
d = MfxMessageDialog(
|
||||||
|
app.top, title=_("Credits"), timeout=timeout,
|
||||||
|
text=TITLE+_(''' credits go to:
|
||||||
|
|
||||||
Volker Weidner for getting me into Solitaire
|
Volker Weidner for getting me into Solitaire
|
||||||
Guido van Rossum for the initial example program
|
Guido van Rossum for the initial example program
|
||||||
|
@ -90,8 +95,8 @@ Natascha
|
||||||
|
|
||||||
The Python, %s, SDL & Linux crews
|
The Python, %s, SDL & Linux crews
|
||||||
for making this program possible''') % t,
|
for making this program possible''') % t,
|
||||||
image=app.gimages.logos[3], image_side="right",
|
image=app.gimages.logos[3], image_side="right",
|
||||||
separator=True)
|
separator=True)
|
||||||
return d.status
|
return d.status
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,6 +107,7 @@ for making this program possible''') % t,
|
||||||
help_html_viewer = None
|
help_html_viewer = None
|
||||||
help_html_index = None
|
help_html_index = None
|
||||||
|
|
||||||
|
|
||||||
def help_html(app, document, dir_, top=None):
|
def help_html(app, document, dir_, top=None):
|
||||||
global help_html_viewer, help_html_index
|
global help_html_viewer, help_html_index
|
||||||
if not document:
|
if not document:
|
||||||
|
@ -114,38 +120,38 @@ def help_html(app, document, dir_, top=None):
|
||||||
document, dir_ = "index.html", "html"
|
document, dir_ = "index.html", "html"
|
||||||
help_html_index = app.dataloader.findFile(document, dir_)
|
help_html_index = app.dataloader.findFile(document, dir_)
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
d = MfxMessageDialog(app.top, title=TITLE + _(" HTML Problem"),
|
MfxMessageDialog(app.top, title=TITLE + _(" HTML Problem"),
|
||||||
text=_("Cannot find help document\n") + document,
|
text=_("Cannot find help document\n") + document,
|
||||||
bitmap="warning")
|
bitmap="warning")
|
||||||
return None
|
return None
|
||||||
##print doc, help_html_index
|
# print doc, help_html_index
|
||||||
try:
|
try:
|
||||||
viewer = help_html_viewer
|
viewer = help_html_viewer
|
||||||
#if viewer.parent.winfo_parent() != top._w:
|
# if viewer.parent.winfo_parent() != top._w:
|
||||||
# viewer.destroy()
|
# viewer.destroy()
|
||||||
# viewer = None
|
# viewer = None
|
||||||
viewer.updateHistoryXYView()
|
viewer.updateHistoryXYView()
|
||||||
viewer.display(doc, relpath=0)
|
viewer.display(doc, relpath=0)
|
||||||
except:
|
except:
|
||||||
##traceback.print_exc()
|
# traceback.print_exc()
|
||||||
top = make_help_toplevel(app, title=TITLE+_(" Help"))
|
top = make_help_toplevel(app, title=TITLE+_(" Help"))
|
||||||
if top.winfo_screenwidth() < 800 or top.winfo_screenheight() < 600:
|
if top.winfo_screenwidth() < 800 or top.winfo_screenheight() < 600:
|
||||||
#maximized = 1
|
# maximized = 1
|
||||||
top.wm_minsize(300, 150)
|
top.wm_minsize(300, 150)
|
||||||
else:
|
else:
|
||||||
#maximized = 0
|
# maximized = 0
|
||||||
top.wm_minsize(400, 200)
|
top.wm_minsize(400, 200)
|
||||||
viewer = HTMLViewer(top, app, help_html_index)
|
viewer = HTMLViewer(top, app, help_html_index)
|
||||||
viewer.display(doc)
|
viewer.display(doc)
|
||||||
#wm_map(top, maximized=maximized)
|
# wm_map(top, maximized=maximized)
|
||||||
viewer.parent.wm_deiconify()
|
viewer.parent.wm_deiconify()
|
||||||
viewer.parent.tkraise()
|
viewer.parent.tkraise()
|
||||||
help_html_viewer = viewer
|
help_html_viewer = viewer
|
||||||
return viewer
|
return viewer
|
||||||
|
|
||||||
|
|
||||||
def destroy_help_html():
|
def destroy_help_html():
|
||||||
try:
|
try:
|
||||||
help_html_viewer.destroy()
|
help_html_viewer.destroy()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
284
pysollib/hint.py
284
pysollib/hint.py
|
@ -1,25 +1,25 @@
|
||||||
#!/usr/bin/env pytho
|
#!/usr/bin/env pytho
|
||||||
# -*- mode: python; coding: utf-8; -*-
|
# -*- mode: python; coding: utf-8; -*-
|
||||||
##---------------------------------------------------------------------------##
|
# ---------------------------------------------------------------------------##
|
||||||
##
|
#
|
||||||
## Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
||||||
## Copyright (C) 2003 Mt. Hood Playing Card Co.
|
# Copyright (C) 2003 Mt. Hood Playing Card Co.
|
||||||
## Copyright (C) 2005-2009 Skomoroh
|
# Copyright (C) 2005-2009 Skomoroh
|
||||||
##
|
#
|
||||||
## This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
## the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
## (at your option) any later version.
|
# (at your option) any later version.
|
||||||
##
|
#
|
||||||
## This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
||||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
## GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
##
|
#
|
||||||
## You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
##
|
#
|
||||||
##---------------------------------------------------------------------------##
|
# ---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
|
@ -41,6 +41,7 @@ from pysollib.util import KING
|
||||||
# * The whole hint system is exclusively used by Game.getHints().
|
# * The whole hint system is exclusively used by Game.getHints().
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
|
||||||
|
|
||||||
class HintInterface:
|
class HintInterface:
|
||||||
# level == 0: show hint (key `H')
|
# level == 0: show hint (key `H')
|
||||||
# level == 1: show hint and display score value (key `Ctrl-H')
|
# level == 1: show hint and display score value (key `Ctrl-H')
|
||||||
|
@ -95,7 +96,7 @@ class AbstractHint(HintInterface):
|
||||||
self.hints = []
|
self.hints = []
|
||||||
self.max_score = 0
|
self.max_score = 0
|
||||||
self.__destructClones()
|
self.__destructClones()
|
||||||
self.solver_state = 'not_started';
|
self.solver_state = 'not_started'
|
||||||
|
|
||||||
#
|
#
|
||||||
# stack cloning
|
# stack cloning
|
||||||
|
@ -130,19 +131,22 @@ class AbstractHint(HintInterface):
|
||||||
#
|
#
|
||||||
# Pressing `Ctrl-H' (level 1) will preserve the score.
|
# Pressing `Ctrl-H' (level 1) will preserve the score.
|
||||||
|
|
||||||
def addHint(self, score, ncards, from_stack, to_stack, text_color=None, forced_move=None):
|
def addHint(self, score, ncards, from_stack,
|
||||||
|
to_stack, text_color=None, forced_move=None):
|
||||||
if score < 0:
|
if score < 0:
|
||||||
return
|
return
|
||||||
self.max_score = max(self.max_score, score)
|
self.max_score = max(self.max_score, score)
|
||||||
# add an atomic hint
|
# add an atomic hint
|
||||||
if self.score_flatten_value > 0:
|
if self.score_flatten_value > 0:
|
||||||
score = (score / self.score_flatten_value) * self.score_flatten_value
|
score = (score / self.score_flatten_value) * \
|
||||||
|
self.score_flatten_value
|
||||||
if text_color is None:
|
if text_color is None:
|
||||||
text_color = self.BLACK
|
text_color = self.BLACK
|
||||||
assert forced_move is None or len(forced_move) == 7
|
assert forced_move is None or len(forced_move) == 7
|
||||||
# pos is used for preserving the original sort order on equal scores
|
# pos is used for preserving the original sort order on equal scores
|
||||||
pos = -len(self.hints)
|
pos = -len(self.hints)
|
||||||
ah = (int(score), pos, ncards, from_stack, to_stack, text_color, forced_move)
|
ah = (int(score), pos, ncards, from_stack, to_stack,
|
||||||
|
text_color, forced_move)
|
||||||
self.hints.append(ah)
|
self.hints.append(ah)
|
||||||
|
|
||||||
# clean up and return hints sorted by score
|
# clean up and return hints sorted by score
|
||||||
|
@ -198,13 +202,15 @@ class AbstractHint(HintInterface):
|
||||||
|
|
||||||
# we move the pile if it is accepted by the target stack
|
# we move the pile if it is accepted by the target stack
|
||||||
def _defaultShallMovePile(self, from_stack, to_stack, pile, rpile):
|
def _defaultShallMovePile(self, from_stack, to_stack, pile, rpile):
|
||||||
if from_stack is to_stack or not to_stack.acceptsCards(from_stack, pile):
|
if from_stack is to_stack or not \
|
||||||
|
to_stack.acceptsCards(from_stack, pile):
|
||||||
return 0
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# same, but check for loops
|
# same, but check for loops
|
||||||
def _cautiousShallMovePile(self, from_stack, to_stack, pile, rpile):
|
def _cautiousShallMovePile(self, from_stack, to_stack, pile, rpile):
|
||||||
if from_stack is to_stack or not to_stack.acceptsCards(from_stack, pile):
|
if from_stack is to_stack or not \
|
||||||
|
to_stack.acceptsCards(from_stack, pile):
|
||||||
return 0
|
return 0
|
||||||
#
|
#
|
||||||
if len(rpile) == 0:
|
if len(rpile) == 0:
|
||||||
|
@ -219,7 +225,8 @@ class AbstractHint(HintInterface):
|
||||||
|
|
||||||
# same, but only check for loops only when in demo mode
|
# same, but only check for loops only when in demo mode
|
||||||
def _cautiousDemoShallMovePile(self, from_stack, to_stack, pile, rpile):
|
def _cautiousDemoShallMovePile(self, from_stack, to_stack, pile, rpile):
|
||||||
if from_stack is to_stack or not to_stack.acceptsCards(from_stack, pile):
|
if from_stack is to_stack or not \
|
||||||
|
to_stack.acceptsCards(from_stack, pile):
|
||||||
return 0
|
return 0
|
||||||
if self.level >= 2:
|
if self.level >= 2:
|
||||||
#
|
#
|
||||||
|
@ -235,7 +242,6 @@ class AbstractHint(HintInterface):
|
||||||
|
|
||||||
shallMovePile = _defaultShallMovePile
|
shallMovePile = _defaultShallMovePile
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# other utility methods
|
# other utility methods
|
||||||
#
|
#
|
||||||
|
@ -243,17 +249,17 @@ class AbstractHint(HintInterface):
|
||||||
def _canDropAllCards(self, from_stack, stacks, stackcards):
|
def _canDropAllCards(self, from_stack, stacks, stackcards):
|
||||||
assert from_stack not in stacks
|
assert from_stack not in stacks
|
||||||
return 0
|
return 0
|
||||||
## # FIXME: this does not account for cards which are dropped herein
|
# FIXME: this does not account for cards which are dropped herein
|
||||||
## cards = pile[:]
|
# cards = pile[:]
|
||||||
## cards.reverse()
|
# cards.reverse()
|
||||||
## for card in cards:
|
# for card in cards:
|
||||||
## for s in stacks:
|
# for s in stacks:
|
||||||
## if s is not from_stack:
|
# if s is not from_stack:
|
||||||
## if s.acceptsCards(from_stack, [card]):
|
# if s.acceptsCards(from_stack, [card]):
|
||||||
## break
|
# break
|
||||||
## else:
|
# else:
|
||||||
## return 0
|
# return 0
|
||||||
## return 1
|
# return 1
|
||||||
|
|
||||||
#
|
#
|
||||||
# misc. constants
|
# misc. constants
|
||||||
|
@ -281,7 +287,6 @@ class DefaultHint(AbstractHint):
|
||||||
#
|
#
|
||||||
# BTW, we do not cheat !
|
# BTW, we do not cheat !
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# bonus scoring used in _getXxxScore() below - subclass overrideable
|
# bonus scoring used in _getXxxScore() below - subclass overrideable
|
||||||
#
|
#
|
||||||
|
@ -289,13 +294,12 @@ class DefaultHint(AbstractHint):
|
||||||
def _preferHighRankMoves(self):
|
def _preferHighRankMoves(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# Basic bonus for moving a card.
|
# Basic bonus for moving a card.
|
||||||
# Bonus must be in range 0..999
|
# Bonus must be in range 0..999
|
||||||
|
|
||||||
BONUS_DROP_CARD = 300 # 0..400
|
BONUS_DROP_CARD = 300 # 0..400
|
||||||
BONUS_SAME_SUIT_MOVE = 200 # 0..400
|
BONUS_SAME_SUIT_MOVE = 200 # 0..400
|
||||||
BONUS_NORMAL_MOVE = 100 # 0..400
|
BONUS_NORMAL_MOVE = 100 # 0..400
|
||||||
|
|
||||||
def _getMoveCardBonus(self, r, t, pile, rpile):
|
def _getMoveCardBonus(self, r, t, pile, rpile):
|
||||||
assert pile
|
assert pile
|
||||||
|
@ -319,7 +323,6 @@ class DefaultHint(AbstractHint):
|
||||||
bonus += self.BONUS_NORMAL_MOVE + (1 + pile[0].rank)
|
bonus += self.BONUS_NORMAL_MOVE + (1 + pile[0].rank)
|
||||||
return bonus
|
return bonus
|
||||||
|
|
||||||
|
|
||||||
# Special bonus for facing up a card after the current move.
|
# Special bonus for facing up a card after the current move.
|
||||||
# Bonus must be in range 0..9000
|
# Bonus must be in range 0..9000
|
||||||
|
|
||||||
|
@ -333,12 +336,11 @@ class DefaultHint(AbstractHint):
|
||||||
bonus = max(self.BONUS_FLIP_CARD - len(rpile), 0)
|
bonus = max(self.BONUS_FLIP_CARD - len(rpile), 0)
|
||||||
return bonus
|
return bonus
|
||||||
|
|
||||||
|
|
||||||
# Special bonus for moving a pile from stack r to stack t.
|
# Special bonus for moving a pile from stack r to stack t.
|
||||||
# Bonus must be in range 0..9000
|
# Bonus must be in range 0..9000
|
||||||
|
|
||||||
BONUS_CREATE_EMPTY_ROW = 9000 # 0..9000
|
BONUS_CREATE_EMPTY_ROW = 9000 # 0..9000
|
||||||
BONUS_CAN_DROP_ALL_CARDS = 4000 # 0..4000
|
BONUS_CAN_DROP_ALL_CARDS = 4000 # 0..4000
|
||||||
BONUS_CAN_CREATE_EMPTY_ROW = 2000 # 0..4000
|
BONUS_CAN_CREATE_EMPTY_ROW = 2000 # 0..4000
|
||||||
|
|
||||||
def _getMoveSpecialBonus(self, r, t, pile, rpile):
|
def _getMoveSpecialBonus(self, r, t, pile, rpile):
|
||||||
|
@ -352,9 +354,10 @@ class DefaultHint(AbstractHint):
|
||||||
if self._canDropAllCards(r, self.game.s.foundations, stackcards=rpile):
|
if self._canDropAllCards(r, self.game.s.foundations, stackcards=rpile):
|
||||||
# we can drop the whole remaining pile
|
# we can drop the whole remaining pile
|
||||||
# (and will create an empty row in the next move)
|
# (and will create an empty row in the next move)
|
||||||
##print "BONUS_CAN_DROP_ALL_CARDS", r, pile, rpile
|
# print "BONUS_CAN_DROP_ALL_CARDS", r, pile, rpile
|
||||||
self.bonus_color = self.RED
|
self.bonus_color = self.RED
|
||||||
return self.BONUS_CAN_DROP_ALL_CARDS + self.BONUS_CAN_CREATE_EMPTY_ROW
|
return self.BONUS_CAN_DROP_ALL_CARDS + \
|
||||||
|
self.BONUS_CAN_CREATE_EMPTY_ROW
|
||||||
# check if the cards below our pile are a whole row
|
# check if the cards below our pile are a whole row
|
||||||
if r.canMoveCards(rpile):
|
if r.canMoveCards(rpile):
|
||||||
# could we move the remaining pile ?
|
# could we move the remaining pile ?
|
||||||
|
@ -366,12 +369,11 @@ class DefaultHint(AbstractHint):
|
||||||
continue
|
continue
|
||||||
if x.acceptsCards(r, rpile):
|
if x.acceptsCards(r, rpile):
|
||||||
# we can create an empty row in the next move
|
# we can create an empty row in the next move
|
||||||
##print "BONUS_CAN_CREATE_EMPTY_ROW", r, x, pile, rpile
|
# print "BONUS_CAN_CREATE_EMPTY_ROW", r, x, pile, rpile
|
||||||
self.bonus_color = self.BLUE
|
self.bonus_color = self.BLUE
|
||||||
return self.BONUS_CAN_CREATE_EMPTY_ROW
|
return self.BONUS_CAN_CREATE_EMPTY_ROW
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# scoring used in getHints() - subclass overrideable
|
# scoring used in getHints() - subclass overrideable
|
||||||
#
|
#
|
||||||
|
@ -387,24 +389,23 @@ class DefaultHint(AbstractHint):
|
||||||
assert 0 <= b2 <= 999
|
assert 0 <= b2 <= 999
|
||||||
return score + b1 + b2, self.bonus_color
|
return score + b1 + b2, self.bonus_color
|
||||||
|
|
||||||
|
|
||||||
# Score for moving a pile (usually a single card) from the WasteStack.
|
# Score for moving a pile (usually a single card) from the WasteStack.
|
||||||
def _getMoveWasteScore(self, score, color, r, t, pile, rpile):
|
def _getMoveWasteScore(self, score, color, r, t, pile, rpile):
|
||||||
assert pile
|
assert pile
|
||||||
self.bonus_color = color
|
self.bonus_color = color
|
||||||
score = 30000
|
score = 30000
|
||||||
if t.cards: score = 31000
|
if t.cards:
|
||||||
|
score = 31000
|
||||||
b2 = self._getMoveCardBonus(r, t, pile, rpile)
|
b2 = self._getMoveCardBonus(r, t, pile, rpile)
|
||||||
assert 0 <= b2 <= 999
|
assert 0 <= b2 <= 999
|
||||||
return score + b2, self.bonus_color
|
return score + b2, self.bonus_color
|
||||||
|
|
||||||
|
|
||||||
# Score for dropping ncards from stack r to stack t.
|
# Score for dropping ncards from stack r to stack t.
|
||||||
def _getDropCardScore(self, score, color, r, t, ncards):
|
def _getDropCardScore(self, score, color, r, t, ncards):
|
||||||
assert t is not r
|
assert t is not r
|
||||||
if ncards > 1:
|
if ncards > 1:
|
||||||
# drop immediately (Spider)
|
# drop immediately (Spider)
|
||||||
return 93000, color
|
return 93000, color
|
||||||
pile = r.cards
|
pile = r.cards
|
||||||
c = pile[-1]
|
c = pile[-1]
|
||||||
# compute distance to t.cap.base_rank - compare Stack.getRankDir()
|
# compute distance to t.cap.base_rank - compare Stack.getRankDir()
|
||||||
|
@ -415,24 +416,24 @@ class DefaultHint(AbstractHint):
|
||||||
if d > t.cap.mod / 2:
|
if d > t.cap.mod / 2:
|
||||||
d = d - t.cap.mod
|
d = d - t.cap.mod
|
||||||
if abs(d) <= 1:
|
if abs(d) <= 1:
|
||||||
# drop Ace and 2 immediately
|
# drop Ace and 2 immediately
|
||||||
score = 92000
|
score = 92000
|
||||||
elif r in self.game.sg.talonstacks:
|
elif r in self.game.sg.talonstacks:
|
||||||
score = 25000 # less than _getMoveWasteScore()
|
score = 25000 # less than _getMoveWasteScore()
|
||||||
elif len(pile) == 1:
|
elif len(pile) == 1:
|
||||||
###score = 50000
|
# score = 50000
|
||||||
score = 91000
|
score = 91000
|
||||||
elif self._canDropAllCards(r, self.game.s.foundations, stackcards=pile[:-1]):
|
elif self._canDropAllCards(
|
||||||
score = 90000
|
r, self.game.s.foundations, stackcards=pile[:-1]):
|
||||||
color = self.RED
|
score = 90000
|
||||||
|
color = self.RED
|
||||||
else:
|
else:
|
||||||
# don't drop this card too eagerly - we may need it
|
# don't drop this card too eagerly - we may need it
|
||||||
# for pile moving
|
# for pile moving
|
||||||
score = 50000
|
score = 50000
|
||||||
score = score + (self.K - c.rank)
|
score += (self.K - c.rank)
|
||||||
return score, color
|
return score, color
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# compute hints - main hint intelligence
|
# compute hints - main hint intelligence
|
||||||
#
|
#
|
||||||
|
@ -462,7 +463,6 @@ class DefaultHint(AbstractHint):
|
||||||
|
|
||||||
# Don't be too clever and give up ;-)
|
# Don't be too clever and give up ;-)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# implementation of the hint steps
|
# implementation of the hint steps
|
||||||
#
|
#
|
||||||
|
@ -476,7 +476,8 @@ class DefaultHint(AbstractHint):
|
||||||
t, ncards = r.canDropCards(self.game.s.foundations)
|
t, ncards = r.canDropCards(self.game.s.foundations)
|
||||||
if t:
|
if t:
|
||||||
score, color = 0, None
|
score, color = 0, None
|
||||||
score, color = self._getDropCardScore(score, color, r, t, ncards)
|
score, color = self._getDropCardScore(
|
||||||
|
score, color, r, t, ncards)
|
||||||
self.addHint(score, ncards, r, t, color)
|
self.addHint(score, ncards, r, t, color)
|
||||||
if score >= 90000 and self.level >= 1:
|
if score >= 90000 and self.level >= 1:
|
||||||
break
|
break
|
||||||
|
@ -493,7 +494,7 @@ class DefaultHint(AbstractHint):
|
||||||
lp = len(pile)
|
lp = len(pile)
|
||||||
lr = len(r.cards)
|
lr = len(r.cards)
|
||||||
assert 1 <= lp <= lr
|
assert 1 <= lp <= lr
|
||||||
rpile = r.cards[ : (lr-lp) ] # remaining pile
|
rpile = r.cards[: (lr-lp)] # remaining pile
|
||||||
|
|
||||||
empty_row_seen = 0
|
empty_row_seen = 0
|
||||||
r_is_waste = r in self.game.sg.talonstacks
|
r_is_waste = r in self.game.sg.talonstacks
|
||||||
|
@ -504,7 +505,8 @@ class DefaultHint(AbstractHint):
|
||||||
continue
|
continue
|
||||||
if r_is_waste:
|
if r_is_waste:
|
||||||
# moving a card from the WasteStack
|
# moving a card from the WasteStack
|
||||||
score, color = self._getMoveWasteScore(score, color, r, t, pile, rpile)
|
score, color = self._getMoveWasteScore(
|
||||||
|
score, color, r, t, pile, rpile)
|
||||||
else:
|
else:
|
||||||
if not t.cards:
|
if not t.cards:
|
||||||
# the target stack is empty
|
# the target stack is empty
|
||||||
|
@ -520,10 +522,10 @@ class DefaultHint(AbstractHint):
|
||||||
else:
|
else:
|
||||||
# the target stack is not empty
|
# the target stack is not empty
|
||||||
score = 80000
|
score = 80000
|
||||||
score, color = self._getMovePileScore(score, color, r, t, pile, rpile)
|
score, color = self._getMovePileScore(
|
||||||
|
score, color, r, t, pile, rpile)
|
||||||
self.addHint(score, lp, r, t, color)
|
self.addHint(score, lp, r, t, color)
|
||||||
|
|
||||||
|
|
||||||
# 2) try if we can move part of a pile within the RowStacks
|
# 2) try if we can move part of a pile within the RowStacks
|
||||||
# so that we can drop a card afterwards
|
# so that we can drop a card afterwards
|
||||||
# score: 40000 .. 59999
|
# score: 40000 .. 59999
|
||||||
|
@ -548,21 +550,22 @@ class DefaultHint(AbstractHint):
|
||||||
# now try to make a move so that the drop-card will get free
|
# now try to make a move so that the drop-card will get free
|
||||||
for di in drop_info:
|
for di in drop_info:
|
||||||
c = di[0]
|
c = di[0]
|
||||||
sub_pile = pile[di[3]+1 : ]
|
sub_pile = pile[di[3]+1:]
|
||||||
##print "trying drop move", c, pile, sub_pile
|
# print "trying drop move", c, pile, sub_pile
|
||||||
##assert r.canMoveCards(sub_pile)
|
# assert r.canMoveCards(sub_pile)
|
||||||
if not r.canMoveCards(sub_pile):
|
if not r.canMoveCards(sub_pile):
|
||||||
continue
|
continue
|
||||||
for t in rows:
|
for t in rows:
|
||||||
if t is r or not t.acceptsCards(r, sub_pile):
|
if t is r or not t.acceptsCards(r, sub_pile):
|
||||||
continue
|
continue
|
||||||
##print "drop move", r, t, sub_pile
|
# print "drop move", r, t, sub_pile
|
||||||
score = 40000
|
score = 40000
|
||||||
score = score + 1000 + (self.K - r.getCard().rank)
|
score = score + 1000 + (self.K - r.getCard().rank)
|
||||||
# force the drop (to avoid loops)
|
# force the drop (to avoid loops)
|
||||||
force = (999999, 0, di[2], r, di[1], self.BLUE, None)
|
force = (999999, 0, di[2], r, di[1], self.BLUE, None)
|
||||||
self.addHint(score, len(sub_pile), r, t, self.RED, forced_move=force)
|
self.addHint(
|
||||||
|
score, len(sub_pile), r, t,
|
||||||
|
self.RED, forced_move=force)
|
||||||
|
|
||||||
# 3) try if we should move a card from a Foundation to a RowStack
|
# 3) try if we should move a card from a Foundation to a RowStack
|
||||||
# score: 20000 .. 29999
|
# score: 20000 .. 29999
|
||||||
|
@ -587,7 +590,7 @@ class DefaultHint(AbstractHint):
|
||||||
if not tt.acceptsCards(r, pile):
|
if not tt.acceptsCards(r, pile):
|
||||||
continue
|
continue
|
||||||
# compute remaining pile in r
|
# compute remaining pile in r
|
||||||
rpile = r.cards[ : (len(r.cards)-len(pile)) ]
|
rpile = r.cards[:(len(r.cards)-len(pile))]
|
||||||
rr = self.ClonedStack(r, stackcards=rpile)
|
rr = self.ClonedStack(r, stackcards=rpile)
|
||||||
if rr.acceptsCards(t, pile):
|
if rr.acceptsCards(t, pile):
|
||||||
# the pile we are going to move from r to t
|
# the pile we are going to move from r to t
|
||||||
|
@ -595,12 +598,11 @@ class DefaultHint(AbstractHint):
|
||||||
# dangerous as we can create loops...
|
# dangerous as we can create loops...
|
||||||
continue
|
continue
|
||||||
score = 20000 + card.rank
|
score = 20000 + card.rank
|
||||||
##print score, s, t, r, pile, rpile
|
# print score, s, t, r, pile, rpile
|
||||||
# force the move from r to t (to avoid loops)
|
# force the move from r to t (to avoid loops)
|
||||||
force = (999999, 0, len(pile), r, t, self.BLUE, None)
|
force = (999999, 0, len(pile), r, t, self.BLUE, None)
|
||||||
self.addHint(score, 1, s, t, self.BLUE, forced_move=force)
|
self.addHint(score, 1, s, t, self.BLUE, forced_move=force)
|
||||||
|
|
||||||
|
|
||||||
# 4) try if we can move a card from a RowStack to a ReserveStack
|
# 4) try if we can move a card from a RowStack to a ReserveStack
|
||||||
# score: 10000 .. 19999
|
# score: 10000 .. 19999
|
||||||
|
|
||||||
|
@ -613,7 +615,7 @@ class DefaultHint(AbstractHint):
|
||||||
continue
|
continue
|
||||||
pile = [card]
|
pile = [card]
|
||||||
# compute remaining pile in r
|
# compute remaining pile in r
|
||||||
rpile = r.cards[ : (len(r.cards)-len(pile)) ]
|
rpile = r.cards[:(len(r.cards)-len(pile))]
|
||||||
rr = self.ClonedStack(r, stackcards=rpile)
|
rr = self.ClonedStack(r, stackcards=rpile)
|
||||||
for t in reservestacks:
|
for t in reservestacks:
|
||||||
if t is r or not t.acceptsCards(r, pile):
|
if t is r or not t.acceptsCards(r, pile):
|
||||||
|
@ -624,17 +626,17 @@ class DefaultHint(AbstractHint):
|
||||||
# dangerous as we can create loops...
|
# dangerous as we can create loops...
|
||||||
continue
|
continue
|
||||||
score = 10000
|
score = 10000
|
||||||
score, color = self._getMovePileScore(score, None, r, t, pile, rpile)
|
score, color = self._getMovePileScore(
|
||||||
|
score, None, r, t, pile, rpile)
|
||||||
self.addHint(score, len(pile), r, t, color)
|
self.addHint(score, len(pile), r, t, color)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# 5) try if we should move a card from a ReserveStack to a RowStack
|
# 5) try if we should move a card from a ReserveStack to a RowStack
|
||||||
|
|
||||||
def step050(self, reservestacks, rows):
|
def step050(self, reservestacks, rows):
|
||||||
if not reservestacks:
|
if not reservestacks:
|
||||||
return
|
return
|
||||||
### FIXME
|
# FIXME
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
@ -643,7 +645,7 @@ class DefaultHint(AbstractHint):
|
||||||
|
|
||||||
class CautiousDefaultHint(DefaultHint):
|
class CautiousDefaultHint(DefaultHint):
|
||||||
shallMovePile = DefaultHint._cautiousShallMovePile
|
shallMovePile = DefaultHint._cautiousShallMovePile
|
||||||
##shallMovePile = DefaultHint._cautiousDemoShallMovePile
|
# shallMovePile = DefaultHint._cautiousDemoShallMovePile
|
||||||
|
|
||||||
def _preferHighRankMoves(self):
|
def _preferHighRankMoves(self):
|
||||||
return 1
|
return 1
|
||||||
|
@ -657,6 +659,7 @@ class CautiousDefaultHint(DefaultHint):
|
||||||
class KlondikeType_Hint(DefaultHint):
|
class KlondikeType_Hint(DefaultHint):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# this works for Yukon, but not too well for Russian Solitaire
|
# this works for Yukon, but not too well for Russian Solitaire
|
||||||
class YukonType_Hint(CautiousDefaultHint):
|
class YukonType_Hint(CautiousDefaultHint):
|
||||||
def step010b_getPiles(self, stack):
|
def step010b_getPiles(self, stack):
|
||||||
|
@ -668,14 +671,16 @@ class YukonType_Hint(CautiousDefaultHint):
|
||||||
p = p[1:] # note: we need a fresh shallow copy
|
p = p[1:] # note: we need a fresh shallow copy
|
||||||
return piles
|
return piles
|
||||||
|
|
||||||
|
|
||||||
class Yukon_Hint(YukonType_Hint):
|
class Yukon_Hint(YukonType_Hint):
|
||||||
BONUS_FLIP_CARD = 9000
|
BONUS_FLIP_CARD = 9000
|
||||||
BONUS_CREATE_EMPTY_ROW = 100
|
BONUS_CREATE_EMPTY_ROW = 100
|
||||||
|
|
||||||
## FIXME: this is only a rough approximation and doesn't seem to help
|
# FIXME: this is only a rough approximation and doesn't seem to help
|
||||||
## for Russian Solitaire
|
# for Russian Solitaire
|
||||||
def _getMovePileScore(self, score, color, r, t, pile, rpile):
|
def _getMovePileScore(self, score, color, r, t, pile, rpile):
|
||||||
s, color = YukonType_Hint._getMovePileScore(self, score, color, r, t, pile, rpile)
|
s, color = YukonType_Hint._getMovePileScore(
|
||||||
|
self, score, color, r, t, pile, rpile)
|
||||||
bonus = s - score
|
bonus = s - score
|
||||||
assert 0 <= bonus <= 9999
|
assert 0 <= bonus <= 9999
|
||||||
# We must take care when moving piles that we won't block cards,
|
# We must take care when moving piles that we won't block cards,
|
||||||
|
@ -697,14 +702,15 @@ class Yukon_Hint(YukonType_Hint):
|
||||||
class FreeCellType_Hint(CautiousDefaultHint):
|
class FreeCellType_Hint(CautiousDefaultHint):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GolfType_Hint(DefaultHint):
|
class GolfType_Hint(DefaultHint):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SpiderType_Hint(DefaultHint):
|
class SpiderType_Hint(DefaultHint):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
# * FreeCell-Solver
|
# * FreeCell-Solver
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
@ -727,17 +733,17 @@ class Base_Solver_Hint:
|
||||||
self.base_rank = game_type['base_rank']
|
self.base_rank = game_type['base_rank']
|
||||||
else:
|
else:
|
||||||
self.base_rank = game.s.foundations[0].cap.base_rank
|
self.base_rank = game.s.foundations[0].cap.base_rank
|
||||||
##print 'game_type:', game_type
|
# print 'game_type:', game_type
|
||||||
##print 'base_rank:', self.base_rank
|
# print 'base_rank:', self.base_rank
|
||||||
|
|
||||||
def config(self, **kw):
|
def config(self, **kw):
|
||||||
self.options.update(kw)
|
self.options.update(kw)
|
||||||
|
|
||||||
|
|
||||||
def card2str1(self, card):
|
def card2str1(self, card):
|
||||||
# row and reserves
|
# row and reserves
|
||||||
rank = (card.rank-self.base_rank) % 13
|
rank = (card.rank-self.base_rank) % 13
|
||||||
return "A23456789TJQK"[rank] + "CSHD"[card.suit]
|
return "A23456789TJQK"[rank] + "CSHD"[card.suit]
|
||||||
|
|
||||||
def card2str2(self, card):
|
def card2str2(self, card):
|
||||||
# foundations
|
# foundations
|
||||||
rank = (card.rank-self.base_rank) % 13
|
rank = (card.rank-self.base_rank) % 13
|
||||||
|
@ -749,7 +755,7 @@ class Base_Solver_Hint:
|
||||||
if taken_hint and taken_hint[6]:
|
if taken_hint and taken_hint[6]:
|
||||||
return [taken_hint[6]]
|
return [taken_hint[6]]
|
||||||
h = self.hints[self.hints_index]
|
h = self.hints[self.hints_index]
|
||||||
#print 'getHints', taken_hint, h
|
# print 'getHints', taken_hint, h
|
||||||
if h is None:
|
if h is None:
|
||||||
return None
|
return None
|
||||||
ncards, src, dest = h
|
ncards, src, dest = h
|
||||||
|
@ -757,7 +763,7 @@ class Base_Solver_Hint:
|
||||||
if len(src.cards) > ncards and not src.cards[-ncards-1].face_up:
|
if len(src.cards) > ncards and not src.cards[-ncards-1].face_up:
|
||||||
# flip card
|
# flip card
|
||||||
thint = (999999, 0, 1, src, src, None, None)
|
thint = (999999, 0, 1, src, src, None, None)
|
||||||
if dest == None: # foundation
|
if dest is None: # foundation
|
||||||
cards = src.cards[-ncards:]
|
cards = src.cards[-ncards:]
|
||||||
for f in self.game.s.foundations:
|
for f in self.game.s.foundations:
|
||||||
if f.acceptsCards(src, cards):
|
if f.acceptsCards(src, cards):
|
||||||
|
@ -766,7 +772,7 @@ class Base_Solver_Hint:
|
||||||
assert dest
|
assert dest
|
||||||
hint = (999999, 0, ncards, src, dest, None, thint)
|
hint = (999999, 0, ncards, src, dest, None, thint)
|
||||||
self.hints_index += 1
|
self.hints_index += 1
|
||||||
#print hint
|
# print hint
|
||||||
return [hint]
|
return [hint]
|
||||||
|
|
||||||
def colonPrefixMatch(self, prefix, s):
|
def colonPrefixMatch(self, prefix, s):
|
||||||
|
@ -778,6 +784,7 @@ class Base_Solver_Hint:
|
||||||
self._v = None
|
self._v = None
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class FreeCellSolver_Hint(Base_Solver_Hint):
|
class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
def _determineIfSolverState(self, line):
|
def _determineIfSolverState(self, line):
|
||||||
if re.search('^(?:Iterations count exceeded)', line):
|
if re.search('^(?:Iterations count exceeded)', line):
|
||||||
|
@ -791,7 +798,8 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
|
|
||||||
def _isSimpleSimon(self):
|
def _isSimpleSimon(self):
|
||||||
game_type = self.game_type
|
game_type = self.game_type
|
||||||
return ('preset' in game_type and game_type['preset'] == 'simple_simon')
|
return ('preset' in game_type and
|
||||||
|
game_type['preset'] == 'simple_simon')
|
||||||
|
|
||||||
def _addBoardLine(self, l):
|
def _addBoardLine(self, l):
|
||||||
self.board += l + '\n'
|
self.board += l + '\n'
|
||||||
|
@ -811,7 +819,8 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
b = ''
|
b = ''
|
||||||
for s in game.s.foundations:
|
for s in game.s.foundations:
|
||||||
if s.cards:
|
if s.cards:
|
||||||
b += ' ' + self.card2str2(s.cards[0 if is_simple_simon else -1])
|
b += ' ' + self.card2str2(
|
||||||
|
s.cards[0 if is_simple_simon else -1])
|
||||||
self._addPrefixLine('Founds:', b)
|
self._addPrefixLine('Founds:', b)
|
||||||
|
|
||||||
b = ''
|
b = ''
|
||||||
|
@ -830,7 +839,6 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
|
|
||||||
return self.board
|
return self.board
|
||||||
|
|
||||||
|
|
||||||
def computeHints(self):
|
def computeHints(self):
|
||||||
game = self.game
|
game = self.game
|
||||||
game_type = self.game_type
|
game_type = self.game_type
|
||||||
|
@ -839,10 +847,10 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
board = self.calcBoardString()
|
board = self.calcBoardString()
|
||||||
#
|
#
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print '--------------------\n', board, '--------------------'
|
print('--------------------\n', board, '--------------------')
|
||||||
#
|
#
|
||||||
args = []
|
args = []
|
||||||
##args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
# args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
||||||
args += ['-m', '-p', '-opt', '-sel']
|
args += ['-m', '-p', '-opt', '-sel']
|
||||||
if progress:
|
if progress:
|
||||||
args += ['--iter-output']
|
args += ['--iter-output']
|
||||||
|
@ -867,7 +875,7 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
|
|
||||||
command = FCS_COMMAND+' '+' '.join([str(i) for i in args])
|
command = FCS_COMMAND+' '+' '.join([str(i) for i in args])
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print command
|
print(command)
|
||||||
kw = {'shell': True,
|
kw = {'shell': True,
|
||||||
'stdin': subprocess.PIPE,
|
'stdin': subprocess.PIPE,
|
||||||
'stdout': subprocess.PIPE,
|
'stdout': subprocess.PIPE,
|
||||||
|
@ -880,9 +888,9 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
pin.close()
|
pin.close()
|
||||||
#
|
#
|
||||||
stack_types = {
|
stack_types = {
|
||||||
'the' : game.s.foundations,
|
'the': game.s.foundations,
|
||||||
'stack' : game.s.rows,
|
'stack': game.s.rows,
|
||||||
'freecell' : game.s.reserves,
|
'freecell': game.s.reserves,
|
||||||
}
|
}
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
@ -894,7 +902,7 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
|
|
||||||
for s in pout:
|
for s in pout:
|
||||||
if DEBUG >= 5:
|
if DEBUG >= 5:
|
||||||
print s,
|
print(s)
|
||||||
|
|
||||||
if self.colonPrefixMatch('Iteration', s):
|
if self.colonPrefixMatch('Iteration', s):
|
||||||
iter = self._v
|
iter = self._v
|
||||||
|
@ -914,7 +922,7 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
hints = []
|
hints = []
|
||||||
for s in pout:
|
for s in pout:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print s,
|
print(s)
|
||||||
if self._determineIfSolverState(s):
|
if self._determineIfSolverState(s):
|
||||||
next
|
next
|
||||||
m = re.match('Total number of states checked is (\d+)\.', s)
|
m = re.match('Total number of states checked is (\d+)\.', s)
|
||||||
|
@ -934,7 +942,9 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
|
|
||||||
move_s = m.group(1)
|
move_s = m.group(1)
|
||||||
|
|
||||||
m = re.match('the sequence on top of Stack (\d+) to the foundations', move_s);
|
m = re.match(
|
||||||
|
'the sequence on top of Stack (\d+) to the foundations',
|
||||||
|
move_s)
|
||||||
|
|
||||||
if m:
|
if m:
|
||||||
ncards = 13
|
ncards = 13
|
||||||
|
@ -943,7 +953,12 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
src = st[sn]
|
src = st[sn]
|
||||||
dest = None
|
dest = None
|
||||||
else:
|
else:
|
||||||
m = re.match('(?P<ncards>a card|(?P<count>\d+) cards) from (?P<source_type>stack|freecell) (?P<source_idx>\d+) to (?P<dest>the foundations|(?P<dest_type>freecell|stack) (?P<dest_idx>\d+))\s*', move_s);
|
m = re.match(
|
||||||
|
'(?P<ncards>a card|(?P<count>\d+) cards) '
|
||||||
|
'from (?P<source_type>stack|freecell)'
|
||||||
|
'(?P<source_idx>\d+) to '
|
||||||
|
'(?P<dest>the foundations|(?P<dest_type>freecell|stack)'
|
||||||
|
' (?P<dest_idx>\d+))\s*', move_s)
|
||||||
|
|
||||||
if not m:
|
if not m:
|
||||||
continue
|
continue
|
||||||
|
@ -969,25 +984,26 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
dest = dt[dn]
|
dest = dt[dn]
|
||||||
|
|
||||||
hints.append([ncards, src, dest])
|
hints.append([ncards, src, dest])
|
||||||
##print src, dest, ncards
|
# print src, dest, ncards
|
||||||
|
|
||||||
#
|
#
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print 'time:', time.time()-start_time
|
print('time:', time.time()-start_time)
|
||||||
##print perr.read(),
|
# print perr.read(),
|
||||||
|
|
||||||
self.hints = hints
|
self.hints = hints
|
||||||
if len(hints) > 0:
|
if len(hints) > 0:
|
||||||
self.solver_state = 'solved'
|
self.solver_state = 'solved'
|
||||||
self.hints.append(None) # XXX
|
self.hints.append(None) # XXX
|
||||||
|
|
||||||
##print self.hints
|
# print self.hints
|
||||||
|
|
||||||
pout.close()
|
pout.close()
|
||||||
perr.close()
|
perr.close()
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
os.wait()
|
os.wait()
|
||||||
|
|
||||||
|
|
||||||
class BlackHoleSolver_Hint(Base_Solver_Hint):
|
class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
BLACK_HOLE_SOLVER_COMMAND = 'black-hole-solve'
|
BLACK_HOLE_SOLVER_COMMAND = 'black-hole-solve'
|
||||||
|
|
||||||
|
@ -1008,27 +1024,27 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
b += cs + ' '
|
b += cs + ' '
|
||||||
board += b.strip() + '\n'
|
board += b.strip() + '\n'
|
||||||
|
|
||||||
return board;
|
return board
|
||||||
|
|
||||||
def computeHints(self):
|
def computeHints(self):
|
||||||
game = self.game
|
game = self.game
|
||||||
game_type = self.game_type
|
game_type = self.game_type
|
||||||
progress = self.options['progress']
|
|
||||||
|
|
||||||
board = self.calcBoardString()
|
board = self.calcBoardString()
|
||||||
#
|
#
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print '--------------------\n', board, '--------------------'
|
print('--------------------\n', board, '--------------------')
|
||||||
#
|
#
|
||||||
args = []
|
args = []
|
||||||
##args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
# args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
||||||
args += ['--game', game_type['preset'], '--rank-reach-prune',]
|
args += ['--game', game_type['preset'], '--rank-reach-prune']
|
||||||
args += ['--max-iters', self.options['max_iters'],]
|
args += ['--max-iters', self.options['max_iters']]
|
||||||
#
|
#
|
||||||
|
|
||||||
command = self.BLACK_HOLE_SOLVER_COMMAND+' '+' '.join([str(i) for i in args])
|
command = self.BLACK_HOLE_SOLVER_COMMAND + ' ' + \
|
||||||
|
' '.join([str(i) for i in args])
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print command
|
print(command)
|
||||||
kw = {'shell': True,
|
kw = {'shell': True,
|
||||||
'stdin': subprocess.PIPE,
|
'stdin': subprocess.PIPE,
|
||||||
'stdout': subprocess.PIPE,
|
'stdout': subprocess.PIPE,
|
||||||
|
@ -1051,7 +1067,7 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
|
|
||||||
for s in pout:
|
for s in pout:
|
||||||
if DEBUG >= 5:
|
if DEBUG >= 5:
|
||||||
print s,
|
print(s)
|
||||||
|
|
||||||
m = re.search('^(Intractable!|Unsolved!|Solved!)\n', s)
|
m = re.search('^(Intractable!|Unsolved!|Solved!)\n', s)
|
||||||
if m:
|
if m:
|
||||||
|
@ -1071,7 +1087,7 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
hints = []
|
hints = []
|
||||||
for s in pout:
|
for s in pout:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print s,
|
print(s)
|
||||||
m = re.match('Total number of states checked is (\d+)\.', s)
|
m = re.match('Total number of states checked is (\d+)\.', s)
|
||||||
if m:
|
if m:
|
||||||
iter = int(m.group(1))
|
iter = int(m.group(1))
|
||||||
|
@ -1085,7 +1101,8 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
self.dialog.setText(states=states)
|
self.dialog.setText(states=states)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
m = re.match('Move a card from stack ([0-9]+) to the foundations', s)
|
m = re.match(
|
||||||
|
'Move a card from stack ([0-9]+) to the foundations', s)
|
||||||
if not m:
|
if not m:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1097,23 +1114,24 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
dest = None
|
dest = None
|
||||||
|
|
||||||
hints.append([ncards, src, dest])
|
hints.append([ncards, src, dest])
|
||||||
##print src, dest, ncards
|
# print src, dest, ncards
|
||||||
|
|
||||||
#
|
#
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print 'time:', time.time()-start_time
|
print('time:', time.time()-start_time)
|
||||||
##print perr.read(),
|
# print perr.read(),
|
||||||
|
|
||||||
self.hints = hints
|
self.hints = hints
|
||||||
self.hints.append(None) # XXX
|
self.hints.append(None) # XXX
|
||||||
|
|
||||||
##print self.hints
|
# print self.hints
|
||||||
|
|
||||||
pout.close()
|
pout.close()
|
||||||
perr.close()
|
perr.close()
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
os.wait()
|
os.wait()
|
||||||
|
|
||||||
|
|
||||||
class FreeCellSolverWrapper:
|
class FreeCellSolverWrapper:
|
||||||
|
|
||||||
def __init__(self, **game_type):
|
def __init__(self, **game_type):
|
||||||
|
@ -1123,6 +1141,7 @@ class FreeCellSolverWrapper:
|
||||||
hint = FreeCellSolver_Hint(game, dialog, **self.game_type)
|
hint = FreeCellSolver_Hint(game, dialog, **self.game_type)
|
||||||
return hint
|
return hint
|
||||||
|
|
||||||
|
|
||||||
class BlackHoleSolverWrapper:
|
class BlackHoleSolverWrapper:
|
||||||
|
|
||||||
def __init__(self, **game_type):
|
def __init__(self, **game_type):
|
||||||
|
@ -1131,4 +1150,3 @@ class BlackHoleSolverWrapper:
|
||||||
def __call__(self, game, dialog):
|
def __call__(self, game, dialog):
|
||||||
hint = BlackHoleSolver_Hint(game, dialog, **self.game_type)
|
hint = BlackHoleSolver_Hint(game, dialog, **self.game_type)
|
||||||
return hint
|
return hint
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Test::Differences qw( eq_or_diff );
|
||||||
use String::ShellQuote qw/ shell_quote /;
|
use String::ShellQuote qw/ shell_quote /;
|
||||||
|
|
||||||
# my $cmd = shell_quote( 'flake8', '.' );
|
# my $cmd = shell_quote( 'flake8', '.' );
|
||||||
my $cmd = shell_quote( 'flake8', glob('./pysollib/[a-g]*.py') );
|
my $cmd = shell_quote( 'flake8', glob('./pysollib/[a-h]*.py') );
|
||||||
|
|
||||||
# TEST
|
# TEST
|
||||||
eq_or_diff( scalar(`$cmd`), '', "flake8 is happy with the code." );
|
eq_or_diff( scalar(`$cmd`), '', "flake8 is happy with the code." );
|
||||||
|
|
Loading…
Add table
Reference in a new issue