From 44e8f8c417d3c52834c0c5a54147447d953d0daa Mon Sep 17 00:00:00 2001 From: skomoroh Date: Sat, 17 Jun 2006 21:18:07 +0000 Subject: [PATCH] + 37 new games git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@9 efabe8c0-fbe8-4139-b769-b5e6d273206e --- pysollib/app.py | 8 +-- pysollib/games/auldlangsyne.py | 43 +++++++++++++ pysollib/games/beleagueredcastle.py | 54 +++++++++++++++- pysollib/games/canfield.py | 72 +++++++++++----------- pysollib/games/curdsandwhey.py | 88 ++++++++++++++++++++++++++ pysollib/games/diplomat.py | 62 ++++++++++++++++++- pysollib/games/fortythieves.py | 52 ++++++++++++++-- pysollib/games/gypsy.py | 56 +++++++++++++++++ pysollib/games/harp.py | 55 ++++++++++++++++- pysollib/games/klondike.py | 95 ++++++++++++++++++++++++++++- pysollib/games/numerica.py | 65 +++++++++++++++++++- pysollib/games/spider.py | 56 ++++++++++++----- pysollib/games/sultan.py | 58 ++++++++++++++++++ pysollib/games/terrace.py | 54 ++++++++++++---- pysollib/games/ultra/hanafuda1.py | 6 +- pysollib/games/windmill.py | 69 ++++++++++++++++++++- pysollib/games/yukon.py | 44 ++++++++++++- 17 files changed, 847 insertions(+), 90 deletions(-) diff --git a/pysollib/app.py b/pysollib/app.py index ea1c99b9..bbdbcde3 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -96,7 +96,7 @@ class Options: self.highlight_piles = 1 self.highlight_cards = 1 self.highlight_samerank = 1 - self.highlight_not_matching = 0 + self.highlight_not_matching = 1 self.mahjongg_show_removed = False self.mahjongg_create_solvable = True self.shisen_show_hint = True @@ -108,6 +108,8 @@ class Options: self.toolbar = 1 ##self.toolbar_style = 'default' self.toolbar_style = 'crystal' + if os.name == 'posix': + self.toolbar_style = 'bluecurve' self.toolbar_relief = 'flat' self.toolbar_compound = 'none' # icons only self.toolbar_size = 0 @@ -129,10 +131,6 @@ class Options: 'autopilotlost' : True, 'autopilotwon' : True, 'deal' : True, - #'deal01' : True, - #'deal02' : True, - #'deal04' : True, - #'deal08' : True, 'dealwaste' : True, 'droppair' : True, 'drop' : True, diff --git a/pysollib/games/auldlangsyne.py b/pysollib/games/auldlangsyne.py index a12f2d8d..f654e657 100644 --- a/pysollib/games/auldlangsyne.py +++ b/pysollib/games/auldlangsyne.py @@ -442,6 +442,47 @@ class Amazons(Game): return ((), (), self.sg.dropstacks) +# /*********************************************************************** +# // Acquaintance +# ************************************************************************/ + +class Acquaintance_Talon(TalonStack): # TalonStack + + def canDealCards(self): + if self.round == self.max_rounds and not self.cards: + return False + return not self.game.isGameWon() + + def _redeal(self): + # move all cards to the Talon + lr = len(self.game.s.rows) + num_cards = 0 + assert len(self.cards) == 0 + rows = self.game.s.rows + for r in rows: + for i in range(len(r.cards)): + num_cards = num_cards + 1 + self.game.moveMove(1, r, self, frames=4) + self.game.flipMove(self) + assert len(self.cards) == num_cards + if num_cards == 0: # game already finished + return + self.game.nextRoundMove(self) + + def dealCards(self, sound=0): + if sound: + self.game.startDealSample() + if len(self.cards) == 0: + self._redeal() + n = self.dealRowAvail(sound=sound) + if sound: + self.game.stopSamples() + return n + +class Acquaintance(AuldLangSyne): + Talon_Class = StackWrapper(Acquaintance_Talon, max_rounds=3) + + # register the game registerGame(GameInfo(172, TamOShanter, "Tam O'Shanter", GI.GT_NUMERICA, 1, 0)) @@ -457,4 +498,6 @@ registerGame(GameInfo(406, Amazons, "Amazons", GI.GT_NUMERICA, 1, -1, ranks=(0, 6, 7, 8, 9, 10, 11), )) +registerGame(GameInfo(490, Acquaintance, "Acquaintance", + GI.GT_NUMERICA, 1, 2)) diff --git a/pysollib/games/beleagueredcastle.py b/pysollib/games/beleagueredcastle.py index 83e38eaa..fa3eb092 100644 --- a/pysollib/games/beleagueredcastle.py +++ b/pysollib/games/beleagueredcastle.py @@ -626,6 +626,57 @@ class Rittenhouse(Game): return abs(card1.rank - card2.rank) == 1 +# /*********************************************************************** +# // Castle Mount +# ************************************************************************/ + +class CastleMount(StreetsAndAlleys): + DEAL = (11, 1) + RowStack_Class = Spider_SS_RowStack + + def createGame(self, rows=12): + l, s = Layout(self), self.s + max_rows = max(12, rows) + self.setSize(l.XM+max_rows*l.XS, l.YM+2*l.YS+20*l.YOFFSET) + + x, y = l.XM+(max_rows-12)*l.XS/2, l.YM + for i in range(4): + for j in range(3): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i, + max_move=0)) + x += l.XS + x, y = l.XM, l.YM+l.YS + for i in range(rows): + s.rows.append(self.RowStack_Class(x, y, self)) + x += l.XS + s.talon = InitialDealTalonStack(self.width-l.XS, self.height-l.YS, self) + + l.defaultAll() + + + def _shuffleHook(self, cards): + # move Aces to top of the Talon (i.e. first cards to be dealt) + return self._shuffleHookMoveToTop(cards, + lambda c: (c.rank == ACE, c.suit)) + + def startGame(self): + self.s.talon.dealRow(rows=self.s.foundations, frames=0) + for i in range(self.DEAL[0]): + self.s.talon.dealRow(frames=0) + self.startDealSample() + for i in range(self.DEAL[1]): + self.s.talon.dealRowAvail() + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return ((card1.rank + 1) % stack1.cap.mod == card2.rank or + (card2.rank + 1) % stack1.cap.mod == card1.rank) + + def getQuickPlayScore(self, ncards, from_stack, to_stack): + if to_stack.cards: + return int(from_stack.cards[-1].suit == to_stack.cards[-1].suit)+1 + return 0 + + # register the game registerGame(GameInfo(146, StreetsAndAlleys, "Streets and Alleys", @@ -656,4 +707,5 @@ registerGame(GameInfo(395, Zerline3Decks, "Zerline (3 decks)", GI.GT_BELEAGUERED_CASTLE | GI.GT_ORIGINAL, 3, 0)) registerGame(GameInfo(400, Rittenhouse, "Rittenhouse", GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 2, 0)) - +registerGame(GameInfo(507, CastleMount, "Castle Mount", + GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 3, 0)) diff --git a/pysollib/games/canfield.py b/pysollib/games/canfield.py index 13d8538b..c1a58d21 100644 --- a/pysollib/games/canfield.py +++ b/pysollib/games/canfield.py @@ -111,8 +111,14 @@ class Canfield(Game): decks = self.gameinfo.decks # set window + if self.INITIAL_RESERVE_FACEUP == 1: + yoffset = l.YOFFSET ##min(l.YOFFSET, 14) + else: + yoffset = 10 + if self.INITIAL_RESERVE_CARDS > 30: + yoffset = 5 # (piles up to 20 cards are playable in default window size) - h = max(3*l.YS, l.YS+self.INITIAL_RESERVE_CARDS*l.YOFFSET) + h = max(3*l.YS, l.YS+self.INITIAL_RESERVE_CARDS*yoffset) self.setSize(l.XM + (2+max(rows, 4*decks))*l.XS + l.XM, l.YM + l.YS + 20 + h) # extra settings @@ -131,7 +137,7 @@ class Canfield(Game): x = x + l.XS s.foundations.append(self.Foundation_Class(x, y, self, i, mod=13, max_move=0)) if text: - if rows >= 4 * decks: + if rows > 4 * decks: tx, ty, ta, tf = l.getTextAttr(None, "se") tx, ty = x + tx + l.XM, y + ty else: @@ -141,10 +147,7 @@ class Canfield(Game): self.texts.info = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) x, y = l.XM, l.YM + l.YS + 20 s.reserves.append(self.ReserveStack_Class(x, y, self)) - if self.INITIAL_RESERVE_FACEUP == 1: - s.reserves[0].CARD_YOFFSET = l.YOFFSET ##min(l.YOFFSET, 14) - else: - s.reserves[0].CARD_YOFFSET = 10 + s.reserves[0].CARD_YOFFSET = yoffset x = l.XM + 2 * l.XS + l.XM for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) @@ -509,17 +512,19 @@ class LittleGate(Gate): # /*********************************************************************** +# // Minerva # // Munger +# // Mystique # ************************************************************************/ -class Munger(Canfield): - - RowStack_Class = StackWrapper(AC_RowStack, base_rank=KING) +class Minerva(Canfield): + RowStack_Class = KingAC_RowStack FILL_EMPTY_ROWS = 0 + INITIAL_RESERVE_CARDS = 11 def createGame(self): - Canfield.createGame(self, rows=7, max_rounds=1, num_deal=1) + Canfield.createGame(self, rows=7, max_rounds=2, num_deal=1, text=False) def startGame(self): self.s.talon.dealRow(frames=0, flip=0) @@ -527,14 +532,13 @@ class Munger(Canfield): self.s.talon.dealRow(frames=0, flip=0) self.startDealSample() self.s.talon.dealRow() - for i in range(7): + for i in range(self.INITIAL_RESERVE_CARDS): self.moveMove(1, self.s.talon, self.s.reserves[0], frames=4, shadow=0) self.flipMove(self.s.reserves[0]) self.s.talon.dealCards() def shallHighlightMatch(self, stack1, card1, stack2, card2): - return (card1.color != card2.color and - abs(card1.rank-card2.rank) == 1) + return card1.color != card2.color and abs(card1.rank-card2.rank) == 1 def _restoreGameHook(self, game): pass @@ -544,6 +548,17 @@ class Munger(Canfield): pass +class Munger(Minerva): + INITIAL_RESERVE_CARDS = 7 + def createGame(self): + Canfield.createGame(self, rows=7, max_rounds=1, num_deal=1, text=False) + + +class Mystique(Munger): + RowStack_Class = AC_RowStack + INITIAL_RESERVE_CARDS = 9 + + # /*********************************************************************** # // Triple Canfield # ************************************************************************/ @@ -643,31 +658,14 @@ class Duke(Game): # /*********************************************************************** -# // Minerva +# // Demon # ************************************************************************/ -class Minerva(Canfield): - RowStack_Class = StackWrapper(AC_RowStack, base_rank=KING) - - INITIAL_RESERVE_CARDS = 11 - INITIAL_RESERVE_FACEUP = 1 - FILL_EMPTY_ROWS = 0 - +class Demon(Canfield): + INITIAL_RESERVE_CARDS = 40 + RowStack_Class = StackWrapper(AC_RowStack, mod=13) def createGame(self): - Canfield.createGame(self, rows=7, max_rounds=2, num_deal=1, text=False) - - def startGame(self): - for i in range(self.INITIAL_RESERVE_CARDS): - self.flipMove(self.s.talon) - self.moveMove(1, self.s.talon, self.s.reserves[0], frames=0, shadow=0) - flip = False - for i in range(3): - self.s.talon.dealRow(flip=flip, frames=0) - flip = not flip - self.startDealSample() - self.s.talon.dealRow() - self.s.talon.dealCards() - + Canfield.createGame(self, rows=8, max_rounds=UNLIMITED_REDEALS, num_deal=1) # register the game @@ -707,4 +705,8 @@ registerGame(GameInfo(413, Duke, "Duke", GI.GT_CANFIELD, 1, 2)) registerGame(GameInfo(422, Minerva, "Minerva", GI.GT_CANFIELD, 1, 1)) +registerGame(GameInfo(476, Demon, "Demon", + GI.GT_CANFIELD, 2, -1)) +registerGame(GameInfo(494, Mystique, "Mystique", + GI.GT_CANFIELD, 1, 0)) diff --git a/pysollib/games/curdsandwhey.py b/pysollib/games/curdsandwhey.py index 43157a7c..07bdb472 100644 --- a/pysollib/games/curdsandwhey.py +++ b/pysollib/games/curdsandwhey.py @@ -305,6 +305,88 @@ class BavarianPatience(GermanPatience): GermanPatience.createGame(self, rows=10) +# /*********************************************************************** +# // Trusty Twelve +# // Knotty Nines +# // Sweet Sixteen +# ************************************************************************/ + +class TrustyTwelve_Hint(AbstractHint): + def computeHints(self): + game = self.game + for r in game.s.rows: + for t in game.s.rows: + if r is t: + continue + card = r.cards[-1] + if len(r.cards) == 1 and t.acceptsCards(r, [card]): + if len(t.cards) > 1: + self.addHint(6000+card.rank, 1, r, t) + else: + self.addHint(5000+card.rank, 1, r, t) + + +class TrustyTwelve(Game): + Hint_Class = TrustyTwelve_Hint + + def createGame(self, rows=12): + l, s = Layout(self), self.s + self.setSize(l.XM+(rows+1)*l.XS, l.YM+l.YS+12*l.YOFFSET) + x, y = l.XM, l.YM + s.talon = TalonStack(x, y, self) + l.createText(s.talon, "ss") + x += l.XS + for i in range(rows): + s.rows.append(RK_RowStack(x, y, self, max_move=1)) + x += l.XS + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + + def fillStack(self, stack): + if not stack.cards and stack in self.s.rows: + if self.s.talon.cards: + old_state = self.enterState(self.S_FILL) + self.s.talon.flipMove() + self.s.talon.moveMove(1, stack) + self.leaveState(old_state) + + def isGameWon(self): + return len(self.s.talon.cards) == 0 + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 1 + + +class KnottyNines(TrustyTwelve): + def createGame(self): + TrustyTwelve.createGame(self, rows=9) + + +class SweetSixteen(TrustyTwelve): + + def createGame(self): + l, s = Layout(self), self.s + self.setSize(l.XM+9*l.XS, l.YM+2*l.YS+20*l.YOFFSET) + x, y = l.XM, l.YM + s.talon = TalonStack(x, y, self) + l.createText(s.talon, "ss") + y = l.YM + for i in range(2): + x = l.XM+l.XS + for j in range(8): + s.rows.append(AC_RowStack(x, y, self, max_move=1)) + x += l.XS + y += l.YS+10*l.YOFFSET + l.defaultStackGroups() + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return card1.color != card2.color and abs(card1.rank-card2.rank) == 1 + + + # register the game registerGame(GameInfo(294, CurdsAndWhey, "Curds and Whey", GI.GT_SPIDER | GI.GT_OPEN, 1, 0)) @@ -324,4 +406,10 @@ registerGame(GameInfo(414, GermanPatience, "German Patience", GI.GT_2DECK_TYPE, 2, 0)) registerGame(GameInfo(415, BavarianPatience, "Bavarian Patience", GI.GT_2DECK_TYPE, 2, 0)) +registerGame(GameInfo(480, TrustyTwelve, "Trusty Twelve", + GI.GT_1DECK_TYPE, 1, 0)) +registerGame(GameInfo(481, KnottyNines, "Knotty Nines", + GI.GT_1DECK_TYPE, 1, 0)) +registerGame(GameInfo(482, SweetSixteen, "Sweet Sixteen", + GI.GT_1DECK_TYPE, 1, 0)) diff --git a/pysollib/games/diplomat.py b/pysollib/games/diplomat.py index 3e05366d..1f87a62f 100644 --- a/pysollib/games/diplomat.py +++ b/pysollib/games/diplomat.py @@ -42,7 +42,9 @@ from pysollib.game import Game from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint -from pysollib.games.fortythieves import FortyThieves_Hint +from fortythieves import FortyThieves_Hint +from spider import Spider_Hint + # /*********************************************************************** # // Diplomat @@ -65,7 +67,7 @@ class Diplomat(Game): l, s = Layout(self), self.s # set window - self.setSize(l.XM + 8*l.XS, l.YM + 5*l.YS) + self.setSize(l.XM+8*l.XS, l.YM+3*l.YS+12*l.YOFFSET+20) # create stacks x, y = l.XM, l.YM @@ -171,6 +173,58 @@ class RowsOfFour(Diplomat): Diplomat.createGame(self, max_rounds=3) +# /*********************************************************************** +# // Dieppe +# ************************************************************************/ + +class Dieppe(Diplomat): + RowStack_Class = RK_RowStack + + def _dealToFound(self): + talon = self.s.talon + if not talon.cards: + return False + talon.flipMove() + for f in self.s.foundations: + if f.acceptsCards(talon, talon.cards[-1:]): + talon.moveMove(1, f) + return True + return False + + def startGame(self): + self.startDealSample() + talon = self.s.talon + for i in range(3): + for r in self.s.rows: + while True: + if not self._dealToFound(): + break + if talon.cards: + talon.moveMove(1, r) + talon.dealCards() + + +# /*********************************************************************** +# // Little Napoleon +# ************************************************************************/ + +class LittleNapoleon(Diplomat): + RowStack_Class = Spider_SS_RowStack + Hint_Class = Spider_Hint + + def startGame(self): + for i in range(3): + self.s.talon.dealRow(frames=0, flip=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() # deal first card to WasteStack + + def getQuickPlayScore(self, ncards, from_stack, to_stack): + if to_stack.cards: + return int(from_stack.cards[-1].suit == to_stack.cards[-1].suit)+1 + return 0 + + # register the game registerGame(GameInfo(149, Diplomat, "Diplomat", GI.GT_FORTY_THIEVES, 2, 0)) @@ -180,4 +234,8 @@ registerGame(GameInfo(150, Congress, "Congress", GI.GT_FORTY_THIEVES, 2, 0)) registerGame(GameInfo(433, RowsOfFour, "Rows of Four", GI.GT_FORTY_THIEVES, 2, 2)) +registerGame(GameInfo(485, Dieppe, "Dieppe", + GI.GT_FORTY_THIEVES, 2, 0)) +registerGame(GameInfo(489, LittleNapoleon, "Little Napoleon", + GI.GT_FORTY_THIEVES, 2, 0)) diff --git a/pysollib/games/fortythieves.py b/pysollib/games/fortythieves.py index fd67d7b2..e9e9a530 100644 --- a/pysollib/games/fortythieves.py +++ b/pysollib/games/fortythieves.py @@ -73,16 +73,18 @@ class FortyThieves(Game): def createGame(self, max_rounds=1, num_deal=1, rows=10, playcards=12, XCARDS=64, XOFFSET=None): # create layout - XM = (10, 4)[rows > 10] if XOFFSET is None: - l, s = Layout(self, XM=XM, YBOTTOM=16), self.s + l, s = Layout(self, YBOTTOM=16), self.s else: - l, s = Layout(self, XM=XM, XOFFSET=XOFFSET, YBOTTOM=16), self.s + l, s = Layout(self, XOFFSET=XOFFSET, YBOTTOM=16), self.s # set window # (compute best XOFFSET - up to 64/72 cards can be in the Waste) decks = self.gameinfo.decks - maxrows = max(rows, 4*decks+2) + if rows < 12: + maxrows = max(rows, 4*decks+2) + else: + maxrows = max(rows, 4*decks) w1, w2 = maxrows*l.XS+l.XM, 2*l.XS if w2 + XCARDS * l.XOFFSET > w1: l.XOFFSET = int((w1 - w2) / XCARDS) @@ -155,6 +157,8 @@ class FortyThieves(Game): # // Napoleon's Square # // Carre Napoleon # // Josephine +# // Marie Rose +# // Big Courtyard # // rows build down by suit # ************************************************************************/ @@ -225,6 +229,22 @@ class Josephine(FortyThieves): ROW_MAX_MOVE = UNLIMITED_MOVES +class MarieRose(Josephine): + DEAL = (0, 5) + def createGame(self): + FortyThieves.createGame(self, rows=12, playcards=16, XCARDS=96) + + +class BigCourtyard(Courtyard): + def createGame(self): + FortyThieves.createGame(self, rows=12, playcards=16, XCARDS=96) + + +class Express(Limited): + def createGame(self): + FortyThieves.createGame(self, rows=14, playcards=16, XCARDS=96) + + # /*********************************************************************** # // Deuces # ************************************************************************/ @@ -303,6 +323,8 @@ class LittleForty(FortyThieves): # // Rank and File # // Emperor # // Triple Line +# // Big Streets +# // Number Twelve # // rows build down by alternate color # ************************************************************************/ @@ -345,6 +367,16 @@ class TripleLine(Streets): Streets.createGame(self, max_rounds=2, rows=12) +class BigStreets(Streets): + def createGame(self): + FortyThieves.createGame(self, rows=12, XCARDS=96) + + +class NumberTwelve(NumberTen): + def createGame(self): + FortyThieves.createGame(self, rows=12, XCARDS=96) + + # /*********************************************************************** # // Red and Black # // Zebra @@ -718,7 +750,7 @@ class Squadron(FortyThieves): registerGame(GameInfo(13, FortyThieves, "Forty Thieves", GI.GT_FORTY_THIEVES, 2, 0, altnames=("Napoleon at St.Helena", - "Big Forty", "Le Cadran"))) + "Le Cadran"))) registerGame(GameInfo(80, BusyAces, "Busy Aces", GI.GT_FORTY_THIEVES, 2, 0)) registerGame(GameInfo(228, Limited, "Limited", @@ -784,3 +816,13 @@ registerGame(GameInfo(440, Squadron, "Squadron", GI.GT_FORTY_THIEVES, 2, 0)) registerGame(GameInfo(462, Josephine, "Josephine", GI.GT_FORTY_THIEVES, 2, 0)) +registerGame(GameInfo(493, MarieRose, "Marie Rose", + GI.GT_FORTY_THIEVES, 3, 0)) +registerGame(GameInfo(503, BigStreets, "Big Streets", + GI.GT_FORTY_THIEVES | GI.GT_ORIGINAL, 3, 0)) +registerGame(GameInfo(504, NumberTwelve, "Number Twelve", + GI.GT_FORTY_THIEVES| GI.GT_ORIGINAL, 3, 0)) +registerGame(GameInfo(505, BigCourtyard, "Big Courtyard", + GI.GT_FORTY_THIEVES| GI.GT_ORIGINAL, 3, 0)) +registerGame(GameInfo(506, Express, "Express", + GI.GT_FORTY_THIEVES| GI.GT_ORIGINAL, 3, 0)) diff --git a/pysollib/games/gypsy.py b/pysollib/games/gypsy.py index 0d382683..af286125 100644 --- a/pysollib/games/gypsy.py +++ b/pysollib/games/gypsy.py @@ -45,6 +45,9 @@ from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint from pysollib.hint import KlondikeType_Hint, YukonType_Hint +from spider import Spider_Hint + + # /*********************************************************************** # // Gypsy # ************************************************************************/ @@ -207,6 +210,7 @@ class DieRussische(Gypsy): # /*********************************************************************** # // Miss Milligan +# // Imperial Guards # ************************************************************************/ class MissMilligan_ReserveStack(AC_RowStack): @@ -263,6 +267,10 @@ class MissMilligan(Gypsy): self.s.talon.dealRow() +class ImperialGuards(MissMilligan): + RowStack_Class = AC_RowStack + + # /*********************************************************************** # // Nomad # ************************************************************************/ @@ -297,6 +305,7 @@ class MilliganCell(MissMilligan): # /*********************************************************************** # // Milligan Harp # // Carlton +# // Steve # ************************************************************************/ class MilliganHarp(Gypsy): @@ -314,6 +323,14 @@ class Carlton(MilliganHarp): MilliganHarp.startGame(self, flip=1) +class Steve(Carlton): + Hint_Class = Spider_Hint + RowStack_Class = Spider_SS_RowStack + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 1 + + # /*********************************************************************** # // Lexington Harp # // Brunswick @@ -491,6 +508,37 @@ class Surprise(Gypsy): self.s.talon.dealRow() +# /*********************************************************************** +# // Elba +# ************************************************************************/ + +class Elba(Gypsy): + Layout_Method = Layout.klondikeLayout + RowStack_Class = KingAC_RowStack + + def createGame(self): + Gypsy.createGame(self, rows=10) + + def startGame(self): + for i in range(4): + self.s.talon.dealRow(flip=0, frames=0) + self.startDealSample() + self.s.talon.dealRow() + + +# /*********************************************************************** +# // Millie +# ************************************************************************/ + +class Millie(Gypsy): + Layout_Method = Layout.klondikeLayout + RowStack_Class = AC_RowStack + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + + # register the game registerGame(GameInfo(1, Gypsy, "Gypsy", GI.GT_GYPSY, 2, 0)) @@ -530,4 +578,12 @@ registerGame(GameInfo(463, Surprise, "Surprise", GI.GT_GYPSY, 2, 0)) registerGame(GameInfo(469, PhantomBlockade, "Phantom Blockade", GI.GT_GYPSY, 2, 0)) +registerGame(GameInfo(478, Elba, "Elba", + GI.GT_GYPSY, 2, 0)) +registerGame(GameInfo(486, ImperialGuards, "Imperial Guards", + GI.GT_GYPSY, 2, 0)) +registerGame(GameInfo(487, Millie, "Millie", + GI.GT_GYPSY, 2, 0)) +registerGame(GameInfo(498, Steve, "Steve", + GI.GT_GYPSY, 2, 0)) diff --git a/pysollib/games/harp.py b/pysollib/games/harp.py index c7fd281c..e7566be0 100644 --- a/pysollib/games/harp.py +++ b/pysollib/games/harp.py @@ -46,6 +46,8 @@ from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint from pysollib.hint import KlondikeType_Hint from pysollib.pysoltk import MfxCanvasText +from spider import Spider_Hint + # /*********************************************************************** # // Double Klondike (Klondike with 2 decks and 9 rows) @@ -83,9 +85,9 @@ class DoubleKlondike(Game): font=self.app.getFont("canvas_default")) return l - def startGame(self): + def startGame(self, flip=0): for i in range(len(self.s.rows)): - self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0) + self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=flip, frames=0) self.startDealSample() self.s.talon.dealRow() self.s.talon.dealCards() # deal first card to WasteStack @@ -166,6 +168,49 @@ class TripleKlondikeByThrees(DoubleKlondike): DoubleKlondike.createGame(self, rows=13, num_deal=3) +# /*********************************************************************** +# // Lady Jane +# // Inquisitor +# ************************************************************************/ + +class LadyJane(DoubleKlondike): + Hint_Class = Spider_Hint + RowStack_Class = Spider_SS_RowStack + + def createGame(self): + DoubleKlondike.createGame(self, rows=10, max_rounds=2, num_deal=3) + def startGame(self): + DoubleKlondike.startGame(self, flip=1) + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 1 + + +class Inquisitor(DoubleKlondike): + RowStack_Class = SS_RowStack + + def createGame(self): + DoubleKlondike.createGame(self, rows=10, max_rounds=3, num_deal=3) + def startGame(self): + DoubleKlondike.startGame(self, flip=1) + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1 + + +# /*********************************************************************** +# // Arabella +# ************************************************************************/ + +class Arabella(DoubleKlondike): + Hint_Class = Spider_Hint + RowStack_Class = StackWrapper(Spider_SS_RowStack, base_rank=KING) + def createGame(self): + DoubleKlondike.createGame(self, rows=13, max_rounds=1, playcards=24) + def startGame(self): + DoubleKlondike.startGame(self, flip=1) + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 1 + + # register the game registerGame(GameInfo(21, DoubleKlondike, "Double Klondike", GI.GT_KLONDIKE, 2, -1)) @@ -182,4 +227,10 @@ registerGame(GameInfo(273, TripleKlondike, "Triple Klondike", GI.GT_KLONDIKE, 3, -1)) registerGame(GameInfo(274, TripleKlondikeByThrees, "Triple Klondike by Threes", GI.GT_KLONDIKE, 3, -1)) +registerGame(GameInfo(495, LadyJane, "Lady Jane", + GI.GT_KLONDIKE, 2, 1)) +registerGame(GameInfo(496, Inquisitor, "Inquisitor", + GI.GT_KLONDIKE, 2, 2)) +registerGame(GameInfo(497, Arabella, "Arabella", + GI.GT_KLONDIKE, 3, 0)) diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py index cc42ebd1..d6e961a0 100644 --- a/pysollib/games/klondike.py +++ b/pysollib/games/klondike.py @@ -952,6 +952,7 @@ class SevenDevils(Klondike): # /*********************************************************************** # // Moving Left +# // Souter # ************************************************************************/ class MovingLeft(Klondike): @@ -964,7 +965,7 @@ class MovingLeft(Klondike): old_state = self.enterState(self.S_FILL) if stack in self.s.rows: i = list(self.s.rows).index(stack) - if i < 9: + if i < len(self.s.rows)-1: from_stack = self.s.rows[i+1] pile = from_stack.getPile() if pile: @@ -972,6 +973,86 @@ class MovingLeft(Klondike): self.leaveState(old_state) +class Souter(MovingLeft): + def createGame(self): + Klondike.createGame(self, max_rounds=2, rows=10, playcards=24) + + +# /*********************************************************************** +# // Big Forty +# // Ali Baba +# // Cassim +# ************************************************************************/ + +class BigForty(Klondike): + RowStack_Class = SS_RowStack + + def createGame(self): + Klondike.createGame(self, rows=10) + + def startGame(self): + self.s.talon.dealRow(frames=0) + self.s.talon.dealRow(frames=0) + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1 + + +class AliBaba(BigForty): + def _shuffleHook(self, cards): + # move Aces to top of the Talon (i.e. first cards to be dealt) + return self._shuffleHookMoveToTop(cards, + lambda c: (c.rank == ACE, c.suit)) + def startGame(self): + self.s.talon.dealRow(rows=self.s.foundations, frames=0) + BigForty.startGame(self) + + +class Cassim(AliBaba): + def createGame(self): + Klondike.createGame(self, rows=7) + + +# /*********************************************************************** +# // Saratoga +# ************************************************************************/ + +class Saratoga(Klondike): + def createGame(self): + Klondike.createGame(self, num_deal=3) + def startGame(self): + Klondike.startGame(self, flip=1) + + +# /*********************************************************************** +# // Whitehorse +# ************************************************************************/ + +class Whitehorse(Klondike): + + def createGame(self): + Klondike.createGame(self, num_deal=3) + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() + + def fillStack(self, stack): + if not stack.cards: + old_state = self.enterState(self.S_FILL) + if stack in self.s.rows: + if not self.s.waste.cards: + self.s.talon.dealCards() + if self.s.waste.cards: + self.s.waste.moveMove(1, stack) + self.leaveState(old_state) + + # register the game registerGame(GameInfo(2, Klondike, "Klondike", GI.GT_KLONDIKE, 1, -1)) @@ -1065,4 +1146,16 @@ registerGame(GameInfo(453, TripleEasthaven, "Triple Easthaven", GI.GT_GYPSY, 3, 0)) registerGame(GameInfo(470, MovingLeft, "Moving Left", GI.GT_KLONDIKE, 2, 0)) +registerGame(GameInfo(471, Souter, "Souter", + GI.GT_KLONDIKE, 2, 1)) +registerGame(GameInfo(473, BigForty, "Big Forty", + GI.GT_KLONDIKE, 1, -1)) +registerGame(GameInfo(474, AliBaba, "Ali Baba", + GI.GT_KLONDIKE, 1, -1)) +registerGame(GameInfo(475, Cassim, "Cassim", + GI.GT_KLONDIKE, 1, -1)) +registerGame(GameInfo(479, Saratoga, "Saratoga", + GI.GT_KLONDIKE, 1, -1)) +registerGame(GameInfo(491, Whitehorse, "Whitehorse", + GI.GT_KLONDIKE, 1, -1)) diff --git a/pysollib/games/numerica.py b/pysollib/games/numerica.py index 05c9a8b8..ca24b5cf 100644 --- a/pysollib/games/numerica.py +++ b/pysollib/games/numerica.py @@ -57,7 +57,7 @@ class Numerica_Hint(DefaultHint): #FIXME: implement this method def _getMoveWasteScore(self, score, color, r, t, pile, rpile): - assert r is self.game.s.waste and len(pile) == 1 + assert r in (self.game.s.waste, self.game.s.talon) and len(pile) == 1 score = 30000 if len(t.cards) == 0: score = score - (KING - r.cards[0].rank) * 1000 @@ -496,6 +496,7 @@ class Toad(Game): self.startDealSample() self.s.talon.dealRow(rows=self.s.reserves) + # /*********************************************************************** # // Shifting # ************************************************************************/ @@ -518,6 +519,65 @@ class Shifting(Numerica): RowStack_Class = StackWrapper(Shifting_RowStack, max_accept=1) +# /*********************************************************************** +# // Strategerie +# ************************************************************************/ + +class Strategerie_Talon(OpenTalonStack): + rightclickHandler = OpenStack.rightclickHandler + + +class Strategerie_RowStack(BasicRowStack): + + def acceptsCards(self, from_stack, cards): + if not BasicRowStack.acceptsCards(self, from_stack, cards): + return False + if from_stack is self.game.s.talon or from_stack in self.game.s.reserves: + return True + return False + + def getBottomImage(self): + return self.game.app.images.getReserveBottom() + + def getHelp(self): + return _('Row. Build regardless of rank and suit.') + + +class Strategerie_ReserveStack(ReserveStack): + def acceptsCards(self, from_stack, cards): + if not ReserveStack.acceptsCards(self, from_stack, cards): + return False + if from_stack is self.game.s.talon: + return True + return False + + +class Strategerie(Game): + Hint_Class = Numerica_Hint + + def createGame(self, **layout): + # create layout + l, s = Layout(self), self.s + l.freeCellLayout(rows=4, reserves=4, texts=1) + self.setSize(l.size[0], l.size[1]) + # create stacks + s.talon = Strategerie_Talon(l.s.talon.x, l.s.talon.y, self) + for r in l.s.foundations: + s.foundations.append(RK_FoundationStack(r.x, r.y, self)) + for r in l.s.rows: + s.rows.append(Strategerie_RowStack(r.x, r.y, self, + max_accept=UNLIMITED_ACCEPTS)) + for r in l.s.reserves: + s.reserves.append(Strategerie_ReserveStack(r.x, r.y, self)) + # default + l.defaultAll() + self.sg.dropstacks.append(s.talon) + + def startGame(self): + self.startDealSample() + self.s.talon.fillStack() + + # register the game registerGame(GameInfo(257, Numerica, "Numerica", @@ -541,4 +601,5 @@ registerGame(GameInfo(430, PussInTheCorner, "Puss in the Corner", GI.GT_NUMERICA, 1, 0)) registerGame(GameInfo(435, Shifting, "Shifting", GI.GT_NUMERICA, 1, 0)) - +registerGame(GameInfo(472, Strategerie, "Strategerie", + GI.GT_NUMERICA, 1, 0)) diff --git a/pysollib/games/spider.py b/pysollib/games/spider.py index 6e083183..02f51d7d 100644 --- a/pysollib/games/spider.py +++ b/pysollib/games/spider.py @@ -542,6 +542,7 @@ class Cicely(Game): # /*********************************************************************** # // Trillium # // Lily +# // Wake-Robin # ************************************************************************/ class Trillium(Game): @@ -549,21 +550,21 @@ class Trillium(Game): Hint_Class = Spider_Hint RowStack_Class = StackWrapper(AC_RowStack, base_rank=ANY_RANK) - def createGame(self, **layout): + def createGame(self, rows=13): # create layout l, s = Layout(self), self.s # set window - w, h = l.XM+13*l.XS, l.YM+l.YS+24*l.YOFFSET + w, h = l.XM+rows*l.XS, l.YM+l.YS+24*l.YOFFSET self.setSize(w, h) # create stacks x, y = l.XM, l.YM - for i in range(13): + for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) x += l.XS - s.talon = DealRowTalonStack(l.XM+6*l.XS, h-l.YS, self) + s.talon = DealRowTalonStack(l.XM+(rows-1)*l.XS/2, h-l.YS, self) l.createText(s.talon, "se") # define stack-groups @@ -591,6 +592,29 @@ class Lily(Trillium): RowStack_Class = StackWrapper(AC_RowStack, base_rank=KING) +class WakeRobin(Trillium): + RowStack_Class = RK_RowStack + + def createGame(self): + Trillium.createGame(self, rows=9) + + def isGameWon(self): + for s in self.s.rows: + if s.cards: + if len(s.cards) != 13 or not isRankSequence(s.cards): + return False + return True + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 1 + + + +class TripleWakeRobin(WakeRobin): + def createGame(self): + Trillium.createGame(self, rows=13) + + # /*********************************************************************** # // Chelicera # ************************************************************************/ @@ -808,9 +832,9 @@ class Applegate(Game): # /*********************************************************************** # // Big Spider # // Spider 3x3 -# // Ground for a Divorce (3 decks) +# // Big Ground # // Spider (4 decks) -# // Ground for a Divorce (4 decks) +# // Very Big Ground # ************************************************************************/ class BigSpider(Spider): @@ -993,11 +1017,11 @@ registerGame(GameInfo(220, RougeEtNoir, "Rouge et Noir", registerGame(GameInfo(269, Spider1Suit, "Spider (1 suit)", GI.GT_SPIDER, 2, 0, suits=(0, 0, 0, 0), - rules_filename = "spider.html")) + rules_filename="spider.html")) registerGame(GameInfo(270, Spider2Suits, "Spider (2 suits)", GI.GT_SPIDER, 2, 0, suits=(0, 0, 2, 2), - rules_filename = "spider.html")) + rules_filename="spider.html")) registerGame(GameInfo(305, ThreeBlindMice, "Three Blind Mice", GI.GT_SPIDER, 1, 0)) registerGame(GameInfo(309, MrsMop, "Mrs. Mop", @@ -1022,8 +1046,7 @@ registerGame(GameInfo(382, Applegate, "Applegate", GI.GT_SPIDER, 1, 0)) registerGame(GameInfo(384, BigSpider, "Big Spider", GI.GT_SPIDER, 3, 0)) -registerGame(GameInfo(401, GroundForADivorce3Decks, - "Ground for a Divorce (3 decks)", +registerGame(GameInfo(401, GroundForADivorce3Decks, "Big Ground", GI.GT_SPIDER, 3, 0)) registerGame(GameInfo(441, York, "York", GI.GT_SPIDER | GI.GT_OPEN | GI.GT_ORIGINAL, 2, 0)) @@ -1032,19 +1055,18 @@ registerGame(GameInfo(444, TripleYork, "Triple York", registerGame(GameInfo(445, BigSpider1Suit, "Big Spider (1 suit)", GI.GT_SPIDER, 3, 0, suits=(0, 0, 0, 0), - rules_filename = "bigspider.html")) + rules_filename="bigspider.html")) registerGame(GameInfo(446, BigSpider2Suits, "Big Spider (2 suits)", GI.GT_SPIDER, 3, 0, suits=(0, 0, 2, 2), - rules_filename = "bigspider.html")) + rules_filename="bigspider.html")) registerGame(GameInfo(449, Spider3x3, "Spider 3x3", GI.GT_SPIDER | GI.GT_ORIGINAL, 3, 0, suits=(0, 1, 2), - rules_filename = "bigspider.html")) + rules_filename="bigspider.html")) registerGame(GameInfo(454, Spider4Decks, "Spider (4 decks)", GI.GT_SPIDER, 4, 0)) -registerGame(GameInfo(455, GroundForADivorce4Decks, - "Ground for a Divorce (4 decks)", +registerGame(GameInfo(455, GroundForADivorce4Decks, "Very Big Ground", GI.GT_SPIDER, 4, 0)) registerGame(GameInfo(458, Spidike, "Spidike", GI.GT_SPIDER, 1, 0)) # GT_GYPSY ? @@ -1054,4 +1076,8 @@ registerGame(GameInfo(460, FredsSpider3Decks, "Fred's Spider (3 decks)", GI.GT_SPIDER, 3, 0)) registerGame(GameInfo(461, OpenSpider, "Open Spider", GI.GT_SPIDER, 2, 0)) +registerGame(GameInfo(501, WakeRobin, "Wake-Robin", + GI.GT_SPIDER | GI.GT_ORIGINAL, 2, 0)) +registerGame(GameInfo(502, TripleWakeRobin, "Wake-Robin (3 decks)", + GI.GT_SPIDER | GI.GT_ORIGINAL, 3, 0)) diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py index 1d44bf30..aacea609 100644 --- a/pysollib/games/sultan.py +++ b/pysollib/games/sultan.py @@ -581,6 +581,7 @@ class Simplicity(Game): # ************************************************************************/ class SixesAndSevens(Game): + def createGame(self, max_rounds=2): l, s = Layout(self), self.s @@ -629,6 +630,61 @@ class SixesAndSevens(Game): self.s.talon.dealCards() +# /*********************************************************************** +# // Corner Suite +# ************************************************************************/ + +class CornerSuite_RowStack(RK_RowStack): + def acceptsCards(self, from_stack, cards): + if not RK_RowStack.acceptsCards(self, from_stack, cards): + return False + if not self.cards: + return from_stack is self.game.s.waste + return True + def getBottomImage(self): + return self.game.app.images.getReserveBottom() + + +class CornerSuite(Game): + Hint_Class = CautiousDefaultHint + + def createGame(self): + l, s = Layout(self), self.s + self.setSize(l.XM+5*l.XS, l.YM+4*l.YS) + + suit = 0 + for x, y in ((0,0), (4,0), (0,4), (4,4)): + x, y = l.XM+x*l.XS, l.YM+y*l.YS + s.foundations.append(SS_FoundationStack(x, y, self, suit=suit)) + suit += 1 + + x, y = l.XM+3*l.XS/2, l.YM + s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 'nw') + x += l.XS + s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'ne') + + y = l.YM+l.YS + for i in range(3): + x = l.XM+l.XS + for j in range(3): + stack = CornerSuite_RowStack(x, y, self, max_move=1) + s.rows.append(stack) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 + x += l.XS + y += l.YS + + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealCards() + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 1 + + # register the game registerGame(GameInfo(330, Sultan, "Sultan", @@ -654,3 +710,5 @@ registerGame(GameInfo(437, Simplicity, "Simplicity", GI.GT_1DECK_TYPE, 1, 0)) registerGame(GameInfo(438, SixesAndSevens, "Sixes and Sevens", GI.GT_2DECK_TYPE, 2, 0)) +registerGame(GameInfo(477, CornerSuite, "Corner Suite", + GI.GT_2DECK_TYPE, 1, 0)) diff --git a/pysollib/games/terrace.py b/pysollib/games/terrace.py index 11ce931c..fc1f0da1 100644 --- a/pysollib/games/terrace.py +++ b/pysollib/games/terrace.py @@ -132,16 +132,17 @@ class Terrace(Game): # game layout # - def createGame(self, rows=9, max_rounds=1, num_deal=1): + def createGame(self, rows=9, max_rounds=1, num_deal=1, playcards=16): # create layout l, s = Layout(self), self.s # set window - # (piles up to 20 cards are playable in default window size) - maxrows = max(rows, 9) - w1, w2 = (maxrows - 8)*l.XS/2, (maxrows - rows)*l.XS/2 - h = max(3*l.YS, 20*l.YOFFSET) - self.setSize(l.XM + maxrows*l.XS + l.XM, l.YM + 2*l.YS + h) + # (piles up to 16 cards are playable in default window size) + decks = self.gameinfo.decks + maxrows = max(rows, decks*4+1) + w1, w2 = (maxrows - decks*4)*l.XS/2, (maxrows - rows)*l.XS/2 + h = max(3*l.YS, playcards*l.YOFFSET) + self.setSize(l.XM + maxrows*l.XS + l.XM, l.YM + 3*l.YS + h) # extra settings self.base_card = None @@ -159,9 +160,10 @@ class Terrace(Game): l.createText(stack, "sw") s.reserves.append(stack) x, y = l.XM + w1, y + l.YS - for i in range(8): - s.foundations.append(self.Foundation_Class(x, y, self, suit=i/2)) - x = x + l.XS + for i in range(4): + for j in range(decks): + s.foundations.append(self.Foundation_Class(x, y, self, suit=i)) + x = x + l.XS x, y = l.XM + w2, y + l.YS for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) @@ -184,11 +186,11 @@ class Terrace(Game): # game overrides # - def startGame(self): + def startGame(self, nrows=4): self.startDealSample() for i in range(self.INITIAL_RESERVE_CARDS): self.s.talon.dealRow(rows=self.s.reserves) - self.s.talon.dealRow(rows=self.s.rows[:4]) + self.s.talon.dealRow(rows=self.s.rows[:nrows]) def fillStack(self, stack): if not stack.cards: @@ -235,7 +237,7 @@ class GeneralsPatience(Terrace): # /*********************************************************************** -# // +# // Blondes and Brunettes # ************************************************************************/ class BlondesAndBrunettes(Terrace): @@ -258,13 +260,35 @@ class BlondesAndBrunettes(Terrace): # /*********************************************************************** -# // +# // Falling Star # ************************************************************************/ class FallingStar(BlondesAndBrunettes): INITIAL_RESERVE_CARDS = 11 +# /*********************************************************************** +# // Signora +# ************************************************************************/ + +class Signora(Terrace): + def startGame(self): + Terrace.startGame(self, nrows=9) + + +# /*********************************************************************** +# // Madame +# ************************************************************************/ + +class Madame(Terrace): + INITIAL_RESERVE_CARDS = 15 + def createGame(self): + Terrace.createGame(self, rows=10, playcards=20) + def startGame(self): + Terrace.startGame(self, nrows=10) + + + # register the game registerGame(GameInfo(135, Terrace, "Terrace", GI.GT_TERRACE, 2, 0)) @@ -276,4 +300,8 @@ registerGame(GameInfo(138, FallingStar, "Falling Star", GI.GT_TERRACE, 2, 0)) registerGame(GameInfo(431, QueenOfItaly, "Queen of Italy", GI.GT_TERRACE, 2, 0)) +registerGame(GameInfo(499, Signora, "Signora", + GI.GT_TERRACE, 2, 0)) +registerGame(GameInfo(500, Madame, "Madame", + GI.GT_TERRACE, 3, 0)) diff --git a/pysollib/games/ultra/hanafuda1.py b/pysollib/games/ultra/hanafuda1.py index 1b30e53d..f6288d80 100644 --- a/pysollib/games/ultra/hanafuda1.py +++ b/pysollib/games/ultra/hanafuda1.py @@ -396,10 +396,10 @@ class SixTengus(SixSages): # /*********************************************************************** -# * Four Seasons +# * Hanafuda Four Seasons # ************************************************************************/ -class FourSeasons(AbstractFlowerGame): +class HanafudaFourSeasons(AbstractFlowerGame): # # Game layout @@ -706,7 +706,7 @@ r(12374, JapaneseGardenII, 'Japanese Garden II', GI.GT_HANAFUDA | GI.GT_OPEN, 1, r(12375, SixSages, 'Six Sages', GI.GT_HANAFUDA | GI.GT_OPEN, 1, 0) r(12376, SixTengus, 'Six Tengus', GI.GT_HANAFUDA | GI.GT_OPEN, 1, 0) r(12377, JapaneseGardenIII, 'Japanese Garden III', GI.GT_HANAFUDA | GI.GT_OPEN, 1, 0) -r(12378, FourSeasons, 'Four Seasons', GI.GT_HANAFUDA | GI.GT_OPEN, 1, 0) +r(12378, HanafudaFourSeasons, 'Hanafuda Four Seasons', GI.GT_HANAFUDA | GI.GT_OPEN, 1, 0) r(12380, Eularia, 'Eularia', GI.GT_HANAFUDA, 1, -1) r(12381, Peony, 'Peony', GI.GT_HANAFUDA, 1, -1) r(12382, Iris, 'Iris', GI.GT_HANAFUDA, 1, 0) diff --git a/pysollib/games/windmill.py b/pysollib/games/windmill.py index fc9e62a7..4d1d7389 100644 --- a/pysollib/games/windmill.py +++ b/pysollib/games/windmill.py @@ -201,8 +201,9 @@ class NapoleonsTomb(Windmill): # ************************************************************************/ class Corners(Game): + RowStack_Class = ReserveStack - def createGame(self): + def createGame(self, max_rounds=3): # create layout l, s = Layout(self, XM=20, YM=20), self.s @@ -211,7 +212,7 @@ class Corners(Game): # create stacks x, y = l.XM+l.XS, l.YM - s.talon = WasteTalonStack(x, y, self, max_rounds=3) + s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds) l.createText(s.talon, "sw") x += l.XS s.waste = WasteStack(x, y, self) @@ -225,7 +226,9 @@ class Corners(Game): i += 1 for d in ((2,0), (1,1), (2,1), (3,1), (2,2)): x, y = x0+d[0]*l.XS, y0+d[1]*l.YS - s.rows.append(ReserveStack(x, y, self)) + stack = self.RowStack_Class(x, y, self) + s.rows.append(stack) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 # define stack-groups l.defaultStackGroups() @@ -260,6 +263,62 @@ class Corners(Game): self.s.talon.dealCards() # deal first card to WasteStack +# /*********************************************************************** +# // Czarina +# // Four Seasons +# ************************************************************************/ + +class Czarina_RowStack(RK_RowStack): + def getBottomImage(self): + return self.game.app.images.getReserveBottom() + + +class Czarina(Corners): + Hint_Class = CautiousDefaultHint + RowStack_Class = StackWrapper(Czarina_RowStack, mod=13, max_move=1) + + def createGame(self): + # extra settings + self.base_card = None + Corners.createGame(self, max_rounds=1) + + def startGame(self): + self.startDealSample() + self.base_card = None + # deal base_card to Foundations, update foundations cap.base_rank + self.base_card = self.s.talon.getCard() + for s in self.s.foundations: + s.cap.base_rank = self.base_card.rank + self.flipMove(self.s.talon) + self.moveMove(1, self.s.talon, self.s.foundations[self.base_card.suit]) + self.s.talon.dealRow() + self.s.talon.dealCards() # deal first 3 cards to WasteStack + + def _shuffleHook(self, cards): + return cards + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return ((card1.rank + 1) % 13 == card2.rank or + (card2.rank + 1) % 13 == card1.rank) + + def _restoreGameHook(self, game): + self.base_card = self.cards[game.loadinfo.base_card_id] + for s in self.s.foundations: + s.cap.base_rank = self.base_card.rank + + def _loadGameHook(self, p): + self.loadinfo.addattr(base_card_id=None) # register extra load var. + self.loadinfo.base_card_id = p.load() + + def _saveGameHook(self, p): + p.dump(self.base_card.id) + + +class FourSeasons(Czarina): + def fillStack(self, stack): + pass + + # register the game registerGame(GameInfo(30, Windmill, "Windmill", GI.GT_2DECK_TYPE, 2, 0)) @@ -267,4 +326,8 @@ registerGame(GameInfo(277, NapoleonsTomb, "Napoleon's Tomb", GI.GT_1DECK_TYPE, 1, 0)) registerGame(GameInfo(417, Corners, "Corners", GI.GT_1DECK_TYPE, 1, 2)) +registerGame(GameInfo(483, Czarina, "Czarina", + GI.GT_1DECK_TYPE, 1, 0)) +registerGame(GameInfo(484, FourSeasons, "Four Seasons", + GI.GT_1DECK_TYPE, 1, 0)) diff --git a/pysollib/games/yukon.py b/pysollib/games/yukon.py index 949425cd..c9442e17 100644 --- a/pysollib/games/yukon.py +++ b/pysollib/games/yukon.py @@ -206,7 +206,7 @@ class Alaska(RussianSolitaire): # /*********************************************************************** -# // Roslin (like Russian Solitaire, but build up or down by alternate color) +# // Roslin (like Yukon, but build up or down by alternate color) # ************************************************************************/ class Roslin_RowStack(Yukon_AC_RowStack): @@ -374,11 +374,12 @@ class DoubleRussianSolitaire(DoubleYukon): # /*********************************************************************** # // Triple Yukon +# // Triple Russian Solitaire # ************************************************************************/ class TripleYukon(Yukon): def createGame(self): - Yukon.createGame(self, rows=13) + Yukon.createGame(self, rows=13, playcards=34) def startGame(self): for i in range(1, len(self.s.rows)): self.s.talon.dealRow(rows=self.s.rows[i:], flip=0, frames=0) @@ -389,6 +390,14 @@ class TripleYukon(Yukon): assert len(self.s.talon.cards) == 0 +class TripleRussianSolitaire(TripleYukon): + RowStack_Class = StackWrapper(Yukon_SS_RowStack, base_rank=KING) + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return (card1.suit == card2.suit and + (card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank)) + + # /*********************************************************************** # // Ten Across # ************************************************************************/ @@ -469,6 +478,7 @@ class Panopticon(TenAcross): # /*********************************************************************** # // Australian Patience # // Raw Prawn +# // Bim Bom # ************************************************************************/ class AustralianPatience(RussianSolitaire): @@ -511,6 +521,29 @@ class BimBom(AustralianPatience): self.s.talon.dealCards() +# /*********************************************************************** +# // Geoffrey +# ************************************************************************/ + +class Geoffrey(Yukon): + Layout_Method = Layout.klondikeLayout + RowStack_Class = StackWrapper(Yukon_SS_RowStack, base_rank=KING) + + def createGame(self): + Yukon.createGame(self, rows=8, waste=0) + + def startGame(self): + for i in (4, 4, 4, 4, 8): + self.s.talon.dealRow(rows=self.s.rows[:i], flip=1, frames=0) + self.s.talon.dealRow(rows=self.s.rows[i:], flip=0, frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealRow(rows=self.s.rows[:4]) + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1 + + # register the game registerGame(GameInfo(19, Yukon, "Yukon", @@ -554,4 +587,9 @@ registerGame(GameInfo(450, RawPrawn, "Raw Prawn", registerGame(GameInfo(456, BimBom, "Bim Bom", GI.GT_YUKON | GI.GT_ORIGINAL, 2, 0)) registerGame(GameInfo(466, DoubleRussianSolitaire, "Double Russian Solitaire", - GI.GT_YUKON | GI.GT_ORIGINAL, 2, 0)) + GI.GT_YUKON, 2, 0)) +registerGame(GameInfo(488, TripleRussianSolitaire, "Triple Russian Solitaire", + GI.GT_YUKON, 3, 0)) +registerGame(GameInfo(492, Geoffrey, "Geoffrey", + GI.GT_YUKON, 1, 0)) +