From 9fd4942f23c4f0fb8233a044e1314f34b257f7c9 Mon Sep 17 00:00:00 2001 From: skomoroh Date: Sun, 6 May 2007 21:42:40 +0000 Subject: [PATCH] * improved solitaire wizard * removed round changes from turnStackMove git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@160 39dd0a4e-7c14-0410-91b3-c4f2d318f732 --- pysollib/customgame.py | 77 ++++++++++++++++++++++++++---------- pysollib/game.py | 4 +- pysollib/gamedb.py | 19 +++++---- pysollib/games/matriarchy.py | 4 +- pysollib/games/sanibel.py | 4 +- pysollib/games/threepeaks.py | 3 +- pysollib/games/yukon.py | 30 +------------- pysollib/hint.py | 25 ++++++++++++ pysollib/move.py | 27 +------------ pysollib/stack.py | 20 ++++++++-- pysollib/wizardutil.py | 63 +++++++++++++++++++---------- 11 files changed, 164 insertions(+), 112 deletions(-) diff --git a/pysollib/customgame.py b/pysollib/customgame.py index 1e96a88c..1705a488 100644 --- a/pysollib/customgame.py +++ b/pysollib/customgame.py @@ -24,7 +24,7 @@ from util import * from stack import * from game import Game from layout import Layout -from hint import AbstractHint, DefaultHint, CautiousDefaultHint +from hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint #from pysoltk import MfxCanvasText from wizardutil import WizardWidgets @@ -58,10 +58,17 @@ class CustomGame(Game): 'base_rank': s['found_base_card'], 'mod': 13, } + # max_move if s['found_type'] not in (Spider_SS_Foundation, Spider_AC_Foundation,): kw['max_move'] = s['found_max_move'] - else: + # suit + if s['found_type'] in (Spider_SS_Foundation, + Spider_AC_Foundation,): + kw['suit'] = ANY_SUIT + # fix dir and base_rank for Spider foundations + if s['found_type'] in (Spider_SS_Foundation, + Spider_AC_Foundation,): kw['dir'] = -kw['dir'] if s['found_base_card'] == KING: kw['base_rank'] = ACE @@ -101,7 +108,7 @@ class CustomGame(Game): } if s['talon'] is InitialDealTalonStack: layout_kw['texts'] = False - layout_kw['playcards'] = 12+s['deal_to_rows'] + layout_kw['playcards'] = max(16, 12+s['deal_face_down']+s['deal_face_up']) # reserves if s['reserves_num']: @@ -125,18 +132,23 @@ class CustomGame(Game): **layout_kw ) + # shuffle + if s['talon_shuffle'] and s['talon'] in (WasteTalonStack, + DealRowRedealTalonStack): + self.s.talon.dealCards = self.s.talon.shuffleAndDealCards + # shallHighlightMatch for c, f in ( ((Spider_AC_RowStack, Spider_SS_RowStack), (self._shallHighlightMatch_RK, self._shallHighlightMatch_RKW)), - ((AC_RowStack, UD_AC_RowStack), + ((AC_RowStack, UD_AC_RowStack, Yukon_AC_RowStack), (self._shallHighlightMatch_AC, self._shallHighlightMatch_ACW)), - ((SS_RowStack, UD_SS_RowStack), + ((SS_RowStack, UD_SS_RowStack, Yukon_SS_RowStack), (self._shallHighlightMatch_SS, self._shallHighlightMatch_SSW)), - ((RK_RowStack, UD_RK_RowStack), + ((RK_RowStack, UD_RK_RowStack, Yukon_RK_RowStack), (self._shallHighlightMatch_RK, self._shallHighlightMatch_RKW)), ((SC_RowStack, UD_SC_RowStack), @@ -169,48 +181,71 @@ class CustomGame(Game): stack.acceptsCards = stack.varyAcceptsCards stack.getBaseCard = stack.varyGetBaseCard + # Hint_Class + # TODO + if s['rows_type'] in (Yukon_SS_RowStack, + Yukon_AC_RowStack, + Yukon_RK_RowStack): + self.Hint_Class = Yukon_Hint + def startGame(self): + + def deal(rows, flip, frames, max_cards): + if max_cards <= 0: + return 0 + return self.s.talon.dealRowAvail(rows=rows, flip=flip, + frames=frames) + frames = 0 + s = self.SETTINGS + max_cards = s['deal_max_cards'] - len(self.s.rows) + if self.s.waste: + max_cards -= 1 + anim_frames = -1 # deal to reserves - n = self.SETTINGS['deal_to_reserves'] + n = s['deal_to_reserves'] for i in range(n): - self.s.talon.dealRowAvail(rows=self.s.reserves, - flip=True, frames=frames) + max_cards -= deal(self.s.reserves[:max_cards], + True, frames, max_cards) if frames == 0 and len(self.s.talon.cards) < 16: - frames = -1 + frames = anim_frames self.startDealSample() # deal to rows - flip = (self.SETTINGS['deal_faceup'] == 'All cards') - max_rows = self.SETTINGS['deal_to_rows'] - if self.SETTINGS['deal_type'] == 'Triangle': + face_down = s['deal_face_down'] + max_rows = s['deal_face_down'] + s['deal_face_up'] + if s['deal_type'] == 'Triangle': # triangle for i in range(1, len(self.s.rows)): - self.s.talon.dealRowAvail(rows=self.s.rows[i:], - flip=flip, frames=frames) + flip = (face_down <= 0) + max_cards -= deal(self.s.rows[i:i+max_cards], + flip, frames, max_cards) + face_down -= 1 max_rows -= 1 if max_rows == 1: break if frames == 0 and len(self.s.talon.cards) < 16: - frames = -1 + frames = anim_frames self.startDealSample() else: # rectangle for i in range(max_rows-1): - self.s.talon.dealRowAvail(rows=self.s.rows, - flip=flip, frames=frames) + flip = (face_down <= 0) + max_cards -= deal(self.s.rows[:max_cards], + flip, frames, max_cards) + face_down -= 1 if frames == 0 and len(self.s.talon.cards) < 16: - frames = -1 + frames = anim_frames self.startDealSample() if frames == 0: self.startDealSample() - self.s.talon.dealRowAvail() + self.s.talon.dealRowAvail(frames=anim_frames) if isinstance(self.s.talon, InitialDealTalonStack): while self.s.talon.cards: - self.s.talon.dealRowAvail() + self.s.talon.dealRowAvail(frames=anim_frames) # deal to waste if self.s.waste: diff --git a/pysollib/game.py b/pysollib/game.py index 6eff160d..f3cd1eb6 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -2548,10 +2548,10 @@ for %d moves. self.hints.list = None # move type 3 - def turnStackMove(self, from_stack, to_stack, update_flags=1): + def turnStackMove(self, from_stack, to_stack): assert from_stack and to_stack and (from_stack is not to_stack) assert len(to_stack.cards) == 0 - am = ATurnStackMove(from_stack, to_stack, update_flags=update_flags) + am = ATurnStackMove(from_stack, to_stack) self.__storeMove(am) am.do(self) self.hints.list = None diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py index 3130bf58..abbf12db 100644 --- a/pysollib/gamedb.py +++ b/pysollib/gamedb.py @@ -456,8 +456,9 @@ class GameInfo(Struct): altnames=tuple(altnames), decks=decks, redeals=redeals, ncards=ncards, category=category, skill_level=skill_level, - suits=tuple(suits), ranks=tuple(ranks), trumps=tuple(trumps), - si=gi_si, rules_filename=rules_filename, plugin=0) + suits=tuple(suits), ranks=tuple(ranks), + trumps=tuple(trumps), + si=gi_si, rules_filename=rules_filename) class GameManager: @@ -472,8 +473,8 @@ class GameManager: self.__all_games = {} # includes hidden games self.__all_gamenames = {} # includes hidden games self.__games_for_solver = [] - self.loading_plugin = False self.check_game = True + self.current_filename = None self.registered_game_types = {} def getSelected(self): @@ -508,12 +509,11 @@ class GameManager: raise GameInfoException("duplicate game altname %s: %s" % (gi.id, n)) - def register(self, gi, check_game=True): + def register(self, gi): ##print gi.id, gi.short_name.encode('utf-8') if not isinstance(gi, GameInfo): raise GameInfoException("wrong GameInfo class") - gi.plugin = self.loading_plugin - if self.check_game and (self.loading_plugin or CHECK_GAMES): + if self.check_game and CHECK_GAMES: self._check_game(gi) ##if 0 and gi.si.game_flags & GI.GT_XORIGINAL: ## return @@ -541,6 +541,8 @@ class GameManager: if hasattr(gi.gameclass, 'Solver_Class') and \ gi.gameclass.Solver_Class is not None: self.__games_for_solver.append(gi.id) + if self.current_filename is not None: + gi.gameclass.MODULE_FILENAME = self.current_filename # # access games database - we do not expose hidden games @@ -612,10 +614,11 @@ def registerGame(gameinfo): return gameinfo -def loadGame(modname, filename, plugin=True, check_game=True): +def loadGame(modname, filename, check_game=False): ##print "load game", modname, filename - GAME_DB.loading_plugin = plugin GAME_DB.check_game = check_game + GAME_DB.current_filename = filename module = imp.load_source(modname, filename) ##execfile(filename, globals(), globals()) + GAME_DB.current_filename = None diff --git a/pysollib/games/matriarchy.py b/pysollib/games/matriarchy.py index ec3732f4..f2caaeb0 100644 --- a/pysollib/games/matriarchy.py +++ b/pysollib/games/matriarchy.py @@ -108,7 +108,9 @@ class Matriarchy_Talon(WasteTalonStack): if n < ncards and len(waste.cards) > 0: assert len(self.cards) == 0 assert self.round < self.max_rounds or update_flags == 0 - self.game.turnStackMove(waste, self, update_flags=update_flags) + self.game.turnStackMove(waste, self) + if update_flags: + self.game.nextRoundMove(self) # do not update self.round anymore in this deal update_flags = 0 assert self.round <= self.max_rounds diff --git a/pysollib/games/sanibel.py b/pysollib/games/sanibel.py index 7d6f9d00..0a57d0ec 100644 --- a/pysollib/games/sanibel.py +++ b/pysollib/games/sanibel.py @@ -38,9 +38,9 @@ from pysollib.util import * from pysollib.stack import * from pysollib.game import Game from pysollib.layout import Layout -from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint from pysollib.games.gypsy import Gypsy -from pysollib.games.yukon import Yukon_Hint + # /************************************************************************ # // Sanibel diff --git a/pysollib/games/threepeaks.py b/pysollib/games/threepeaks.py index 6d3e75c3..322b9b63 100644 --- a/pysollib/games/threepeaks.py +++ b/pysollib/games/threepeaks.py @@ -68,7 +68,8 @@ class ThreePeaks_TalonStack(WasteTalonStack): if sound: self.game.playSample("turnwaste", priority=20) num_cards = len(waste.cards) - game.turnStackMove(waste, self, update_flags=1) + game.turnStackMove(waste, self) + game.nextRoundMove(self) game.leaveState(old_state) return num_cards diff --git a/pysollib/games/yukon.py b/pysollib/games/yukon.py index b08ce580..0c9566c6 100644 --- a/pysollib/games/yukon.py +++ b/pysollib/games/yukon.py @@ -41,41 +41,13 @@ from pysollib.mfxutil import kwdefault from pysollib.stack import * from pysollib.game import Game from pysollib.layout import Layout -from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint from pysollib.hint import YukonType_Hint from pysollib.hint import FreeCellSolverWrapper from pysollib.pysoltk import MfxCanvasText from spider import Spider_SS_Foundation -# /*********************************************************************** -# // -# ************************************************************************/ - -class Yukon_Hint(YukonType_Hint): - BONUS_FLIP_CARD = 9000 - BONUS_CREATE_EMPTY_ROW = 100 - - ## FIXME: this is only a rough approximation and doesn't seem to help - ## for Russian Solitaire - def _getMovePileScore(self, score, color, r, t, pile, rpile): - s, color = YukonType_Hint._getMovePileScore(self, score, color, r, t, pile, rpile) - bonus = s - score - assert 0 <= bonus <= 9999 - # We must take care when moving piles that we won't block cards, - # i.e. if there is a card in pile which would be needed - # for a card in stack t. - tpile = t.getPile() - if tpile: - for cr in pile: - rr = self.ClonedStack(r, stackcards=[cr]) - for ct in tpile: - if rr.acceptsCards(t, [ct]): - d = bonus / 1000 - bonus = (d * 1000) + bonus % 100 - break - return score + bonus, color - # /*********************************************************************** # // Yukon diff --git a/pysollib/hint.py b/pysollib/hint.py index 08b55dbb..2b251898 100644 --- a/pysollib/hint.py +++ b/pysollib/hint.py @@ -678,6 +678,31 @@ class YukonType_Hint(CautiousDefaultHint): p = p[1:] # note: we need a fresh shallow copy return piles +class Yukon_Hint(YukonType_Hint): + BONUS_FLIP_CARD = 9000 + BONUS_CREATE_EMPTY_ROW = 100 + + ## FIXME: this is only a rough approximation and doesn't seem to help + ## for Russian Solitaire + def _getMovePileScore(self, score, color, r, t, pile, rpile): + s, color = YukonType_Hint._getMovePileScore(self, score, color, r, t, pile, rpile) + bonus = s - score + assert 0 <= bonus <= 9999 + # We must take care when moving piles that we won't block cards, + # i.e. if there is a card in pile which would be needed + # for a card in stack t. + tpile = t.getPile() + if tpile: + for cr in pile: + rr = self.ClonedStack(r, stackcards=[cr]) + for ct in tpile: + if rr.acceptsCards(t, [ct]): + d = bonus / 1000 + bonus = (d * 1000) + bonus % 100 + break + return score + bonus, color + + # FIXME class FreeCellType_Hint(CautiousDefaultHint): pass diff --git a/pysollib/move.py b/pysollib/move.py index a5dd3bd4..c1513bf6 100644 --- a/pysollib/move.py +++ b/pysollib/move.py @@ -224,11 +224,10 @@ class AFlipAllMove(AtomicMove): # ************************************************************************/ class ATurnStackMove(AtomicMove): - def __init__(self, from_stack, to_stack, update_flags=1): + def __init__(self, from_stack, to_stack): assert from_stack is not to_stack self.from_stack_id = from_stack.id self.to_stack_id = to_stack.id - self.update_flags = update_flags def redo(self, game): from_stack = game.allstacks[self.from_stack_id] @@ -246,16 +245,6 @@ class ATurnStackMove(AtomicMove): to_stack.addCard(card, unhide=unhide, update=0) card.showBack(unhide=unhide) ##print 3, unhide, to_stack.getCard().__dict__ - if self.update_flags & 2: - ### not used yet - assert 0 - from_stack.round = from_stack.round + 1 - if self.update_flags & 1: - assert to_stack is game.s.talon - assert to_stack.round < to_stack.max_rounds or to_stack.max_rounds < 0 - to_stack.round = to_stack.round + 1 - from_stack.updateText() - to_stack.updateText() def undo(self, game): from_stack = game.allstacks[self.to_stack_id] @@ -270,22 +259,10 @@ class ATurnStackMove(AtomicMove): assert not card.face_up card.showFace(unhide=unhide) to_stack.addCard(card, unhide=unhide, update=0) - if self.update_flags & 2: - ### not used yet - assert 0 - assert to_stack.round > 1 - to_stack.round = to_stack.round - 1 - if self.update_flags & 1: - assert from_stack is game.s.talon - assert from_stack.round > 1 - from_stack.round = from_stack.round - 1 - from_stack.updateText() - to_stack.updateText() def cmpForRedo(self, other): return (cmp(self.from_stack_id, other.from_stack_id) or - cmp(self.to_stack_id, other.to_stack_id) or - cmp(self.update_flags, other.update_flags)) + cmp(self.to_stack_id, other.to_stack_id)) # /*********************************************************************** diff --git a/pysollib/stack.py b/pysollib/stack.py index 30768ec5..b97d0401 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -1840,7 +1840,7 @@ class DealRowRedealTalonStack(TalonStack, RedealCards_StackMethods): return True return False - def dealCards(self, sound=0, rows=None): + def dealCards(self, sound=0, rows=None, shuffle=False): num_cards = 0 if rows is None: rows = self.game.s.rows @@ -1849,12 +1849,19 @@ class DealRowRedealTalonStack(TalonStack, RedealCards_StackMethods): if not self.cards: # move all cards to talon num_cards = self._redeal(rows=rows, frames=4) + if shuffle: + # shuffle + self.game.shuffleStackMove(self) self.game.nextRoundMove(self) num_cards += self.dealRowAvail(rows=rows, sound=0) if sound: self.game.stopSamples() return num_cards + def shuffleAndDealCards(self, sound=0, rows=None): + DealRowRedealTalonStack.dealCards(self, sound=sound, + rows=rows, shuffle=True) + class DealReserveRedealTalonStack(DealRowRedealTalonStack): @@ -2564,7 +2571,7 @@ class WasteTalonStack(TalonStack): return 1 return 0 - def dealCards(self, sound=0): + def dealCards(self, sound=0, shuffle=False): old_state = self.game.enterState(self.game.S_DEAL) num_cards = 0 waste = self.waste @@ -2587,10 +2594,17 @@ class WasteTalonStack(TalonStack): if sound: self.game.playSample("turnwaste", priority=20) num_cards = len(waste.cards) - self.game.turnStackMove(waste, self, update_flags=1) + self.game.turnStackMove(waste, self) + if shuffle: + # shuffle + self.game.shuffleStackMove(self) + self.game.nextRoundMove(self) self.game.leaveState(old_state) return num_cards + def shuffleAndDealCards(self, sound=0): + WasteTalonStack.dealCards(self, sound=sound, shuffle=True) + class FaceUpWasteTalonStack(WasteTalonStack): def canFlipCard(self): diff --git a/pysollib/wizardutil.py b/pysollib/wizardutil.py index c678b382..d89462f0 100644 --- a/pysollib/wizardutil.py +++ b/pysollib/wizardutil.py @@ -42,14 +42,14 @@ class WizSetting: self.values_map = values_map self.default = gettext(default) ##self.values_dict = dict(self.values_map) - self.translate_map = {} + self.translation_map = {} ##self.values = [i[0] for i in self.values_map] if widget == 'menu': self.values = [] for k, v in self.values_map: t = gettext(k) self.values.append(t) - self.translate_map[t] = k + self.translation_map[t] = k assert self.default in self.values else: self.values = self.values_map @@ -100,7 +100,7 @@ LayoutType = WizSetting( TalonType = WizSetting( values_map = ((n_('Initial dealing'), InitialDealTalonStack), (n_('Deal to waste'), WasteTalonStack), - (n_('Deal to rows'), DealRowTalonStack), + (n_('Deal to rows'), DealRowRedealTalonStack), ), default = n_('Initial dealing'), label = _('Type:'), @@ -124,6 +124,13 @@ DealToWaste = WizSetting( label = _('Deal to waste:'), var_name = 'deal_to_waste', ) +TalonShuffle = WizSetting( + values_map = (0, 1), + default = 0, + label = _('Shuffle:'), + var_name = 'talon_shuffle', + widget = 'check', + ) FoundType = WizSetting( values_map = ((n_('Same suit'), SS_FoundationStack), (n_('Alternate color'), AC_FoundationStack), @@ -184,12 +191,18 @@ RowsType = WizSetting( (n_('Same color'), SC_RowStack), (n_('Rank'), RK_RowStack), (n_('Any suit but the same'), BO_RowStack), + (n_('Up or down by same suit'), UD_SS_RowStack), (n_('Up or down by alternate color'), UD_AC_RowStack), (n_('Up or down by rank'), UD_RK_RowStack), (n_('Up or down by same color'), UD_SC_RowStack), + (n_('Spider same suit'), Spider_SS_RowStack), (n_('Spider alternate color'), Spider_AC_RowStack), + + (n_('Yukon same suit'), Yukon_SS_RowStack), + (n_('Yukon alternate color'), Yukon_AC_RowStack), + (n_('Yukon rank'), Yukon_RK_RowStack), ), default = n_('Alternate color'), label = _('Type:'), @@ -246,26 +259,34 @@ DealType = WizSetting( label = _('Type:'), var_name = 'deal_type', ) -DealFaceUp = WizSetting( - values_map = ((n_('Top cards'), 'top'), (n_('All cards'), 'all')), - default = n_('All cards'), - label = _('Face-up:'), - var_name = 'deal_faceup', - ) -DealMaxRows = WizSetting( +DealFaceDown = WizSetting( values_map = (0, 20), - default = 7, + default = 0, widget = 'spin', - label = _('Deal to rows:'), - var_name = 'deal_to_rows', + label = _('# of face-down cards:'), + var_name = 'deal_face_down', + ) +DealFaceUp = WizSetting( + values_map = (1, 20), + default = 8, + widget = 'spin', + label = _('# of face-up cards:'), + var_name = 'deal_face_up', ) DealToReseves = WizSetting( values_map = (0, 20), default = 0, widget = 'spin', - label = _('Deal ro reserves:'), + label = _('Deal to reserves:'), var_name = 'deal_to_reserves', ) +DealMaxCards = WizSetting( + values_map = (0, 208), + default = 52, + widget = 'spin', + label = _('Max # of dealt cards:'), + var_name = 'deal_max_cards', + ) WizardWidgets = ( _('General'), @@ -277,6 +298,7 @@ WizardWidgets = ( TalonType, Redeals, DealToWaste, + TalonShuffle, _('Foundations'), FoundType, FoundBaseCard, @@ -296,9 +318,10 @@ WizardWidgets = ( ReservesMaxAccept, _('Initial dealing'), DealType, + DealFaceDown, DealFaceUp, - DealMaxRows, DealToReseves, + DealMaxCards, ) @@ -319,17 +342,16 @@ def write_game(app, game=None): check_game = True else: # edit current game - fn = game.SETTINGS['file'] - fn = os.path.join(app.dn.plugins, fn) + fn = game.MODULE_FILENAME mn = game.__module__ gameid = game.SETTINGS['gameid'] - n = gameid-200000 check_game = False ##print '===>', fn fd = open(fn, 'w') fd.write('''\ +## -*- coding: utf-8 -*- ## THIS FILE WAS GENERATED AUTOMATICALLY BY SOLITAIRE WIZARD ## DO NOT EDIT @@ -345,18 +367,19 @@ class MyCustomGame(CustomGame): continue v = w.variable.get() if w.widget == 'menu': - v = w.translate_map[v] + v = w.translation_map[v] if isinstance(v, int): fd.write(" '%s': %i,\n" % (w.var_name, v)) else: if w.var_name == 'name': v = v.replace('\\', '\\\\') v = v.replace("'", "\\'") + if isinstance(v, unicode): + v = v.encode('utf-8') if not v: v = 'Invalid Game Name' fd.write(" '%s': '%s',\n" % (w.var_name, v)) fd.write(" 'gameid': %i,\n" % gameid) - fd.write(" 'file': '%s',\n" % os.path.split(fn)[1]) fd.write('''\ }