diff --git a/pysollib/actions.py b/pysollib/actions.py index 1a2104d7..54917d87 100644 --- a/pysollib/actions.py +++ b/pysollib/actions.py @@ -339,32 +339,29 @@ class PysolMenubarActions: if self.changed(): if not self.game.areYouSure(_("Select random game")): return game_id = None - for i in range(1000): # just in case, don't loop forever - gi = self.app.getGameInfo(self.app.getRandomGameId()) - if gi is None: - continue + games = [] + for g in self.app.gdb.getGamesIdSortedById(): + gi = self.app.getGameInfo(g) if 1 and gi.id == self.game.id: # force change of game continue if 1 and gi.category != self.game.gameinfo.category: # don't change game category continue - if type == 'all': - game_id = gi.id - break won, lost = self.app.stats.getStats(self.app.opt.player, gi.id) - if type == 'won' and won > 0: - game_id = gi.id - break - if type == 'not won' and won == 0 and lost > 0: - game_id = gi.id - break - if type == 'not played' and won+lost == 0: - game_id = gi.id - break + if type == 'all': + games.append(gi.id) + elif type == 'won' and won > 0: + games.append(gi.id) + elif type == 'not won' and won == 0 and lost > 0: + games.append(gi.id) + elif type == 'not played' and won+lost == 0: + games.append(gi.id) + if games: + game_id = self.app.getRandomGameId(games) if game_id and game_id != self.game.id: self.game.endGame() - self.game.quitGame(gi.id) + self.game.quitGame(game_id) def _mSelectNextGameFromList(self, gl, step): if self._cancelDrag(): return diff --git a/pysollib/app.py b/pysollib/app.py index c70b7a60..7b6ef030 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -1218,8 +1218,10 @@ Please select a %s type %s. n = re.sub(r"[^\w]", "", n) return n - def getRandomGameId(self): - return self.miscrandom.choice(self.gdb.getGamesIdSortedById()) + def getRandomGameId(self, games=None): + if games is None: + return self.miscrandom.choice(self.gdb.getGamesIdSortedById()) + return self.miscrandom.choice(games) def getAllUserNames(self): names = [] diff --git a/pysollib/game.py b/pysollib/game.py index 37c740b6..903886c4 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -249,6 +249,14 @@ class Game: print 'WARNING: shallHighlightMatch is not valid (wrap):', \ class_name, r.__class__ break + if self.s.talon.max_rounds > 1 and \ + self.s.talon.texts.rounds is None: + print 'WARNING: max_rounds > 1, but talon.texts.rounds is None:', \ + class_name + elif self.s.talon.max_rounds <= 1 and \ + self.s.talon.texts.rounds is not None: + print 'WARNING: max_rounds <= 1, but talon.texts.rounds is not None:', \ + class_name def initBindings(self): @@ -2071,7 +2079,8 @@ Congratulations, you did it ! def getQuickPlayScore(self, ncards, from_stack, to_stack): if to_stack in self.s.reserves: # if to_stack in reserves prefer empty stack - return 1000-len(to_stack.cards) + ##return 1000 - len(to_stack.cards) + return 1000 - int(len(to_stack.cards) != 0) # prefer non-empty piles in to_stack return 1001 + int(len(to_stack.cards) != 0) diff --git a/pysollib/games/auldlangsyne.py b/pysollib/games/auldlangsyne.py index 52789338..8eba1e75 100644 --- a/pysollib/games/auldlangsyne.py +++ b/pysollib/games/auldlangsyne.py @@ -72,10 +72,7 @@ class TamOShanter(Game): s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, "s") if texts: - tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nn') x, y = l.XM+2*l.XS, l.YM for i in range(4*self.gameinfo.decks): s.foundations.append(self.Foundation_Class(x, y, self, suit=i%4)) @@ -273,10 +270,7 @@ class Interregnum(Game): s.rows.append(self.RowStack_Class(x, y, self)) s.talon = self.Talon_Class(self.width-l.XS, self.height-l.YS, self) if texts: - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nn') else: l.createText(s.talon, "n") @@ -404,12 +398,12 @@ class Colorado(Game): for i in range(4): s.foundations.append(self.Foundation_Class(x, y, self, suit=i, max_move=0)) - x = x + l.XS + x += l.XS x += 2*l.XM for i in range(4): s.foundations.append(self.Foundation_Class(x, y, self, suit=i, max_move=0, base_rank=KING, dir=-1)) - x = x + l.XS + x += l.XS y = l.YM+l.YS for i in range(2): @@ -422,9 +416,9 @@ class Colorado(Game): x += l.XS y += l.YS - x, y = l.XM+9*l.XS, l.YM+3*l.YS + x, y = l.XM + 9*l.XS, self.height - l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=1) - l.createText(s.talon, "s") + l.createText(s.talon, "n") x -= l.XS s.waste = WasteStack(x, y, self, max_cards=1) diff --git a/pysollib/games/bakersdozen.py b/pysollib/games/bakersdozen.py index d354378a..dadaee11 100644 --- a/pysollib/games/bakersdozen.py +++ b/pysollib/games/bakersdozen.py @@ -75,6 +75,7 @@ class CastlesInSpain(Game): s.rows.append(self.RowStack_Class(r.x, r.y, self)) # default l.defaultAll() + return l def startGame(self, flip=(0, 0, 0)): for f in flip: @@ -252,7 +253,7 @@ class Cruel(CastlesInSpain): Solver_Class = None def createGame(self): - CastlesInSpain.createGame(self, rows=12) + return CastlesInSpain.createGame(self, rows=12) def _shuffleHook(self, cards): # move Aces to bottom of the Talon (i.e. last cards to be dealt) @@ -275,6 +276,11 @@ class RoyalFamily(Cruel): Talon_Class = StackWrapper(Cruel_Talon, max_rounds=2) RowStack_Class = UD_AC_RowStack + def createGame(self): + l = Cruel.createGame(self) + l.createRoundText(self.s.talon, 'sw') + + def _shuffleHook(self, cards): # move Kings to bottom of the Talon (i.e. last cards to be dealt) return self._shuffleHookMoveToBottom(cards, lambda c: (c.rank == KING, c.suit)) @@ -287,6 +293,10 @@ class Indefatigable(Cruel): Talon_Class = StackWrapper(Cruel_Talon, max_rounds=3) RowStack_Class = UD_SS_RowStack + def createGame(self): + l = Cruel.createGame(self) + l.createRoundText(self.s.talon, 'sw') + def _shuffleHook(self, cards): # move Aces to bottom of the Talon (i.e. last cards to be dealt) return self._shuffleHookMoveToBottom(cards, lambda c: (c.rank == ACE, c.suit)) @@ -300,9 +310,15 @@ class Indefatigable(Cruel): class Perseverance(Cruel, BakersDozen): 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 createGame(self): + l = Cruel.createGame(self) + l.createRoundText(self.s.talon, 'sw') + def _shuffleHook(self, cards): # move Kings to bottom of each stack (???) #cards = BakersDozen._shuffleHook(self, cards) diff --git a/pysollib/games/beleagueredcastle.py b/pysollib/games/beleagueredcastle.py index 878cd48b..74a5980d 100644 --- a/pysollib/games/beleagueredcastle.py +++ b/pysollib/games/beleagueredcastle.py @@ -608,11 +608,11 @@ class CastleOfIndolence(Game): # create stacks x, y = l.XM, l.YM+4*l.YS s.talon = InitialDealTalonStack(x, y, self) - x, y = l.XM+w-l.XS, l.YM+4*l.YS + x, y = l.XM+w-l.XS, self.height-l.YS for i in range(4): stack = OpenStack(x, y, self, max_accept=0) s.reserves.append(stack) - l.createText(stack, 's') + l.createText(stack, 'n') x += l.XS x = l.XM + w diff --git a/pysollib/games/braid.py b/pysollib/games/braid.py index f4085f17..7cc484cb 100644 --- a/pysollib/games/braid.py +++ b/pysollib/games/braid.py @@ -159,10 +159,8 @@ class Braid(Game): x, y = l.XM + 7 * l.XS, l.YM + l.YS * 3/2 s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, "s") - s.talon.texts.rounds = MfxCanvasText(self.canvas, - x + l.CW / 2, y - l.TEXT_MARGIN, - anchor="s", font=font) - x = x - l.XS + l.createRoundText(s.talon, 'nn') + x -= l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") y = l.YM diff --git a/pysollib/games/calculation.py b/pysollib/games/calculation.py index 0964d4ef..72b118a6 100644 --- a/pysollib/games/calculation.py +++ b/pysollib/games/calculation.py @@ -235,7 +235,7 @@ class BetsyRoss(Calculation): stack = BetsyRoss_Foundation(x, y, self, base_rank=i, max_cards=1, max_move=0, max_accept=0) s.foundations.append(stack) - x = x + l.XS + x += l.XS x = x0 y = l.YM + l.YS for i in range(4): @@ -247,13 +247,15 @@ class BetsyRoss(Calculation): stack.texts.misc = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) s.foundations.append(stack) - x = x + l.XS - self.texts.help = MfxCanvasText(self.canvas, x + l.XM, y + l.CH / 2, text=help, - anchor="w", font=self.app.getFont("canvas_fixed")) + x += l.XS + self.texts.help = MfxCanvasText(self.canvas, x + l.XM, y + l.CH / 2, + text=help, anchor="w", + font=self.app.getFont("canvas_fixed")) x = l.XM s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, "n") - y = y + l.YS + l.createRoundText(s.talon, 'nnn') + y += l.YS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") @@ -411,10 +413,7 @@ class SeniorWrangler(Game): x += l.XS x, y = l.XM, l.YM+l.YS s.talon = SeniorWrangler_Talon(x, y, self, max_rounds=9) - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nn') # define stack-groups l.defaultStackGroups() diff --git a/pysollib/games/camelot.py b/pysollib/games/camelot.py index 0a9034a3..cfb8bb4a 100644 --- a/pysollib/games/camelot.py +++ b/pysollib/games/camelot.py @@ -162,10 +162,12 @@ class Camelot(Game): s.rows.append(self.RowStack_Class(x, y, self)) x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) + l.createText(s.talon, 's') x, y = l.XM + w + 4*l.XS + w, l.YM s.foundations.append(Camelot_Foundation(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_accept=0, max_move=0, max_cards=52)) + l.createText(s.foundations[0], 's') # define stack-groups l.defaultStackGroups() return l diff --git a/pysollib/games/canfield.py b/pysollib/games/canfield.py index abd54277..c41afe38 100644 --- a/pysollib/games/canfield.py +++ b/pysollib/games/canfield.py @@ -106,7 +106,8 @@ class Canfield(Game): # game layout # - def createGame(self, rows=4, max_rounds=-1, num_deal=3, text=True): + def createGame(self, rows=4, max_rounds=-1, num_deal=3, + text=True, round_text=False): # create layout l, s = Layout(self), self.s decks = self.gameinfo.decks @@ -120,6 +121,8 @@ class Canfield(Game): yoffset = 5 # (piles up to 20 cards are playable in default window size) h = max(3*l.YS, l.YS+self.INITIAL_RESERVE_CARDS*yoffset) + if round_text: + h += l.TEXT_HEIGHT self.setSize(l.XM + (2+max(rows, 4*decks))*l.XS + l.XM, l.YM + l.YS + l.TEXT_HEIGHT + h) # extra settings @@ -127,16 +130,21 @@ class Canfield(Game): # create stacks x, y = l.XM, l.YM - s.talon = self.Talon_Class(x, y, self, max_rounds=max_rounds, num_deal=num_deal) + s.talon = self.Talon_Class(x, y, self, + max_rounds=max_rounds, num_deal=num_deal) l.createText(s.talon, "s") - x = x + l.XS + if round_text: + l.createRoundText(s.talon, 'sss') + x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") - x = x + l.XM + x += l.XM + y = l.YM for i in range(4): for j in range(decks): - x = x + l.XS - s.foundations.append(self.Foundation_Class(x, y, self, i, mod=13, max_move=0)) + x += l.XS + s.foundations.append(self.Foundation_Class(x, y, self, i, + mod=13, max_move=0)) if text: if rows > 4 * decks: tx, ty, ta, tf = l.getTextAttr(None, "se") @@ -148,12 +156,16 @@ class Canfield(Game): self.texts.info = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) x, y = l.XM, l.YM + l.YS + l.TEXT_HEIGHT + if round_text: + y += l.TEXT_HEIGHT s.reserves.append(self.ReserveStack_Class(x, y, self)) s.reserves[0].CARD_YOFFSET = yoffset - x = l.XM + 2 * l.XS + l.XM + x, y = l.XM + 2 * l.XS + l.XM, l.YM + l.YS + if text: + y += l.TEXT_HEIGHT for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) - x = x + l.XS + x += l.XS # define stack-groups l.defaultStackGroups() @@ -240,7 +252,7 @@ class SuperiorCanfield(Canfield): class Rainfall(Canfield): def createGame(self): - Canfield.createGame(self, max_rounds=3, num_deal=1) + Canfield.createGame(self, max_rounds=3, num_deal=1, round_text=True) # /*********************************************************************** @@ -263,7 +275,7 @@ class Storehouse(Canfield): RowStack_Class = StackWrapper(Canfield_SS_RowStack, mod=13) def createGame(self): - Canfield.createGame(self, max_rounds=3, num_deal=1) + Canfield.createGame(self, max_rounds=3, num_deal=1, round_text=True) def _shuffleHook(self, cards): # move Twos to top of the Talon (i.e. first cards to be dealt) @@ -315,7 +327,8 @@ class AmericanToad(Canfield): INITIAL_RESERVE_FACEUP = 1 def createGame(self): - Canfield.createGame(self, rows=8, max_rounds=2, num_deal=1) + Canfield.createGame(self, rows=8, max_rounds=2, num_deal=1, + round_text=True) shallHighlightMatch = Game._shallHighlightMatch_SSW @@ -330,7 +343,8 @@ class VariegatedCanfield(Canfield): INITIAL_RESERVE_FACEUP = 1 def createGame(self): - Canfield.createGame(self, rows=5, max_rounds=3) + Canfield.createGame(self, rows=5, max_rounds=3, + text=False, round_text=True) def _shuffleHook(self, cards): # move Aces to top of the Talon (i.e. first cards to be dealt) @@ -375,7 +389,8 @@ class EagleWing(Canfield): x, y = l.XM, l.YM s.talon = WasteTalonStack(x, y, self, max_rounds=3, num_deal=1) l.createText(s.talon, "s") - x = x + l.XS + l.createRoundText(s.talon, 'ne', dx=l.XS) + x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") for i in range(4): @@ -521,14 +536,19 @@ class Doorway(LittleGate): def createGame(self): l = LittleGate.createGame(self, rows=5) - tx, ty, ta, tf = l.getTextAttr(self.s.reserves[0], "s") + king_stack, queen_stack = self.s.reserves + tx, ty, ta, tf = l.getTextAttr(king_stack, "s") font = self.app.getFont("canvas_default") - MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font, text=_('King')) - tx, ty, ta, tf = l.getTextAttr(self.s.reserves[1], "s") + king_stack.texts.misc = MfxCanvasText(self.canvas, tx, ty, + anchor=ta, font=font, + text=_('King')) + tx, ty, ta, tf = l.getTextAttr(queen_stack, "s") font = self.app.getFont("canvas_default") - MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font, text=_('Queen')) - self.s.reserves[0].cap.base_rank = KING - self.s.reserves[1].cap.base_rank = QUEEN + queen_stack.texts.misc = MfxCanvasText(self.canvas, tx, ty, + anchor=ta, font=font, + text=_('Queen')) + king_stack.cap.base_rank = KING + queen_stack.cap.base_rank = QUEEN def startGame(self): self.startDealSample() @@ -554,7 +574,8 @@ class Minerva(Canfield): INITIAL_RESERVE_CARDS = 11 def createGame(self): - Canfield.createGame(self, rows=7, max_rounds=2, num_deal=1, text=False) + Canfield.createGame(self, rows=7, max_rounds=2, num_deal=1, + text=False, round_text=True) def startGame(self): self.s.talon.dealRow(frames=0, flip=0) @@ -608,7 +629,7 @@ class Acme(Canfield): Hint_Class = Canfield_Hint def createGame(self): - Canfield.createGame(self, max_rounds=2, num_deal=1) + Canfield.createGame(self, max_rounds=2, num_deal=1, round_text=True) def _shuffleHook(self, cards): # move Aces to top of the Talon (i.e. first cards to be dealt) @@ -644,43 +665,34 @@ class Duke(Game): ReserveStack_Class = OpenStack RowStack_Class = AC_RowStack - def createGame(self, max_rounds=3, texts=False): + def createGame(self): l, s = Layout(self), self.s - w, h = l.XM+6*l.XS+4*l.XOFFSET, l.YM+2*l.YS+12*l.YOFFSET - if texts: - h += l.TEXT_HEIGHT + w, h = l.XM + 6*l.XS + 4*l.XOFFSET, l.YM + l.TEXT_HEIGHT + 2*l.YS + 12*l.YOFFSET self.setSize(w, h) - self.base_card = None - x, y = l.XM, l.YM - s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds) + s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 's') + l.createRoundText(s.talon, 'ne', dx=l.XS) x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 's') x += l.XS+4*l.XOFFSET + y = l.YM for i in range(4): s.foundations.append(self.Foundation_Class(x, y, self, suit=i)) x += l.XS - x0, y0, w = l.XM, l.YM+l.YS+l.TEXT_HEIGHT, l.XS+2*l.XOFFSET + x0, y0, w = l.XM, l.YM+l.YS+2*l.TEXT_HEIGHT, l.XS+2*l.XOFFSET for i, j in ((0,0), (0,1), (1,0), (1,1)): x, y = x0+i*w, y0+j*l.YS stack = self.ReserveStack_Class(x, y, self, max_accept=0) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 s.reserves.append(stack) x, y = l.XM+2*l.XS+4*l.XOFFSET, l.YM+l.YS - if texts: - y += l.TEXT_HEIGHT for i in range(4): s.rows.append(self.RowStack_Class(x, y, self)) x += l.XS - if texts: - tx, ty, ta, tf = l.getTextAttr(s.foundations[-1], "ss") - font = self.app.getFont("canvas_default") - self.texts.info = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) l.defaultStackGroups() @@ -720,7 +732,7 @@ class CanfieldRush(Canfield): Talon_Class = CanfieldRush_Talon #RowStack_Class = StackWrapper(AC_RowStack, mod=13) def createGame(self): - Canfield.createGame(self, max_rounds=3) + Canfield.createGame(self, max_rounds=3, round_text=True) # /*********************************************************************** diff --git a/pysollib/games/capricieuse.py b/pysollib/games/capricieuse.py index 64060675..e85ebfc0 100644 --- a/pysollib/games/capricieuse.py +++ b/pysollib/games/capricieuse.py @@ -48,7 +48,7 @@ class Capricieuse(Game): # game layout # - def createGame(self, rows=12): + def createGame(self, rows=12, round_text=True): # create layout l, s = Layout(self), self.s @@ -60,20 +60,22 @@ class Capricieuse(Game): x, y, = l.XM+(rows-8)*l.XS/2, l.YM for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) - x = x + l.XS + x += l.XS for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i, base_rank=KING, dir=-1)) - x = x + l.XS + x += l.XS x, y, = l.XM, y + l.YS for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self, max_move=1, max_accept=1)) - x = x + l.XS + x += l.XS s.talon = self.Talon_Class(l.XM, l.YM, self) + if round_text: + l.createRoundText(self.s.talon, 'ne') - # default - l.defaultAll() + # define stack-groups + l.defaultStackGroups() # # game overrides @@ -105,6 +107,9 @@ class Nationale(Capricieuse): Talon_Class = InitialDealTalonStack RowStack_Class = StackWrapper(UD_SS_RowStack, mod=13) + def createGame(self): + Capricieuse.createGame(self, round_text=False) + shallHighlightMatch = Game._shallHighlightMatch_SSW @@ -129,11 +134,12 @@ class Strata(Game): s.foundations.append(DieRussische_Foundation(x, y, self, suit=i%4, max_cards=8)) x = x + l.XS - x, y, = l.XM+l.XS/2, l.YM+l.YS + x, y, = l.XM+l.XS, l.YM+l.YS for i in range(8): s.rows.append(AC_RowStack(x, y, self, max_move=1, max_accept=1)) x = x + l.XS - s.talon = RedealTalonStack(l.XM, l.YM, self, max_rounds=3) + s.talon = RedealTalonStack(l.XM, l.YM+l.YS/2, self, max_rounds=3) + l.createRoundText(s.talon, 'nn') # define stack-groups l.defaultStackGroups() @@ -159,7 +165,7 @@ class Fifteen(Capricieuse): Talon_Class = InitialDealTalonStack def createGame(self): - Capricieuse.createGame(self, rows=15) + Capricieuse.createGame(self, rows=15, round_text=False) def startGame(self): for i in range(6): diff --git a/pysollib/games/curdsandwhey.py b/pysollib/games/curdsandwhey.py index 20db53a8..4b81df13 100644 --- a/pysollib/games/curdsandwhey.py +++ b/pysollib/games/curdsandwhey.py @@ -467,10 +467,7 @@ class FourPacks(Game): x, y = self.width-l.XS, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty-l.TEXT_MARGIN, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nnn') x -= l.XS s.waste = WasteStack(x, y, self) diff --git a/pysollib/games/dieboesesieben.py b/pysollib/games/dieboesesieben.py index 763febb9..1bbdeb63 100644 --- a/pysollib/games/dieboesesieben.py +++ b/pysollib/games/dieboesesieben.py @@ -103,7 +103,8 @@ class DieBoeseSieben(Game): x, y, = l.XM + (2*i+8-rows)*l.XS/2, l.YM + l.YS s.rows.append(AC_RowStack(x, y, self)) s.talon = DieBoeseSieben_Talon(l.XM, self.height-l.YS, self, max_rounds=2) - l.createText(s.talon, "se") + l.createText(s.talon, 'ne') + l.createRoundText(s.talon, 'se') # define stack-groups l.defaultStackGroups() diff --git a/pysollib/games/diplomat.py b/pysollib/games/diplomat.py index 297a28af..88176fb5 100644 --- a/pysollib/games/diplomat.py +++ b/pysollib/games/diplomat.py @@ -82,6 +82,8 @@ class Diplomat(Game): x, y, = l.XM, self.height - l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds) l.createText(s.talon, "n") + if max_rounds > 1: + l.createRoundText(self.s.talon, 'nnn') x = x + l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "n") @@ -166,10 +168,7 @@ class Congress(Diplomat): s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") if max_rounds > 1: - tx, ty, ta, tf = l.getTextAttr(s.waste, "ne") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne', dx=l.XS) # define stack-groups l.defaultStackGroups() diff --git a/pysollib/games/doublets.py b/pysollib/games/doublets.py index 21734152..49150621 100644 --- a/pysollib/games/doublets.py +++ b/pysollib/games/doublets.py @@ -90,6 +90,7 @@ class Doublets(Game): x = x + l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") + l.createRoundText(s.talon, 'nn') # define stack-groups l.defaultStackGroups() diff --git a/pysollib/games/fan.py b/pysollib/games/fan.py index 7024864f..ba367154 100644 --- a/pysollib/games/fan.py +++ b/pysollib/games/fan.py @@ -108,11 +108,7 @@ class Fan(Game): x, y = self.width - l.XS, self.height - l.YS s.talon = self.Talon_Class(x, y, self) if texts: - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) - + l.createRoundText(s.talon, 'nn') # define stack-groups l.defaultStackGroups() @@ -238,6 +234,8 @@ class LaBelleLucie_Talon(TalonStack): class LaBelleLucie(Fan): Talon_Class = StackWrapper(LaBelleLucie_Talon, max_rounds=3) RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK) + def createGame(self): + return Fan.createGame(self, texts=True) # /*********************************************************************** @@ -356,7 +354,7 @@ class Trefoil(LaBelleLucie): Foundation_Classes = [StackWrapper(SS_FoundationStack, min_cards=1)] def createGame(self): - return Fan.createGame(self, rows=(5,5,5,1)) + return Fan.createGame(self, rows=(5,5,5,1), texts=True) def _shuffleHook(self, cards): # move Aces to bottom of the Talon (i.e. last cards to be dealt) @@ -434,6 +432,7 @@ class Intelligence(Fan): x, y = s.talon.x - l.XS, s.talon.y s.reserves.append(Intelligence_ReserveStack(x, y, self, max_move=0, max_accept=0, max_cards=UNLIMITED_CARDS)) l.createText(s.reserves[0], "sw") + l.createRoundText(s.talon, 'nn') # redefine the stack-groups l.defaultStackGroups() @@ -713,10 +712,7 @@ class Crescent(Game): self.setSize(w, h) x, y = l.XM, l.YM s.talon = Crescent_Talon(x, y, self, max_rounds=4) - tx, ty, ta, tf = l.getTextAttr(s.talon, 'ne') - font=self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') x, y = w-8*l.XS, l.YM for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) @@ -765,7 +761,7 @@ class School(Fan): RowStack_Class = StackWrapper(RK_RowStack, dir=0, base_rank=NO_RANK) def createGame(self): - Fan.createGame(self, rows=(4, 4, 4, 4), playcards=10) + Fan.createGame(self, rows=(4, 4, 4, 4), playcards=10, texts=True) def startGame(self): for i in range(2): @@ -895,10 +891,7 @@ class ForestGlade(Game): x, y = l.XM, self.height - l.YS s.talon = ForestGlade_Talon(x, y, self, max_rounds=3) l.createText(s.talon, 'ne') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'se') - font=self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'se') l.defaultStackGroups() diff --git a/pysollib/games/fortythieves.py b/pysollib/games/fortythieves.py index 5b117d81..52c49710 100644 --- a/pysollib/games/fortythieves.py +++ b/pysollib/games/fortythieves.py @@ -115,13 +115,8 @@ class FortyThieves(Game): max_rounds=max_rounds, num_deal=num_deal) l.createText(s.talon, "n") if max_rounds > 1: - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, - tx, ty-l.TEXT_MARGIN, - anchor=ta, - font=font) - x = x - l.XS + l.createRoundText(s.talon, 'nnn') + x -= l.XS s.waste = WasteStack(x, y, self) s.waste.CARD_XOFFSET = -l.XOFFSET l.createText(s.waste, "n") @@ -711,33 +706,34 @@ class Octagon(Game): l, s = Layout(self), self.s w1 = l.XS+12*l.XOFFSET - w, h = l.XM+2*l.XS+2*w1, l.YM+3*l.YS + w, h = l.XM+2*l.XS+2*w1, l.YM+4*l.YS self.setSize(w, h) for x, y in ((l.XM, l.YM), (l.XM+w1+2*l.XS+l.XM, l.YM), - (l.XM, l.YM+2*l.YS), - (l.XM+w1+2*l.XS+l.XM, l.YM+2*l.YS),): + (l.XM, l.YM+3*l.YS), + (l.XM+w1+2*l.XS+l.XM, l.YM+3*l.YS),): stack = SS_RowStack(x, y, self, max_move=1) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 s.rows.append(stack) i = 0 - for x, y in ((l.XM+w1, l.YM), - (l.XM+w1+l.XS, l.YM), - (l.XM+w1-2*l.XS-l.XS/2-l.XM, l.YM+l.YS), - (l.XM+w1-l.XS-l.XS/2-l.XM, l.YM+l.YS), - (l.XM+w1+2*l.XS+l.XS/2+l.XM, l.YM+l.YS), - (l.XM+w1+3*l.XS+l.XS/2+l.XM, l.YM+l.YS), - (l.XM+w1, l.YM+2*l.YS), - (l.XM+w1+l.XS, l.YM+2*l.YS),): + for x, y in ((l.XM+w1, l.YM), + (l.XM+w1+l.XS, l.YM), + (l.XM+w1-2*l.XS-l.XS/2-l.XM, l.YM+1.5*l.YS), + (l.XM+w1-l.XS-l.XS/2-l.XM, l.YM+1.5*l.YS), + (l.XM+w1+2*l.XS+l.XS/2+l.XM, l.YM+1.5*l.YS), + (l.XM+w1+3*l.XS+l.XS/2+l.XM, l.YM+1.5*l.YS), + (l.XM+w1, l.YM+3*l.YS), + (l.XM+w1+l.XS, l.YM+3*l.YS),): s.foundations.append(SS_FoundationStack(x, y, self, suit=i%4)) i += 1 - x, y = l.XM+w1, l.YM+l.YS + x, y = l.XM+w1, l.YM+1.5*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=4) - l.createText(s.talon, 'nw') + l.createText(s.talon, 's') + l.createRoundText(s.talon, 'nn') x += l.XS s.waste = WasteStack(x, y, self) - l.createText(s.waste, 'ne') + l.createText(s.waste, 's') l.defaultStackGroups() @@ -1154,6 +1150,82 @@ class Floradora(Game): shallHighlightMatch = Game._shallHighlightMatch_RK +# /*********************************************************************** +# // Blind Patience +# ************************************************************************/ + +class BlindPatience_Hint(DefaultHint): + SCORE_FLIP = 80000 + + def shallMovePile(self, from_stack, to_stack, pile, rpile): + if from_stack is to_stack or not to_stack.acceptsCards(from_stack, pile): + return False + # + if len(rpile) == 0: + return True + # now check for loops + rr = self.ClonedStack(from_stack, stackcards=rpile) + if self.level < 2: + # hint + if to_stack.cards and not to_stack.cards[-1].face_up: + if rr.cards and not rr.cards[-1].face_up: + return True + if rr.cards and not rr.cards[-1].face_up: + return True + if not to_stack.cards: + return True + else: + # demo mode + if rr.cards and not rr.cards[-1].face_up: + if len(rr.cards) < len(to_stack.cards): + return True + 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 False + return True + + +class BlindPatience_RowStack(AC_RowStack): + def acceptsCards(self, from_stack, cards): + if self.cards and not self.cards[-1].face_up: + return True + return AC_RowStack.acceptsCards(self, from_stack, cards) + + +class BlindPatience(FortyThieves): + Hint_Class = BlindPatience_Hint + RowStack_Class = BlindPatience_RowStack + + def startGame(self): + for i in range(3): + self.s.talon.dealRow(flip=0, frames=0) + self.startDealSample() + self.s.talon.dealRow(flip=0) + self.s.talon.dealCards() # deal first card to WasteStack + + def getAutoStacks(self, event=None): + if event is None: + # do not auto flip + return ([], self.sg.dropstacks, self.sg.dropstacks) + return (self.sg.dropstacks, self.sg.dropstacks, self.sg.dropstacks) + + def getQuickPlayScore(self, ncards, from_stack, to_stack): + if to_stack in self.s.rows: + if to_stack.cards: + if to_stack.cards[-1].face_up: + # top card is face up + return 1001 + else: + return 1000 + else: + return 999 + # prefer non-empty piles in to_stack + return 1001 + int(len(to_stack.cards) != 0) + + shallHighlightMatch = Game._shallHighlightMatch_AC + + # register the game registerGame(GameInfo(13, FortyThieves, "Forty Thieves", @@ -1271,4 +1343,6 @@ registerGame(GameInfo(679, TripleInterchange, "Triple Interchange", GI.GT_FORTY_THIEVES, 3, -1, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(683, FamousFifty, "Famous Fifty", GI.GT_FORTY_THIEVES, 2, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(751, BlindPatience, "Blind Patience", + GI.GT_FORTY_THIEVES, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/glenwood.py b/pysollib/games/glenwood.py index 539be55e..f8be2761 100644 --- a/pysollib/games/glenwood.py +++ b/pysollib/games/glenwood.py @@ -104,16 +104,17 @@ class Glenwood(Game): l, s = Layout(self), self.s # set window - self.setSize(2*l.XM + 6*l.XS, l.YM + l.TEXT_HEIGHT + 5*l.YS) + self.setSize(l.XM + 7*l.XS, l.YM + l.TEXT_HEIGHT + 5*l.YS) # create stacks x, y = l.XM, l.YM s.talon = Glenwood_Talon(x, y, self, max_rounds=2, num_deal=1) l.createText(s.talon, "s") + l.createRoundText(s.talon, 'ne', dx=l.XS) x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") - x += l.XS+l.XM + x += 2*l.XS for i in range(4): s.foundations.append(self.Foundation_Class(x, y, self, i, dir=1, mod=13, base_rank=ANY_RANK, max_move=0)) @@ -126,7 +127,7 @@ class Glenwood(Game): anchor=ta, font=font) for i in range(4): - x = 2*l.XM + (i+2)*l.XS + x = l.XM + (i+3)*l.XS y = l.YM+l.TEXT_HEIGHT+l.YS s.rows.append(self.RowStack_Class(x, y, self, mod=13)) for i in range(4): @@ -269,6 +270,7 @@ class DoubleFives(Glenwood): x, y = l.XM, self.height-l.YS s.talon = DoubleFives_Talon(x, y, self, max_rounds=2, num_deal=1) l.createText(s.talon, "n") + l.createRoundText(self.s.talon, 'nnn') x += l.XS for i in range(5): s.reserves.append(DoubleFives_WasteStack(x, y, self)) diff --git a/pysollib/games/golf.py b/pysollib/games/golf.py index 26049ba8..774efd38 100644 --- a/pysollib/games/golf.py +++ b/pysollib/games/golf.py @@ -493,10 +493,11 @@ class Robert(Game): s.foundations.append(BlackHole_Foundation(x, y, self, ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52)) x, y = l.XM+l.XS, l.YM+l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) - l.createText(s.talon, 'sw') + l.createText(s.talon, 'nw') + l.createRoundText(self.s.talon, 'se', dx=l.XS) x += l.XS s.waste = WasteStack(x, y, self) - l.createText(s.waste, 'se') + l.createText(s.waste, 'ne') # define stack-groups l.defaultStackGroups() @@ -581,6 +582,7 @@ class Dolphin(Game): max_cards = 52*self.gameinfo.decks s.foundations.append(RK_FoundationStack(x, y, self, base_rank=ANY_RANK, mod=13, max_cards=max_cards)) + l.createText(s.foundations[0], 'ne') x, y = l.XM, l.YM+l.YS for i in range(rows): s.rows.append(BasicRowStack(x, y, self)) @@ -817,11 +819,7 @@ class DevilsSolitaire(Game): x, y = l.XM+4.5*l.XS, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty-l.TEXT_MARGIN, - anchor=ta, font=font) - + l.createRoundText(s.talon, 'nnn') x -= l.XS s.waste = DevilsSolitaire_WasteStack(x, y, self) l.createText(s.waste, 'n') @@ -970,11 +968,7 @@ class NapoleonTakesMoscow(Game, FirTree_GameMethods): x, y = l.XM, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty-l.TEXT_MARGIN, - anchor=ta, font=font) - + l.createRoundText(s.talon, 'nnn') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 'n') diff --git a/pysollib/games/grandduchess.py b/pysollib/games/grandduchess.py index 003df89c..0336f7eb 100644 --- a/pysollib/games/grandduchess.py +++ b/pysollib/games/grandduchess.py @@ -91,10 +91,7 @@ class GrandDuchess(Game): x, y = l.XM, l.YM s.talon = GrandDuchess_Talon(x, y, self, max_rounds=4) l.createText(s.talon, 'se') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'ne') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') x += 2*l.XS for i in range(4): diff --git a/pysollib/games/grandfathersclock.py b/pysollib/games/grandfathersclock.py index 8daba1d4..5f0a1167 100644 --- a/pysollib/games/grandfathersclock.py +++ b/pysollib/games/grandfathersclock.py @@ -170,6 +170,7 @@ class Dial(Game): x, y = l.XM, l.YM s.talon = WasteTalonStack(x, y, self, max_rounds=2) l.createText(s.talon, 's') + l.createRoundText(s.talon, 'sss') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 's') diff --git a/pysollib/games/gypsy.py b/pysollib/games/gypsy.py index b2255eb2..00b3b3c9 100644 --- a/pysollib/games/gypsy.py +++ b/pysollib/games/gypsy.py @@ -860,10 +860,7 @@ class LockedCards(Game): x, y = self.width-l.XS, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty-l.TEXT_MARGIN, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nnn') x -= l.XS s.waste = WasteStack(x, y, self) diff --git a/pysollib/games/harp.py b/pysollib/games/harp.py index 33dc45aa..00b124b7 100644 --- a/pysollib/games/harp.py +++ b/pysollib/games/harp.py @@ -77,13 +77,10 @@ class DoubleKlondike(Game): l.defaultAll() # extra if max_rounds > 1: - assert s.talon.texts.rounds is None - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") + anchor = 'nn' if layout.get("texts"): - ty = ty - l.TEXT_MARGIN - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + anchor = 'nnn' + l.createRoundText(s.talon, anchor) return l def startGame(self, flip=0): @@ -249,12 +246,9 @@ class BigDeal(DoubleKlondike): s.waste.CARD_XOFFSET = XOFFSET l.createText(s.waste, 'n') if max_rounds > 1: - tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') - ty -= l.TEXT_MARGIN - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) - self.setRegion(s.rows, (-999, -999, l.XM+rows*l.XS-l.CW/2, 999999), priority=1) + l.createRoundText(s.talon, 'nnn') + self.setRegion(s.rows, (-999, -999, l.XM+rows*l.XS-l.CW/2, 999999), + priority=1) l.defaultStackGroups() diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py index ea5b2c56..5268624d 100644 --- a/pysollib/games/klondike.py +++ b/pysollib/games/klondike.py @@ -99,10 +99,11 @@ class VegasKlondike(Klondike): getGameBalance = Game.getGameScoreCasino def createGame(self, max_rounds=1): - Klondike.createGame(self, max_rounds=max_rounds) + l = Klondike.createGame(self, max_rounds=max_rounds) self.texts.score = MfxCanvasText(self.canvas, 8, self.height - 8, anchor="sw", font=self.app.getFont("canvas_large")) + return l def updateText(self): if self.preview > 1: @@ -123,7 +124,8 @@ class VegasKlondike(Klondike): class CasinoKlondike(VegasKlondike): def createGame(self): - VegasKlondike.createGame(self, max_rounds=3) + l = VegasKlondike.createGame(self, max_rounds=3) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) # /*********************************************************************** @@ -156,7 +158,9 @@ class Chinaman(ThumbAndPouch): RowStack_Class = StackWrapper(BO_RowStack, base_rank=KING) def createGame(self): - Klondike.createGame(self, num_deal=3, max_rounds=2) + l = Klondike.createGame(self, num_deal=3, + max_rounds=2, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) # /*********************************************************************** @@ -271,7 +275,8 @@ class PasSeul(Eastcliff): class BlindAlleys(Eastcliff): def createGame(self): - Klondike.createGame(self, max_rounds=2, rows=6) + l = Klondike.createGame(self, max_rounds=2, rows=6, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) def _shuffleHook(self, cards): # move Aces to top of the Talon (i.e. first cards to be dealt) @@ -317,7 +322,9 @@ class Usk(Somerset): Solver_Class = None def createGame(self): - Klondike.createGame(self, max_rounds=2, rows=10, waste=0, texts=0) + l = Klondike.createGame(self, max_rounds=2, rows=10, + waste=False, texts=False, round_text=True) + l.createRoundText(self.s.talon, 'ne') def redealCards(self): n = 0 @@ -403,12 +410,8 @@ class EightTimesEight(Klondike): class AchtmalAcht(EightTimesEight): def createGame(self): - l = Klondike.createGame(self, rows=8, max_rounds=3) - s = self.s - x, y = s.waste.x - l.XM, s.waste.y - s.talon.texts.rounds = MfxCanvasText(self.canvas, x, y, - anchor="ne", - font=self.app.getFont("canvas_default")) + l = Klondike.createGame(self, rows=8, max_rounds=3, round_text=True) + l.createRoundText(self.s.talon, 'sw', dx=-l.XS) class EightByEight_RowStack(RK_RowStack): @@ -425,7 +428,8 @@ class EightByEight(EightTimesEight): RowStack_Class = EightByEight_RowStack def createGame(self): - Klondike.createGame(self, rows=8, max_rounds=3) + l = Klondike.createGame(self, rows=8, max_rounds=3, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) shallHighlightMatch = Game._shallHighlightMatch_RK @@ -447,12 +451,16 @@ class Batsford_ReserveStack(ReserveStack): class Batsford(Klondike): def createGame(self, **layout): kwdefault(layout, rows=10, max_rounds=1, playcards=22) + round_text = (layout['max_rounds'] > 1) + layout['round_text'] = round_text l = Klondike.createGame(self, **layout) s = self.s x, y = l.XM, self.height - l.YS s.reserves.append(Batsford_ReserveStack(x, y, self, max_cards=3)) - self.setRegion(s.reserves, (-999, y - l.YM, x + l.XS, 999999), priority=1) + self.setRegion(s.reserves, (-999, y - l.YM - l.CH/2, x + l.XS - l.CW/2, 999999), priority=1) l.createText(s.reserves[0], "se") + if round_text: + l.createRoundText(self.s.talon, 'ne', dx=l.XS) l.defaultStackGroups() @@ -467,7 +475,8 @@ class BatsfordAgain(Batsford): class Jumbo(Klondike): def createGame(self): - Klondike.createGame(self, rows=9, max_rounds=2) + l = Klondike.createGame(self, rows=9, max_rounds=2, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) def startGame(self, flip=0): for i in range(9): @@ -805,7 +814,8 @@ class Lanes(Klondike): RowStack_Class = StackWrapper(AC_RowStack, base_rank=ANY_RANK, max_move=1) def createGame(self): - Klondike.createGame(self, rows=6, max_rounds=2) + l = Klondike.createGame(self, rows=6, max_rounds=2, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) def _shuffleHook(self, cards): # move Aces to top of the Talon (i.e. first cards to be dealt) @@ -866,7 +876,8 @@ class Q_C_(Klondike): RowStack_Class = StackWrapper(SS_RowStack, base_rank=ANY_RANK, max_move=1) def createGame(self): - Klondike.createGame(self, rows=6, max_rounds=2) + l = Klondike.createGame(self, rows=6, max_rounds=2) + l.createRoundText(self.s.talon, 'sss') def startGame(self): for i in range(3): @@ -1044,7 +1055,9 @@ class MovingLeft(Klondike): class Souter(MovingLeft): def createGame(self): - Klondike.createGame(self, max_rounds=2, rows=10, playcards=24) + l = Klondike.createGame(self, max_rounds=2, rows=10, + playcards=24, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) # /*********************************************************************** @@ -1127,7 +1140,8 @@ class Whitehorse(Klondike): class Boost(Klondike): def createGame(self): - Klondike.createGame(self, rows=4, max_rounds=3) + l = Klondike.createGame(self, rows=4, max_rounds=3, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) # /*********************************************************************** @@ -1137,7 +1151,8 @@ class Boost(Klondike): class GoldRush(Klondike): Talon_Class = CanfieldRush_Talon def createGame(self): - Klondike.createGame(self, max_rounds=3) + l = Klondike.createGame(self, max_rounds=3, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) # /*********************************************************************** @@ -1344,7 +1359,9 @@ class EightSages(Klondike): RowStack_Class = EightSages_Row def createGame(self): - Klondike.createGame(self, max_rounds=2, rows=8, playcards=12) + l = Klondike.createGame(self, max_rounds=2, rows=8, + playcards=12, round_text=True) + l.createRoundText(self.s.talon, 'ne', dx=l.XS) def startGame(self): self.startDealSample() diff --git a/pysollib/games/larasgame.py b/pysollib/games/larasgame.py index 060996a0..747c3409 100644 --- a/pysollib/games/larasgame.py +++ b/pysollib/games/larasgame.py @@ -247,11 +247,8 @@ class LarasGame(Game): x, y = l.XM + l.XS * (ROW_LENGTH + 2), h - l.YM - l.YS * 3 s.talon = self.Talon_Class(x, y, self, max_rounds=self.MAX_ROUNDS) l.createText(s.talon, "s") - if self.MAX_ROUNDS - 1: - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - s.talon.texts.rounds = MfxCanvasText(self.canvas, - tx, ty, anchor=ta, - font=self.app.getFont("canvas_default")) + if self.MAX_ROUNDS > 1: + l.createRoundText(s.talon, 'nn') y = h - l.YS * 2 s.rows.append(LarasGame_RowStack(x, y, self, yoffset=0)) diff --git a/pysollib/games/matriarchy.py b/pysollib/games/matriarchy.py index dce786ac..867ec424 100644 --- a/pysollib/games/matriarchy.py +++ b/pysollib/games/matriarchy.py @@ -192,9 +192,7 @@ class Matriarchy(Game): y = c2 + l.CH / 2 s.talon = Matriarchy_Talon(x, y, self, max_rounds=VARIABLE_REDEALS) l.createText(s.talon, "n") - s.talon.texts.rounds = MfxCanvasText(self.canvas, - tx, y + l.YS, anchor="n", - font=self.app.getFont("canvas_default")) + l.createRoundText(s.talon, 'ss') s.talon.texts.misc = MfxCanvasText(self.canvas, tx, center, anchor="center", font=self.app.getFont("canvas_large")) diff --git a/pysollib/games/montana.py b/pysollib/games/montana.py index 9fa09348..cba58a66 100644 --- a/pysollib/games/montana.py +++ b/pysollib/games/montana.py @@ -168,7 +168,7 @@ class Montana(Game): RLEN, RSTEP, RBASE = 52, 13, 1 - def createGame(self): + def createGame(self, round_text=True): # create layout l, s = Layout(self, card_x_space=4), self.s @@ -183,6 +183,8 @@ class Montana(Game): x = x + l.XS x = l.XM + (self.RSTEP-1)*l.XS/2 s.talon = self.Talon_Class(x, self.height-l.YS, self) + if round_text: + l.createRoundText(s.talon, 'se') if self.RBASE: # create an invisible stack to hold the four Aces s.internals.append(InvisibleStack(self)) @@ -387,6 +389,8 @@ class SpacesAndAces(BlueMoon): Talon_Class = InitialDealTalonStack RowStack_Class = SpacesAndAces_RowStack + def createGame(self): + Montana.createGame(self, round_text=False) # /*********************************************************************** # // Paganini diff --git a/pysollib/games/numerica.py b/pysollib/games/numerica.py index 40058ca2..f6763729 100644 --- a/pysollib/games/numerica.py +++ b/pysollib/games/numerica.py @@ -148,6 +148,8 @@ class Numerica(Game): # define stack-groups l.defaultStackGroups() + return l + # # game overrides @@ -280,26 +282,27 @@ class PussInTheCorner(Numerica): def createGame(self, rows=4): l, s = Layout(self), self.s - self.setSize(l.XM+4*l.XS, l.YM+4*l.YS) + self.setSize(l.XM+5*l.XS, l.YM+4*l.YS) for x, y in ((l.XM, l.YM ), - (l.XM+3*l.XS, l.YM ), + (l.XM+4*l.XS, l.YM ), (l.XM, l.YM+3*l.YS), - (l.XM+3*l.XS, l.YM+3*l.YS), + (l.XM+4*l.XS, l.YM+3*l.YS), ): stack = PussInTheCorner_RowStack(x, y, self, max_accept=1, max_move=1) stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 s.rows.append(stack) - for x, y in ((l.XM+ l.XS, l.YM+ l.YS), - (l.XM+ l.XS, l.YM+2*l.YS), - (l.XM+2*l.XS, l.YM+ l.YS), - (l.XM+2*l.XS, l.YM+2*l.YS), + for x, y in ((l.XM+1.5*l.XS, l.YM+ l.YS), + (l.XM+1.5*l.XS, l.YM+2*l.YS), + (l.XM+2.5*l.XS, l.YM+ l.YS), + (l.XM+2.5*l.XS, l.YM+2*l.YS), ): s.foundations.append(PussInTheCorner_Foundation(x, y, self, max_move=0)) - x, y = l.XM+3*l.XS/2, l.YM + x, y = l.XM + 2*l.XS, l.YM s.waste = s.talon = PussInTheCorner_Talon(x, y, self, max_rounds=2) l.createText(s.talon, 'se') + l.createRoundText(self.s.talon, 'ne') # define stack-groups l.defaultStackGroups() @@ -744,7 +747,7 @@ class AnnoDomini(Numerica): RowStack_Class = StackWrapper(AC_RowStack, mod=13) def createGame(self): - Numerica.createGame(self, max_rounds=3, waste_max_cards=UNLIMITED_CARDS) + l = Numerica.createGame(self, max_rounds=3, waste_max_cards=UNLIMITED_CARDS) year = str(time.localtime()[0]) i = 0 for s in self.s.foundations: @@ -756,6 +759,7 @@ class AnnoDomini(Numerica): d = JACK s.cap.base_rank = d i += 1 + l.createRoundText(self.s.talon, 'nn') def startGame(self): self.startDealSample() diff --git a/pysollib/games/pasdedeux.py b/pysollib/games/pasdedeux.py index 7d908c9c..a0672d0b 100644 --- a/pysollib/games/pasdedeux.py +++ b/pysollib/games/pasdedeux.py @@ -174,11 +174,8 @@ class PasDeDeux(Game): x, y = self.width - 2*l.XS, self.height - l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=2) l.createText(s.talon, "se") - s.talon.texts.rounds = MfxCanvasText(self.canvas, - x + l.XS, y, - anchor="nw", - font=self.app.getFont("canvas_default")) - x = x - l.XS + l.createRoundText(s.talon, 'ne') + x -= l.XS s.waste = PasDeDeux_Waste(x, y, self, max_move=0) l.createText(s.waste, "sw") s.internals.append(InvisibleStack(self)) # for _swapPairMove() diff --git a/pysollib/games/pileon.py b/pysollib/games/pileon.py index 18dbae0f..89214aeb 100644 --- a/pysollib/games/pileon.py +++ b/pysollib/games/pileon.py @@ -157,6 +157,7 @@ class Foursome(Game): x = l.XM+(max_rows-1)*l.XS s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT, max_cards=52, max_accept=0)) + l.createText(s.foundations[0], 'nw') x, y = l.XM+l.XS*(max_rows-rows)/2, l.YM+l.YS for i in range(rows): s.rows.append(UD_AC_RowStack(x, y, self, mod=13)) diff --git a/pysollib/games/pyramid.py b/pysollib/games/pyramid.py index 9f194e25..74a14ac2 100644 --- a/pysollib/games/pyramid.py +++ b/pysollib/games/pyramid.py @@ -240,10 +240,7 @@ class Pyramid(Game): if texts: l.createText(s.talon, "se") if s.talon.max_rounds > 1: - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font=self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') if waste: y = y + l.YS s.waste = self.WasteStack_Class(x, y, self, max_accept=1) @@ -252,6 +249,7 @@ class Pyramid(Game): s.foundations.append(self.Foundation_Class(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=52*decks)) + l.createText(s.foundations[0], 's') if reserves: x, y = l.XM+(max_rows-reserves)*l.XS/2, l.YM+4*l.YS for i in range(reserves): @@ -402,6 +400,7 @@ class Thirteens(Pyramid): s.foundations.append(Pyramid_Foundation(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=52)) + l.createText(s.foundations[0], 'n') # define stack-groups l.defaultStackGroups() @@ -480,6 +479,7 @@ class Elevens(Pyramid): s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT, max_accept=0, max_move=0, max_cards=52)) + l.createText(s.foundations[0], 'n') y = l.YM for i in range(rows): x = l.XM @@ -684,6 +684,7 @@ class TripleAlliance(Game): x, y = self.width-l.XS, l.YM s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT, max_move=0, max_accept=0, max_cards=52)) + l.createText(s.foundations[0], 'nw') y = l.YM+l.YS nstacks = 0 for i in range(4): @@ -836,6 +837,7 @@ class Baroness(Pyramid): s.foundations.append(Pyramid_Foundation(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=52)) + l.createText(s.foundations[0], 's') x, y = l.XM, self.height-l.YS s.reserves.append(Giza_Reserve(x, y, self, max_accept=1)) y -= l.YS @@ -899,10 +901,8 @@ class Apophis(Pharaohs): x, y = l.XM, l.YM s.talon = DealReserveRedealTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'se') - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') + y += l.YS for i in range(3): stack = Pyramid_Waste(x, y, self, max_accept=1) @@ -913,6 +913,7 @@ class Apophis(Pharaohs): s.foundations.append(Pyramid_Foundation(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=52)) + l.createText(s.foundations[0], 'nw') # define stack-groups l.defaultStackGroups() @@ -1087,10 +1088,8 @@ class TwoPyramids(Pyramid): x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, "se") - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') + y += l.YS s.waste = self.WasteStack_Class(x, y, self, max_accept=1) l.createText(s.waste, "se") @@ -1098,6 +1097,7 @@ class TwoPyramids(Pyramid): s.foundations.append(self.Foundation_Class(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=104)) + l.createText(s.foundations[0], 'nw') # define stack-groups l.defaultStackGroups() self.sg.openstacks.append(s.talon) @@ -1133,6 +1133,7 @@ class KingTut(RelaxedPyramid): s.foundations.append(self.Foundation_Class(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=52)) + l.createText(s.foundations[0], 'nw') l.defaultStackGroups() self.sg.openstacks.append(s.waste) @@ -1169,10 +1170,8 @@ class Triangle(Pyramid): x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, "se") - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font=self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') + y += l.YS s.waste = self.WasteStack_Class(x, y, self, max_accept=1) l.createText(s.waste, "se") @@ -1212,10 +1211,8 @@ class UpAndDown(Pyramid): x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, "se") - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font=self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') + y += l.YS s.waste = self.WasteStack_Class(x, y, self, max_accept=1) l.createText(s.waste, "se") @@ -1223,6 +1220,7 @@ class UpAndDown(Pyramid): s.foundations.append(self.Foundation_Class(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_move=0, max_cards=104)) + l.createText(s.foundations[0], 'sw') # define stack-groups l.defaultStackGroups() diff --git a/pysollib/games/royalcotillion.py b/pysollib/games/royalcotillion.py index 263b5fdf..fa557073 100644 --- a/pysollib/games/royalcotillion.py +++ b/pysollib/games/royalcotillion.py @@ -41,6 +41,7 @@ from pysollib.stack import * from pysollib.game import Game from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from pysollib.pysoltk import MfxCanvasText from unionsquare import UnionSquare_Foundation @@ -153,6 +154,7 @@ class OddAndEven(RoyalCotillion): x, y = l.XM, self.height - l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=2) l.createText(s.talon, "n") + l.createRoundText(s.talon, 'nnn') x = x + l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "n") @@ -189,15 +191,15 @@ class Kingdom(RoyalCotillion): x, y, = l.XM, l.YM for i in range(8): s.foundations.append(self.Foundation_Class(x, y, self, ANY_SUIT)) - x = x + l.XS + x += l.XS x, y, = l.XM, y + l.YS for i in range(8): s.reserves.append(ReserveStack(x, y, self, max_accept=0)) - x = x + l.XS - x, y = l.XM + 3*l.XS, y + 3*l.YS/2 + x += l.XS + x, y = l.XM + 3*l.XS, l.YM + 3*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=1) l.createText(s.talon, "sw") - x = x + l.XS + x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "se") @@ -223,6 +225,7 @@ class Kingdom(RoyalCotillion): # /*********************************************************************** # // Alhambra # // Granada +# // Reserves # // Grant's Reinforcement # ************************************************************************/ @@ -233,6 +236,8 @@ class Alhambra_Hint(CautiousDefaultHint): class Alhambra_RowStack(UD_SS_RowStack): getBottomImage = Stack._getReserveBottomImage + def getHelp(self): + return _('Waste. Build up or down by suit.') class Alhambra_Talon(DealRowTalonStack): @@ -244,6 +249,13 @@ class Alhambra_Talon(DealRowTalonStack): return True return False + def _deal(self): + num_cards = 0 + for r in self.game.s.rows: + if self.cards: + self.game.flipAndMoveMove(self, r) + num_cards += 1 + def dealCards(self, sound=False): old_state = self.game.enterState(self.game.S_DEAL) num_cards = 0 @@ -252,7 +264,10 @@ class Alhambra_Talon(DealRowTalonStack): if self.cards: if sound and not self.game.demo: self.game.playSample("dealwaste") - num_cards = self.dealRowAvail(sound=False, frames=4) + if len(self.game.s.rows) > 1: + num_cards = self.dealRowAvail(sound=False, frames=4) + else: + num_cards = self._deal() elif r_cards and self.round != self.max_rounds: if sound: self.game.playSample("turnwaste", priority=20) @@ -260,7 +275,10 @@ class Alhambra_Talon(DealRowTalonStack): for i in range(len(r.cards)): self.game.moveMove(1, r, self, frames=0) self.game.flipMove(self) - num_cards = self.dealRowAvail(sound=False, frames=4) + if len(self.game.s.rows) > 1: + num_cards = self.dealRowAvail(sound=False, frames=4) + else: + num_cards = self._deal() self.game.nextRoundMove(self) self.game.leaveState(old_state) return num_cards @@ -276,7 +294,9 @@ class Alhambra(Game): l, s = Layout(self), self.s # set window - self.setSize(l.XM+8*l.XS, l.YM+3.5*l.YS+playcards*l.YOFFSET) + w, h = l.XM+8*l.XS, l.YM+3.5*l.YS+playcards*l.YOFFSET + h += l.TEXT_HEIGHT + self.setSize(w, h) # create stacks x, y, = l.XM, l.YM @@ -296,15 +316,25 @@ class Alhambra(Game): x = x + l.XS x, y = l.XM+(8-1-rows)*l.XS/2, self.height-l.YS s.talon = Alhambra_Talon(x, y, self, max_rounds=3) - l.createText(s.talon, "sw") + if rows == 1: + l.createText(s.talon, 'sw') + else: + l.createText(s.talon, 'n') + anchor = 'nn' + if rows > 1: + anchor = 'nnn' + l.createRoundText(s.talon, anchor) + x += l.XS for i in range(rows): stack = self.RowStack_Class(x, y, self, mod=13, max_accept=1) stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 s.rows.append(stack) x += l.XS - if rows == 1: - l.createText(stack, 'se') + if rows == 1: + l.createText(stack, 'se') + else: + l.createText(stack, 'n') # define stack-groups (non default) l.defaultStackGroups() @@ -333,8 +363,13 @@ class Granada(Alhambra): Alhambra.createGame(self, rows=4) -class GrantsReinforcement(Alhambra): - RowStack_Class = StackWrapper(Alhambra_RowStack, base_rank=NO_RANK) +class Reserves_RowStack(UD_RK_RowStack): + getBottomImage = Stack._getReserveBottomImage + def getHelp(self): + return _('Waste. Build up or down regardless of suit.') + +class Reserves(Alhambra): + RowStack_Class = StackWrapper(Reserves_RowStack, base_rank=NO_RANK) def createGame(self): Alhambra.createGame(self, reserves=4, playcards=11) @@ -347,6 +382,12 @@ class GrantsReinforcement(Alhambra): self.s.talon.dealRow(rows=self.s.reserves) self.s.talon.dealCards() + shallHighlightMatch = Game._shallHighlightMatch_RKW + + +class GrantsReinforcement(Reserves): + RowStack_Class = StackWrapper(Alhambra_RowStack, base_rank=NO_RANK) + def fillStack(self, stack): for r in self.s.reserves: if r.cards: @@ -357,6 +398,8 @@ class GrantsReinforcement(Alhambra): self.s.talon.moveMove(1, r) self.leaveState(old_state) + shallHighlightMatch = Game._shallHighlightMatch_SSW + # /*********************************************************************** # // Carpet @@ -512,6 +555,8 @@ class BritishConstitution(Game): class NewBritishConstitution(BritishConstitution): RowStack_Class = StackWrapper(NewBritishConstitution_RowStack, base_rank=JACK) + shallHighlightMatch = Game._shallHighlightMatch_RK + # /*********************************************************************** # // Twenty @@ -970,10 +1015,11 @@ class FourWinds(Game): # talon & waste x, y = l.XM+3.5*l.XS, l.YM+2.5*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=2) - l.createText(s.talon, 'n') + l.createText(s.talon, 's') + l.createRoundText(self.s.talon, 'nn') x += l.XS s.waste = WasteStack(x, y, self) - l.createText(s.waste, 'n') + l.createText(s.waste, 's') l.defaultStackGroups() @@ -1244,9 +1290,10 @@ class TwilightZone(Game): x += l.XS - x, y = l.XM, l.YM + x, y = l.XM, l.YM+l.YS/2 s.talon = TwilightZone_Talon(x, y, self, max_move=1, max_rounds=2) l.createText(s.talon, 's') + l.createRoundText(s.talon, 'nn') x += l.XS s.waste = TwilightZone_Waste(x, y, self, max_accept=1) l.createText(s.waste, 's') @@ -1315,7 +1362,7 @@ registerGame(GameInfo(579, ThreePirates, "Three Pirates", registerGame(GameInfo(608, Frames, "Frames", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(609, GrantsReinforcement, "Grant's Reinforcement", - GI.GT_2DECK_TYPE, 2, 2, GI.SL_MOSTLY_SKILL)) + GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) registerGame(GameInfo(638, RoyalRendezvous, "Royal Rendezvous", GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(639, ShadyLanes, "Shady Lanes", @@ -1330,4 +1377,6 @@ registerGame(GameInfo(695, TheRedAndTheBlack, "The Red and the Black", GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(748, TwilightZone, "Twilight Zone", GI.GT_2DECK_TYPE, 2, 1, GI.SL_BALANCED)) +registerGame(GameInfo(752, Reserves, "Reserves", + GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) diff --git a/pysollib/games/simplex.py b/pysollib/games/simplex.py index ce240ab9..1eae92aa 100644 --- a/pysollib/games/simplex.py +++ b/pysollib/games/simplex.py @@ -72,21 +72,23 @@ class Simplex(Game): l, s = Layout(self), self.s # set window - w, h = l.XM+10*l.XS, l.YM+2*l.YS+9*l.YOFFSET + w, h = l.XM+10*l.XS, l.YM+2*l.YS+4*l.YOFFSET+l.TEXT_HEIGHT self.setSize(w, h) # create stacks x, y = l.XM, l.YM s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 's') x += l.XS s.waste = WasteStack(x, y, self) + l.createText(s.waste, 's') x += l.XS stack = Simplex_Foundation(x, y, self, suit=ANY_SUIT, base_rank=ANY_RANK, max_cards=52) xoffset = (self.width-3*l.XS)/51 stack.CARD_XOFFSET, stack.CARD_YOFFSET = xoffset, 0 s.foundations.append(stack) - x, y = l.XM, l.YM+l.YS + x, y = l.XM, l.YM+l.YS+l.TEXT_HEIGHT for i in range(9): s.rows.append(Simplex_RowStack(x, y, self)) x += l.XS diff --git a/pysollib/games/sthelena.py b/pysollib/games/sthelena.py index 585dc777..2316bb42 100644 --- a/pysollib/games/sthelena.py +++ b/pysollib/games/sthelena.py @@ -249,10 +249,7 @@ class LesQuatreCoins(Game): x, y = l.XM, l.YM+2*l.YS s.talon = LesQuatreCoins_Talon(x, y, self, max_rounds=3) l.createText(s.talon, 's') - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nn') l.defaultStackGroups() diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py index e5aea135..288196d4 100644 --- a/pysollib/games/sultan.py +++ b/pysollib/games/sultan.py @@ -49,7 +49,7 @@ class Sultan(Game): l, s = Layout(self), self.s # set window - w, h = 3*l.XM+5*l.XS, l.YM+4*l.YS+l.TEXT_HEIGHT + w, h = 3*l.XM+5*l.XS, l.YM+4*l.YS+l.TEXT_HEIGHT+l.TEXT_MARGIN self.setSize(w, h) # create stacks @@ -82,6 +82,7 @@ class Sultan(Game): x, y = 2*l.XM+1.5*l.XS, l.YM+3*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, "s") + l.createRoundText(self.s.talon, 'sss') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "s") @@ -128,11 +129,8 @@ class Boudoir(Game): x, y = l.XM, l.YM+l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font=self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) l.createText(s.talon, 'ne') + l.createRoundText(s.talon, 'nn') y += l.YS s.waste = WasteStack(x, y, self) l.createText(s.waste, 'ne') @@ -194,10 +192,7 @@ class CaptiveQueens(Game): x, y = l.XM, l.YM+l.YS/2 s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, "se") - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nn') y += l.YS s.waste = WasteStack(x, y, self) l.createText(s.waste, "se") @@ -210,8 +205,8 @@ class CaptiveQueens(Game): x, y = l.XM+1.5*l.XS, l.YM+l.YS for i in range(4): - s.rows.append(AbstractFoundationStack(x, y, self, suit=i, - max_cards=1, max_move=0, base_rank=QUEEN)) + s.foundations.append(AbstractFoundationStack(x, y, self, suit=i, + max_cards=1, max_move=0, base_rank=QUEEN)) x += l.XS x, y = l.XM+1.5*l.XS, l.YM+2*l.YS @@ -255,6 +250,7 @@ class Contradance(Game): x, y = l.XM+3*l.XS, l.YM+3*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=2) l.createText(s.talon, 'n') + l.createRoundText(self.s.talon, 'nnn') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 'n') @@ -294,6 +290,7 @@ class IdleAces(Game): x, y = l.XM, l.YM s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 's') + l.createRoundText(s.talon, 'ne', dx=l.XS) x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 's') @@ -452,10 +449,7 @@ class Matrimony(Game): s.talon = Matrimony_Talon(l.XM, l.YM, self, max_rounds=17) l.createText(s.talon, 'se') - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') x, y = l.XM+2*l.XS, l.YM for i in range(4): @@ -503,7 +497,10 @@ class PicturePatience(Game): def createGame(self, max_rounds=1): l, s = Layout(self), self.s - self.setSize(3*l.XM+5*l.XS, l.YM+4*l.YS) + w, h = 3*l.XM+5*l.XS, l.YM+4*l.YS + if max_rounds > 1: + h += l.TEXT_HEIGHT+l.TEXT_MARGIN + self.setSize(w, h) x, y = l.XM, l.YM for i in range(4): @@ -524,10 +521,15 @@ class PicturePatience(Game): y += l.YS x, y = 2*l.XM+l.XS+l.XS/2, l.YM+3*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds) - l.createText(s.talon, 'sw') x += l.XS s.waste = WasteStack(x, y, self) - l.createText(s.waste, 'se') + if max_rounds > 1: + l.createText(s.talon, 's') + l.createRoundText(s.talon, 'sss') + l.createText(s.waste, 's') + else: + l.createText(s.talon, 'sw') + l.createText(s.waste, 'se') l.defaultStackGroups() @@ -660,7 +662,8 @@ class TwoRings(Game): x += l.XS s.talon = DealRowRedealTalonStack(x, y, self, max_rounds=2) - l.createText(s.talon, 'sw') + l.createText(s.talon, 'nw') + l.createRoundText(s.talon, 'sw') l.defaultStackGroups() @@ -859,25 +862,26 @@ class CircleEight(Game): def createGame(self): l, s = Layout(self), self.s - self.setSize(l.XM+5*l.XS, l.YM+3*l.YS) + self.setSize(l.XM+5*l.XS, l.YM+4*l.YS) for i, j in ((1,0), (2,0), (3,0), - (4,1), - (3,2), - (2,2), - (1,2), - (0,1), + (4,1.5), + (3,3), + (2,3), + (1,3), + (0,1.5), ): x, y = l.XM+i*l.XS, l.YM+j*l.YS stack = RK_RowStack(x, y, self, dir=1, mod=13, max_move=0) s.rows.append(stack) stack.CARD_YOFFSET = 0 - x, y = l.XM+1.5*l.XS, l.YM+l.YS + x, y = l.XM+1.5*l.XS, l.YM+1.5*l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=2) l.createText(s.talon, 'nw') + l.createRoundText(self.s.talon, 'nn') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 'ne') @@ -994,10 +998,7 @@ class Toni(Game): x, y = l.XM, l.YM s.talon = DealRowRedealTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'se') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'ne') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') l.defaultStackGroups() diff --git a/pysollib/games/tournament.py b/pysollib/games/tournament.py index 61056495..246873f7 100644 --- a/pysollib/games/tournament.py +++ b/pysollib/games/tournament.py @@ -101,10 +101,7 @@ class Tournament(Game): s.talon = Tournament_Talon(l.XM, l.YM, self, max_rounds=3) l.createText(s.talon, "se") - tx, ty, ta, tf = l.getTextAttr(s.talon, "ne") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) + l.createRoundText(s.talon, 'ne') # define stack-groups l.defaultStackGroups() diff --git a/pysollib/games/windmill.py b/pysollib/games/windmill.py index b50092cb..c19fa969 100644 --- a/pysollib/games/windmill.py +++ b/pysollib/games/windmill.py @@ -273,6 +273,8 @@ class Corners(Game): x, y = l.XM+1.5*l.XS, l.YM s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds) l.createText(s.talon, "sw") + if max_rounds > 1: + l.createRoundText(self.s.talon, 'nw') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "se") diff --git a/pysollib/games/yukon.py b/pysollib/games/yukon.py index 691667b3..84bf5e53 100644 --- a/pysollib/games/yukon.py +++ b/pysollib/games/yukon.py @@ -147,6 +147,10 @@ class Grandfather_Talon(RedealTalonStack): class Grandfather(RussianSolitaire): Talon_Class = StackWrapper(Grandfather_Talon, max_rounds=3) + def createGame(self): + l = Yukon.createGame(self) + l.createRoundText(self.s.talon, 'nn') + def startGame(self): for i, j in ((1,7),(1,6),(2,6),(2,5),(3,5),(3,4)): self.s.talon.dealRowAvail(rows=self.s.rows[i:j], flip=0, frames=0) diff --git a/pysollib/games/zodiac.py b/pysollib/games/zodiac.py index e5e77e89..48717945 100644 --- a/pysollib/games/zodiac.py +++ b/pysollib/games/zodiac.py @@ -176,10 +176,7 @@ class TwelveSleepingMaids(Game): x, y = self.width-l.XS, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') - tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") - font = self.app.getFont("canvas_default") - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty-l.TEXT_MARGIN, - anchor=ta, font=font) + l.createRoundText(s.talon, 'nnn') x -= l.XS s.waste = WasteStack(x, y, self) diff --git a/pysollib/hint.py b/pysollib/hint.py index faed140f..8ef4ae36 100644 --- a/pysollib/hint.py +++ b/pysollib/hint.py @@ -156,7 +156,7 @@ class AbstractHint(HintInterface): self.hints.append(ah) # clean up and return hints sorted by score - def __returnHints(self): + def _returnHints(self): hints = self.hints self.reset() hints.sort() @@ -189,14 +189,14 @@ class AbstractHint(HintInterface): if r.canFlipCard(): self.addHint(self.SCORE_FLIP, 1, r, r) if self.SCORE_FLIP >= 90000: - return self.__returnHints() + return self._returnHints() # 3) ask subclass to do something useful self.computeHints() # 4) try if we can deal cards if self.level >= 2: if game.canDealCards(): self.addHint(self.SCORE_DEAL, 0, game.s.talon, None) - return self.__returnHints() + return self._returnHints() # subclass def computeHints(self): diff --git a/pysollib/layout.py b/pysollib/layout.py index 8e064127..6294b0b8 100644 --- a/pysollib/layout.py +++ b/pysollib/layout.py @@ -235,6 +235,24 @@ class Layout: anchor=ta, font=font) stack.texts.ncards.text_format = text_format or tf + def createRoundText(self, stack, anchor, dx=0, dy=0): + if self.canvas.preview > 1: + return + assert stack.texts.rounds is None + delta_x, delta_y = 0, 0 + if anchor == 'nnn': + anchor = 'nn' + delta_y = -self.TEXT_MARGIN + elif anchor == 'sss': + anchor = 'ss' + delta_y = self.TEXT_MARGIN + tx, ty, ta, tf = self.getTextAttr(stack, anchor) + tx += delta_x + dx + ty += delta_y + dy + font = self.game.app.getFont("canvas_default") + stack.texts.rounds = MfxCanvasText(self.canvas, tx, ty, + anchor=ta, font=font) + def setRegion(self, stacks, rects): self.regions.append((stacks, rects)) @@ -416,7 +434,8 @@ class Layout: # def gypsyLayout(self, rows, waste=0, reserves=0, - texts=1, reserve_texts=False, playcards=25): + texts=1, reserve_texts=False, round_text=False, + playcards=25): S = self.__createStack CW, CH = self.CW, self.CH XM, YM = self.XM, self.YM @@ -458,15 +477,18 @@ class Layout: if texts: x -= XS/2 self.s.talon = s = S(x, y) + anchor = 's' + if round_text: + anchor = 'n' if texts: # place text right of stack - self._setText(s, anchor="se") + self._setText(s, anchor=anchor+"e") if waste: x -= XS self.s.waste = s = S(x, y) if texts: # place text left of stack - self._setText(s, anchor="sw") + self._setText(s, anchor=anchor+"w") # create reserves x, y = XM, h-YS for i in range(reserves): @@ -564,7 +586,7 @@ class Layout: # def klondikeLayout(self, rows, waste, reserves=0, - texts=1, reserve_texts=False, + texts=1, reserve_texts=False, round_text=False, playcards=16, center=1, text_height=0): S = self.__createStack CW, CH = self.CW, self.CH @@ -576,8 +598,11 @@ class Layout: foundrows = 1 + (suits > 5) frows = decks * suits / foundrows toprows = 1 + waste + frows + if round_text: + toprows += 1 maxrows = max(rows, toprows, reserves) + w = XM + maxrows * XS # set size so that at least 2/3 of a card is visible with 16 cards h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET h = max(h, 2 * YS) @@ -606,7 +631,7 @@ class Layout: text_height = self.TEXT_HEIGHT for row in range(foundrows): - x = XM + (maxrows - frows) * XS + x = w - frows * XS if center and frows + 2 * (1 + waste + 1) <= maxrows: # center the foundations x = XM + (maxrows - frows) * XS / 2 @@ -618,7 +643,8 @@ class Layout: # below x = XM - if rows < maxrows: x += (maxrows-rows) * XS/2 + if rows < maxrows: + x += (maxrows-rows) * XS/2 ##y += YM * (3 - foundrows) y += text_height for i in range(rows): @@ -643,7 +669,7 @@ class Layout: self._setText(s, anchor="n") # set window - self.size = (XM + maxrows * XS, h) + self.size = (w, h) # diff --git a/pysollib/tile/selecttile.py b/pysollib/tile/selecttile.py index af2f94c6..0e21b7bc 100644 --- a/pysollib/tile/selecttile.py +++ b/pysollib/tile/selecttile.py @@ -36,6 +36,7 @@ # imports import Tkinter +import Tile import tkColorChooser # PySol imports @@ -129,13 +130,17 @@ class SelectTileDialogWithPreview(MfxDialog): else: w1, w2 = 200, 300 font = app.getFont("default") - self.tree = self.Tree_Class(self, top_frame, key=key, - default=kw.default, + padx, pady = 4, 4 + frame = Tile.Frame(top_frame) + frame.pack(fill='both', expand=True, + padx=kw.padx-padx, pady=kw.pady-pady) + self.tree = self.Tree_Class(self, frame, key=key, default=kw.default, font=font, width=w1) - self.tree.frame.pack(side="left", fill='both', expand=False, padx=kw.padx, pady=kw.pady) - self.preview = MfxScrolledCanvas(top_frame, width=w2, hbar=0, vbar=0) + self.tree.frame.pack(side="left", fill='both', expand=False, + padx=padx, pady=pady) + self.preview = MfxScrolledCanvas(frame, width=w2, hbar=0, vbar=0) self.preview.pack(side="right", fill='both', expand=True, - padx=kw.padx, pady=kw.pady) + padx=padx, pady=pady) self.preview.canvas.preview = 1 # create a preview of the current state self.preview_key = -1 @@ -158,6 +163,7 @@ class SelectTileDialogWithPreview(MfxDialog): default=0, resizable=True, font=None, + padx=10, pady=10, ) return MfxDialog.initKw(self, kw) diff --git a/pysollib/tile/tkcanvas.py b/pysollib/tile/tkcanvas.py index fb3be6e9..173f4235 100644 --- a/pysollib/tile/tkcanvas.py +++ b/pysollib/tile/tkcanvas.py @@ -153,8 +153,7 @@ class MfxCanvas(Tkinter.Canvas): stretch = self._stretch_bg_image if Image: if stretch: - w = max(self.winfo_width(), int(self.cget('width'))) - h = max(self.winfo_height(), int(self.cget('height'))) + w, h = self._geometry() im = self._bg_img.resize((w, h)) image = ImageTk.PhotoImage(im) else: @@ -179,10 +178,7 @@ class MfxCanvas(Tkinter.Canvas): self.__tiles.append(id) else: iw, ih = image.width(), image.height() - #sw = max(self.winfo_screenwidth(), 1024) - #sh = max(self.winfo_screenheight(), 768) - sw = max(self.winfo_width(), int(self.cget('width'))) - sh = max(self.winfo_height(), int(self.cget('height'))) + sw, sh = self._geometry() for x in range(-self.xmargin, sw, iw): for y in range(-self.ymargin, sh, ih): id = self._x_create("image", x, y, image=image, anchor="nw") @@ -190,6 +186,19 @@ class MfxCanvas(Tkinter.Canvas): self.__tiles.append(id) return 1 + def _geometry(self): + w = max(self.winfo_width(), int(self.cget('width'))) + h = max(self.winfo_height(), int(self.cget('height'))) + scrollregion = self.cget('scrollregion') + if not scrollregion: + return w, h + x, y, sw, sh = [int(i) for i in scrollregion.split()] + sw -= x + sh -= y + w = max(w, sw) + h = max(h, sh) + return w, h + # # top-image support diff --git a/pysollib/tile/tkutil.py b/pysollib/tile/tkutil.py index e5368daa..789e21b4 100644 --- a/pysollib/tile/tkutil.py +++ b/pysollib/tile/tkutil.py @@ -197,7 +197,7 @@ __mfx_bindings = {} __mfx_wm_protocols = ("WM_DELETE_WINDOW", "WM_TAKE_FOCUS", "WM_SAVE_YOURSELF") def bind(widget, sequence, func, add=None): - assert callable(func) + ##assert callable(func) # XXX: removed in py3k if sequence in __mfx_wm_protocols: funcid = widget._register(func) widget.tk.call("wm", "protocol", widget._w, sequence, funcid) diff --git a/pysollib/tk/selecttile.py b/pysollib/tk/selecttile.py index c32a59bb..6fb53375 100644 --- a/pysollib/tk/selecttile.py +++ b/pysollib/tk/selecttile.py @@ -128,14 +128,18 @@ class SelectTileDialogWithPreview(MfxDialog): else: w1, w2 = 200, 300 font = app.getFont("default") - self.tree = self.Tree_Class(self, top_frame, key=key, + padx, pady = 4, 4 + frame = Tkinter.Frame(top_frame) + frame.pack(fill='both', expand=True, + padx=kw.padx-padx, pady=kw.pady-pady) + self.tree = self.Tree_Class(self, frame, key=key, default=kw.default, font=font, width=w1) self.tree.frame.pack(side="left", fill='both', expand=False, - padx=kw.padx, pady=kw.pady) - self.preview = MfxScrolledCanvas(top_frame, width=w2, hbar=0, vbar=0) + padx=padx, pady=pady) + self.preview = MfxScrolledCanvas(frame, width=w2, hbar=0, vbar=0) self.preview.pack(side="right", fill='both', expand=True, - padx=kw.padx, pady=kw.pady) + padx=padx, pady=pady) self.preview.canvas.preview = 1 # create a preview of the current state self.preview_key = -1 diff --git a/pysollib/tk/tkcanvas.py b/pysollib/tk/tkcanvas.py index c98d4ac8..a6a4d8c8 100644 --- a/pysollib/tk/tkcanvas.py +++ b/pysollib/tk/tkcanvas.py @@ -152,8 +152,7 @@ class MfxCanvas(Tkinter.Canvas): stretch = self._stretch_bg_image if Image: if stretch: - w = max(self.winfo_width(), int(self.cget('width'))) - h = max(self.winfo_height(), int(self.cget('height'))) + w, h = self._geometry() im = self._bg_img.resize((w, h)) image = ImageTk.PhotoImage(im) else: @@ -178,10 +177,7 @@ class MfxCanvas(Tkinter.Canvas): self.__tiles.append(id) else: iw, ih = image.width(), image.height() - #sw = max(self.winfo_screenwidth(), 1024) - #sh = max(self.winfo_screenheight(), 768) - sw = max(self.winfo_width(), int(self.cget('width'))) - sh = max(self.winfo_height(), int(self.cget('height'))) + sw, sh = self._geometry() for x in range(-self.xmargin, sw, iw): for y in range(-self.ymargin, sh, ih): id = self._x_create("image", x, y, image=image, anchor="nw") @@ -189,6 +185,19 @@ class MfxCanvas(Tkinter.Canvas): self.__tiles.append(id) return 1 + def _geometry(self): + w = max(self.winfo_width(), int(self.cget('width'))) + h = max(self.winfo_height(), int(self.cget('height'))) + scrollregion = self.cget('scrollregion') + if not scrollregion: + return w, h + x, y, sw, sh = [int(i) for i in scrollregion.split()] + sw -= x + sh -= y + w = max(w, sw) + h = max(h, sh) + return w, h + # # top-image support diff --git a/pysollib/tk/tkutil.py b/pysollib/tk/tkutil.py index e5368daa..789e21b4 100644 --- a/pysollib/tk/tkutil.py +++ b/pysollib/tk/tkutil.py @@ -197,7 +197,7 @@ __mfx_bindings = {} __mfx_wm_protocols = ("WM_DELETE_WINDOW", "WM_TAKE_FOCUS", "WM_SAVE_YOURSELF") def bind(widget, sequence, func, add=None): - assert callable(func) + ##assert callable(func) # XXX: removed in py3k if sequence in __mfx_wm_protocols: funcid = widget._register(func) widget.tk.call("wm", "protocol", widget._w, sequence, funcid)