diff --git a/pysollib/game.py b/pysollib/game.py index 027a310d..055e2054 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -190,18 +190,32 @@ class Game: print 'WARNING: invalid sum of foundations.max_cards:', \ class_name, ncards, self.gameinfo.ncards if self.s.rows: - from stack import AC_RowStack, SS_RowStack, RK_RowStack + from stack import AC_RowStack, UD_AC_RowStack, \ + SS_RowStack, UD_SS_RowStack, \ + RK_RowStack, UD_RK_RowStack, \ + Spider_AC_RowStack, Spider_SS_RowStack r = self.s.rows[0] for c, f in ( - (AC_RowStack, (self._shallHighlightMatch_AC, - self._shallHighlightMatch_ACW)), - (SS_RowStack, (self._shallHighlightMatch_SS, - self._shallHighlightMatch_SSW)), - (RK_RowStack, (self._shallHighlightMatch_RK, - self._shallHighlightMatch_RKW)),): - if isinstance(r, c) and not self.shallHighlightMatch in f: - print 'WARNING: shallHighlightMatch is not valid:', \ - class_name, r.__class__ + ((Spider_AC_RowStack, Spider_SS_RowStack), + (self._shallHighlightMatch_RK, + self._shallHighlightMatch_RKW)), + ((AC_RowStack, UD_AC_RowStack), + (self._shallHighlightMatch_AC, + self._shallHighlightMatch_ACW)), + ((SS_RowStack, UD_SS_RowStack), + (self._shallHighlightMatch_SS, + self._shallHighlightMatch_SSW)), + ((RK_RowStack, UD_RK_RowStack), + (self._shallHighlightMatch_RK, + self._shallHighlightMatch_RKW)),): + if isinstance(r, c): + if not self.shallHighlightMatch in f: + print 'WARNING: shallHighlightMatch is not valid:', \ + class_name, r.__class__ + if r.cap.mod == 13 and self.shallHighlightMatch != f[1]: + print 'WARNING: shallHighlightMatch is not valid (wrap):', \ + class_name, r.__class__ + break # optimize regions self.optimizeRegions() # create cards diff --git a/pysollib/games/bakersdozen.py b/pysollib/games/bakersdozen.py index f8c93abb..3f8142f7 100644 --- a/pysollib/games/bakersdozen.py +++ b/pysollib/games/bakersdozen.py @@ -148,8 +148,6 @@ class BakersDozen(CastlesInSpain): class SpanishPatience(BakersDozen): Foundation_Class = AC_FoundationStack - shallHighlightMatch = Game._shallHighlightMatch_AC - # /*********************************************************************** # // Portuguese Solitaire diff --git a/pysollib/games/beleagueredcastle.py b/pysollib/games/beleagueredcastle.py index 9189b08d..e846d580 100644 --- a/pysollib/games/beleagueredcastle.py +++ b/pysollib/games/beleagueredcastle.py @@ -277,6 +277,9 @@ class Bastion(Game): self.s.talon.dealRow(rows=self.s.reserves) + shallHighlightMatch = Game._shallHighlightMatch_SS + + class TenByOne(Bastion): def createGame(self): Bastion.createGame(self, reserves=1) @@ -683,11 +686,7 @@ class CastleMount(Lightweight): RowStack_Class = Spider_SS_RowStack shallHighlightMatch = Game._shallHighlightMatch_RK - - 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 + getQuickPlayScore = Game._getSpiderQuickPlayScore # /*********************************************************************** @@ -713,6 +712,8 @@ class SelectiveCastle(StreetsAndAlleys, Chessboard): def updateText(self): Chessboard.updateText(self) + shallHighlightMatch = Game._shallHighlightMatch_RKW + # register the game registerGame(GameInfo(146, StreetsAndAlleys, "Streets and Alleys", diff --git a/pysollib/games/bristol.py b/pysollib/games/bristol.py index 4fcd44d5..d298f834 100644 --- a/pysollib/games/bristol.py +++ b/pysollib/games/bristol.py @@ -144,6 +144,8 @@ class Bristol(Game): self.s.talon.dealRow(rows=r) self.s.talon.dealCards() # deal first cards to Reserves + shallHighlightMatch = Game._shallHighlightMatch_RK + # /*********************************************************************** # // Belvedere @@ -376,6 +378,124 @@ class Gotham(NewYork): self.s.talon.dealRow(frames=0) NewYork.startGame(self) + shallHighlightMatch = Game._shallHighlightMatch_RKW + + +# /*********************************************************************** +# // Interment +# ************************************************************************/ + +class Interment_Hint(CautiousDefaultHint): + def computeHints(self): + CautiousDefaultHint.computeHints(self) + if self.hints: + return + if not self.game.s.talon.cards: + return + c = self.game.s.talon.cards[-1].rank + if 0 <= c <= 3: + r = self.game.s.xwastes[0] + elif 4 <= c <= 7: + r = self.game.s.xwastes[1] + else: + r = self.game.s.xwastes[2] + self.addHint(5000, 1, self.game.s.talon, r) + + +class Interment_Talon(OpenTalonStack): + rightclickHandler = OpenStack.rightclickHandler + doubleclickHandler = OpenStack.doubleclickHandler + + +class Interment_Reserve(OpenStack): + def canFlipCard(self): + return False + + +class Interment_Waste(ReserveStack): + def acceptsCards(self, from_stack, cards): + if not ReserveStack.acceptsCards(self, from_stack, cards): + return False + return from_stack is self.game.s.talon + + +class Interment(Game): + Hint_Class = Interment_Hint + + def createGame(self): + # create layout + l, s = Layout(self), self.s + s.addattr(xwastes=[]) # register extra stack variable + + # set window + w, h = l.XM+11*l.XS, l.YM+6*l.YS + self.setSize(w, h) + + # create stacks + x, y, = l.XM, l.YM + s.talon = Interment_Talon(x, y, self) + l.createText(s.talon, 'ne') + x += 1.5*l.XS + for i in range(8): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i/2)) + x += l.XS + x, y = l.XM, l.YM+l.YS + for i in range(3): + s.xwastes.append(Interment_Waste(x, y, self, + max_cards=UNLIMITED_CARDS)) + y += l.YS + x, y = l.XM+1.5*l.XS, l.YM+l.YS + for i in range(8): + s.rows.append(SS_RowStack(x, y, self, max_move=1)) + x += l.XS + x, y = self.width-l.XS, l.YM + stack = Interment_Reserve(x, y, self) + s.reserves.append(stack) + l.createText(stack, 'nw') + y += l.YS + for i in range(5): + s.reserves.append(OpenStack(x, y, self)) + y += l.YS + + # define stack-groups + l.defaultStackGroups() + self.sg.dropstacks += s.xwastes + self.sg.openstacks += s.xwastes + self.sg.dropstacks.append(s.talon) + + + def startGame(self): + for i in range(13): + self.s.talon.dealRow(rows=[self.s.reserves[0]], flip=0, frames=0) + self.s.talon.dealRow(rows=self.s.reserves[1:], frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.fillStack() + + + def fillStack(self, stack): + if not stack.cards: + old_state = self.enterState(self.S_FILL) + if stack in self.s.rows: + if self.s.talon.cards: + self.s.talon.moveMove(1, stack) + if stack in self.s.reserves[1:]: + from_stack = self.s.reserves[0] + if from_stack.cards: + from_stack.flipMove() + from_stack.moveMove(1, stack) + self.leaveState(old_state) + + + shallHighlightMatch = Game._shallHighlightMatch_SS + + + def getQuickPlayScore(self, ncards, from_stack, to_stack): + if to_stack in self.s.xwastes: + return 0 + return 1+Game.getQuickPlayScore(self, ncards, from_stack, to_stack) + + # register the game registerGame(GameInfo(42, Bristol, "Bristol", @@ -390,4 +510,6 @@ registerGame(GameInfo(468, Spike, "Spike", GI.GT_KLONDIKE, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(519, Gotham, "Gotham", GI.GT_FAN_TYPE, 2, 0, GI.SL_BALANCED)) +registerGame(GameInfo(604, Interment, "Interment", + GI.GT_FAN_TYPE, 2, 0, GI.SL_BALANCED)) diff --git a/pysollib/games/canfield.py b/pysollib/games/canfield.py index 9dfea82e..9be4bf61 100644 --- a/pysollib/games/canfield.py +++ b/pysollib/games/canfield.py @@ -255,6 +255,7 @@ class Rainbow(Canfield): def createGame(self): Canfield.createGame(self, max_rounds=1, num_deal=1) + shallHighlightMatch = Game._shallHighlightMatch_RKW # /*********************************************************************** # // Storehouse (aka Straight Up) @@ -318,6 +319,8 @@ class AmericanToad(Canfield): def createGame(self): Canfield.createGame(self, rows=8, max_rounds=2, num_deal=1) + shallHighlightMatch = Game._shallHighlightMatch_SSW + # /*********************************************************************** # // Variegated Canfield @@ -397,6 +400,8 @@ class EagleWing(Canfield): # define stack-groups l.defaultStackGroups() + shallHighlightMatch = Game._shallHighlightMatch_SSW + # /*********************************************************************** # // Gate @@ -720,6 +725,89 @@ class CanfieldRush(Canfield): Canfield.createGame(self, max_rounds=3) +# /*********************************************************************** +# // Skippy +# ************************************************************************/ + +class Skippy(Canfield): + FILL_EMPTY_ROWS = 0 + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + playcards = 8 + w0 = l.XS+playcards*l.XOFFSET + w = l.XM+l.XS/2+max(10*l.XS, l.XS+4*w0) + h = l.YM+5*l.YS+l.TEXT_HEIGHT + self.setSize(w, h) + + # extra settings + self.base_card = None + + # 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 = self.width - 8*l.XS + for i in range(8): + s.foundations.append(SS_FoundationStack(x, y, self, + suit=i%4, mod=13)) + x += l.XS + tx, ty, ta, tf = l.getTextAttr(None, "ss") + tx, ty = x-l.XS+tx, y+ty + font = self.app.getFont("canvas_default") + self.texts.info = MfxCanvasText(self.canvas, tx, ty, + anchor=ta, font=font) + x, y = l.XM, l.YM+l.YS+l.TEXT_HEIGHT + for i in range(4): + s.reserves.append(ReserveStack(x, y, self)) + y += l.YS + y = l.YM+l.YS+l.TEXT_HEIGHT + for i in range(4): + x = l.XM+l.XS+l.XS/2 + for j in range(4): + stack = RK_RowStack(x, y, self, max_move=1, mod=13) + s.rows.append(stack) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 + x += w0 + y += l.YS + + # define stack-groups + l.defaultStackGroups() + + + def startGame(self): + self.base_card = None + self.updateText() + # 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 + n = self.base_card.suit + self.flipMove(self.s.talon) + self.moveMove(1, self.s.talon, self.s.foundations[n], frames=0) + self.updateText() + # update rows cap.base_rank + row_base_rank = (self.base_card.rank-1)%13 + for s in self.s.rows: + s.cap.base_rank = row_base_rank + # + for i in range(3): + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() + + + shallHighlightMatch = Game._shallHighlightMatch_RKW + + + # register the game registerGame(GameInfo(105, Canfield, "Canfield", # was: 262 GI.GT_CANFIELD | GI.GT_CONTRIB, 1, -1, GI.SL_BALANCED)) @@ -764,5 +852,8 @@ registerGame(GameInfo(494, Mystique, "Mystique", registerGame(GameInfo(521, CanfieldRush, "Canfield Rush", GI.GT_CANFIELD, 1, 2, GI.SL_BALANCED)) registerGame(GameInfo(527, Doorway, "Doorway", - GI.GT_KLONDIKE, 1, 0, GI.SL_BALANCED)) + GI.GT_KLONDIKE, 1, 0, GI.SL_BALANCED, + altnames=('Solstice',) )) +registerGame(GameInfo(605, Skippy, "Skippy", + GI.GT_FAN_TYPE, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/capricieuse.py b/pysollib/games/capricieuse.py index c36f43bd..62d6c96c 100644 --- a/pysollib/games/capricieuse.py +++ b/pysollib/games/capricieuse.py @@ -22,7 +22,6 @@ __all__ = [] # imports -import sys # PySol imports from pysollib.gamedb import registerGame, GameInfo, GI @@ -33,48 +32,16 @@ from pysollib.game import Game from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from gypsy import DieRussische_Foundation + # /*********************************************************************** # // Capricieuse # ************************************************************************/ -class Capricieuse_Talon(TalonStack): - - def canDealCards(self): - if self.round == self.max_rounds: - return False - return not self.game.isGameWon() - - def dealCards(self, sound=0): - # move all cards to the Talon, shuffle and redeal - lr = len(self.game.s.rows) - num_cards = 0 - assert len(self.cards) == 0 - for r in self.game.s.rows[::-1]: - for i in range(len(r.cards)): - num_cards = num_cards + 1 - self.game.moveMove(1, r, self, frames=0) - assert len(self.cards) == num_cards - if num_cards == 0: # game already finished - return 0 - # shuffle - self.game.shuffleStackMove(self) - # redeal - self.game.nextRoundMove(self) - self.game.startDealSample() - for i in range(lr): - k = min(lr, len(self.cards)) - for j in range(k): - self.game.moveMove(1, self, self.game.s.rows[j], frames=4) - # done - self.game.stopSamples() - assert len(self.cards) == 0 - return num_cards - - class Capricieuse(Game): - Talon_Class = StackWrapper(Capricieuse_Talon, max_rounds=3) + Talon_Class = StackWrapper(RedealTalonStack, max_rounds=3) RowStack_Class = UD_SS_RowStack # @@ -87,7 +54,7 @@ class Capricieuse(Game): l, s = Layout(self), self.s # set window - self.setSize(l.XM+12*l.XS, l.YM+l.YS+20*l.YOFFSET) + self.setSize(l.XM+12*l.XS, l.YM+2*l.YS+15*l.YOFFSET) # create stacks x, y, = l.XM+2*l.XS, l.YM @@ -120,7 +87,12 @@ class Capricieuse(Game): self.s.talon.dealRow(self.s.foundations) def _shuffleHook(self, cards): - return self._shuffleHookMoveToBottom(cards, lambda c: (c.deck == 0 and c.rank in (0, 12), (c.rank, c.suit)), 8) + return self._shuffleHookMoveToBottom(cards, + lambda c: (c.deck == 0 and c.rank in (0, 12), (c.rank, c.suit)), 8) + + def redealCards(self): + while self.s.talon.cards: + self.s.talon.dealRowAvail(frames=4) shallHighlightMatch = Game._shallHighlightMatch_SS @@ -136,9 +108,54 @@ class Nationale(Capricieuse): shallHighlightMatch = Game._shallHighlightMatch_SSW +# /*********************************************************************** +# // Strata +# ************************************************************************/ + +class Strata(Game): + + def createGame(self, **layout): + + # create layout + l, s = Layout(self), self.s + + # set window + self.setSize(l.XM+9*l.XS, l.YM+2*l.YS+12*l.YOFFSET) + + # create stacks + x, y, = l.XM+l.XS, l.YM + for i in range(8): + s.foundations.append(DieRussische_Foundation(x, y, self, + suit=i%4, max_cards=8)) + x = x + l.XS + 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=2) + + # define stack-groups + l.defaultStackGroups() + + def startGame(self): + for i in range(7): + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + + def redealCards(self): + while self.s.talon.cards: + self.s.talon.dealRowAvail(frames=4) + + shallHighlightMatch = Game._shallHighlightMatch_AC + + # register the game registerGame(GameInfo(292, Capricieuse, "Capricieuse", GI.GT_BAKERS_DOZEN | GI.GT_OPEN, 2, 2, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(293, Nationale, "Nationale", GI.GT_BAKERS_DOZEN | GI.GT_OPEN, 2, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(606, Strata, "Strata", + GI.GT_BAKERS_DOZEN | GI.GT_OPEN, 2, 1, GI.SL_MOSTLY_SKILL, + ranks=(0, 6, 7, 8, 9, 10, 11, 12) )) diff --git a/pysollib/games/curdsandwhey.py b/pysollib/games/curdsandwhey.py index dc0825f2..3a32eed7 100644 --- a/pysollib/games/curdsandwhey.py +++ b/pysollib/games/curdsandwhey.py @@ -138,6 +138,7 @@ class Nordic(MissMuffet): class Dumfries_TalonStack(OpenTalonStack): rightclickHandler = OpenStack.rightclickHandler + doubleclickHandler = OpenStack.doubleclickHandler class Dumfries_RowStack(BasicRowStack): diff --git a/pysollib/games/dieboesesieben.py b/pysollib/games/dieboesesieben.py index 1531fd22..847d7445 100644 --- a/pysollib/games/dieboesesieben.py +++ b/pysollib/games/dieboesesieben.py @@ -117,6 +117,8 @@ class DieBoeseSieben(Game): for flip in (1, 0, 1, 0, 1, 0, 1): self.s.talon.dealRow(flip=flip) + shallHighlightMatch = Game._shallHighlightMatch_AC + # register the game registerGame(GameInfo(120, DieBoeseSieben, "Bad Seven", diff --git a/pysollib/games/diplomat.py b/pysollib/games/diplomat.py index 05e1fa8a..93b8de48 100644 --- a/pysollib/games/diplomat.py +++ b/pysollib/games/diplomat.py @@ -196,6 +196,8 @@ class Wheatsheaf(Congress): ] RowStack_Class = UD_SS_RowStack + shallHighlightMatch = Game._shallHighlightMatch_SS + # /*********************************************************************** # // Rows of Four @@ -252,10 +254,7 @@ class LittleNapoleon(Diplomat): 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 + getQuickPlayScore = Game._getSpiderQuickPlayScore # /*********************************************************************** @@ -272,6 +271,8 @@ class TwinQueens(Congress): def createGame(self): Congress.createGame(self, max_rounds=2) + shallHighlightMatch = Game._shallHighlightMatch_SS + # register the game diff --git a/pysollib/games/fan.py b/pysollib/games/fan.py index 26d81a67..c0d339bd 100644 --- a/pysollib/games/fan.py +++ b/pysollib/games/fan.py @@ -213,6 +213,7 @@ class LaBelleLucie(Fan): class SuperFlowerGarden(LaBelleLucie): RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK) + shallHighlightMatch = Game._shallHighlightMatch_RK # /*********************************************************************** @@ -559,7 +560,8 @@ class BoxFan(Fan): class Troika(Fan): - RowStack_Class = StackWrapper(RK_RowStack, dir=0, base_rank=NO_RANK, max_cards=3) + RowStack_Class = StackWrapper(RK_RowStack, dir=0, + base_rank=NO_RANK, max_cards=3) def createGame(self): Fan.createGame(self, rows=(6, 6, 6), playcards=4) @@ -580,7 +582,6 @@ class Troika(Fan): self.s.talon.dealRow(rows=[t], frames=4) - class TroikaPlus_RowStack(RK_RowStack): def getBottomImage(self): return self.game.app.images.getReserveBottom() @@ -600,6 +601,7 @@ class TroikaPlus(Troika): ## self.s.talon.dealRow(rows=self.s.rows[:-1]) + # register the game registerGame(GameInfo(56, Fan, "Fan", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/fortythieves.py b/pysollib/games/fortythieves.py index fc15acc6..b329ecc2 100644 --- a/pysollib/games/fortythieves.py +++ b/pysollib/games/fortythieves.py @@ -288,6 +288,8 @@ class Deuces(FortyThieves): self.s.talon.dealRow(rows=self.s.foundations) FortyThieves.startGame(self) + shallHighlightMatch = Game._shallHighlightMatch_SSW + # /*********************************************************************** # // Corona @@ -311,6 +313,8 @@ class Quadrangle(Corona): FortyThieves.startGame(self) self.s.talon.dealSingleBaseCard() + shallHighlightMatch = Game._shallHighlightMatch_SSW + # /*********************************************************************** # // Forty and Eight @@ -334,10 +338,8 @@ class LittleForty(FortyThieves): def createGame(self): FortyThieves.createGame(self, max_rounds=4, num_deal=3, XOFFSET=0) - 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 + shallHighlightMatch = Game._shallHighlightMatch_RK + getQuickPlayScore = Game._getSpiderQuickPlayScore # /*********************************************************************** @@ -796,10 +798,8 @@ class Waterloo(FortyThieves): 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 + getQuickPlayScore = Game._getSpiderQuickPlayScore + shallHighlightMatch = Game._shallHighlightMatch_RK # /*********************************************************************** diff --git a/pysollib/games/freecell.py b/pysollib/games/freecell.py index edc1d8d6..1f3dfdf2 100644 --- a/pysollib/games/freecell.py +++ b/pysollib/games/freecell.py @@ -553,6 +553,9 @@ class KingCell(FreeCell): Hint_Class = FreeCellType_Hint RowStack_Class = StackWrapper(KingCell_RowStack, base_rank=KING) + shallHighlightMatch = Game._shallHighlightMatch_RK + + # register the game registerGame(GameInfo(5, RelaxedFreeCell, "Relaxed FreeCell", diff --git a/pysollib/games/glenwood.py b/pysollib/games/glenwood.py index f11c9d69..ce739d81 100644 --- a/pysollib/games/glenwood.py +++ b/pysollib/games/glenwood.py @@ -225,12 +225,14 @@ class DoubleFives_Talon(RedealTalonStack): class DoubleFives_RowStack(SS_RowStack): - def canMoveCards(self, cards): - if self.game.base_rank is None: - return False - if not SS_RowStack.canMoveCards(self, cards): - return False - return True + def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): + SS_RowStack.moveMove(self, ncards, to_stack, frames, shadow) + if self.game.base_rank is None and to_stack in self.game.s.foundations: + old_state = self.game.enterState(self.game.S_FILL) + self.game.saveStateMove(2|16) # for undo + self.game.base_rank = to_stack.cards[-1].rank + self.game.saveStateMove(1|16) # for redo + self.game.leaveState(old_state) class DoubleFives_WasteStack(WasteStack): diff --git a/pysollib/games/golf.py b/pysollib/games/golf.py index 40c00933..da1690f6 100644 --- a/pysollib/games/golf.py +++ b/pysollib/games/golf.py @@ -534,6 +534,8 @@ class FourLeafClovers(Game): self.startDealSample() self.s.talon.dealRow() + shallHighlightMatch = Game._shallHighlightMatch_RKW + # /*********************************************************************** # // All in a Row diff --git a/pysollib/games/gypsy.py b/pysollib/games/gypsy.py index e56d1b95..9435b043 100644 --- a/pysollib/games/gypsy.py +++ b/pysollib/games/gypsy.py @@ -326,11 +326,7 @@ class Steve(Carlton): RowStack_Class = Spider_SS_RowStack shallHighlightMatch = Game._shallHighlightMatch_RK - - 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 + getQuickPlayScore = Game._getSpiderQuickPlayScore # /*********************************************************************** @@ -446,7 +442,6 @@ class Cone(Gypsy): for i in range(7): s.rows.append(AC_RowStack(x, y, self, mod=13)) x += l.XS - #y += l.YS for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i, mod=13, max_cards=26)) @@ -455,13 +450,14 @@ class Cone(Gypsy): # define stack-groups l.defaultStackGroups() - def startGame(self): self.startDealSample() self.s.talon.dealRow() for i in (1, 2, 3): self.s.talon.dealRow(rows=self.s.rows[i:-i]) + shallHighlightMatch = Game._shallHighlightMatch_ACW + # /*********************************************************************** # // Surprise diff --git a/pysollib/games/harp.py b/pysollib/games/harp.py index a859eece..8a9d5d49 100644 --- a/pysollib/games/harp.py +++ b/pysollib/games/harp.py @@ -188,11 +188,9 @@ class LadyJane(DoubleKlondike): DoubleKlondike.createGame(self, rows=10, max_rounds=2, num_deal=3) def startGame(self): DoubleKlondike.startGame(self, flip=1) + shallHighlightMatch = Game._shallHighlightMatch_RK - 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 + getQuickPlayScore = Game._getSpiderQuickPlayScore class Inquisitor(DoubleKlondike): @@ -212,15 +210,14 @@ class Inquisitor(DoubleKlondike): 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) + shallHighlightMatch = Game._shallHighlightMatch_RK - 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 + getQuickPlayScore = Game._getSpiderQuickPlayScore # /*********************************************************************** diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py index 16c94b74..fa295af8 100644 --- a/pysollib/games/klondike.py +++ b/pysollib/games/klondike.py @@ -277,6 +277,8 @@ class BlindAlleys(Eastcliff): # // Somerset # // Morehead # // Canister +# // American Canister +# // British Canister # ************************************************************************/ class Somerset(Klondike): @@ -299,22 +301,6 @@ class Morehead(Somerset): RowStack_Class = StackWrapper(BO_RowStack, max_move=1) -class Canister(Klondike): - Talon_Class = InitialDealTalonStack - RowStack_Class = RK_RowStack - ###Hint_Class = CautiousDefaultHint - - def createGame(self): - Klondike.createGame(self, max_rounds=1, rows=8, waste=0, texts=0) - - def startGame(self): - for i in range(5): - self.s.talon.dealRow(frames=0) - self.startDealSample() - self.s.talon.dealRow() - self.s.talon.dealRow(rows=self.s.rows[2:6]) - - class Usk(Somerset): Talon_Class = RedealTalonStack @@ -329,6 +315,34 @@ class Usk(Somerset): self.s.talon.dealRowAvail(rows=self.s.rows[n:], frames=4) n += 1 +# /*********************************************************************** +# // Canister +# // American Canister +# // British Canister +# ************************************************************************/ + +class AmericanCanister(Klondike): + Talon_Class = InitialDealTalonStack + + def createGame(self): + Klondike.createGame(self, max_rounds=1, rows=8, waste=0, texts=0) + + def startGame(self): + for i in range(5): + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealRow(rows=self.s.rows[2:6]) + + +class Canister(AmericanCanister): + RowStack_Class = RK_RowStack + shallHighlightMatch = Game._shallHighlightMatch_RK + + +class BritishCanister(AmericanCanister): + RowStack_Class = StackWrapper(KingAC_RowStack, max_move=1) + # /*********************************************************************** # // Agnes Sorel @@ -472,6 +486,8 @@ class FlowerGarden(Stonewall): DEAL = (1, 1, 1, 1, -1, 1, 1) + shallHighlightMatch = Game._shallHighlightMatch_RK + # /*********************************************************************** # // King Albert @@ -543,6 +559,9 @@ class Brigade(Raglan): # ************************************************************************/ class Jane_Talon(OpenTalonStack): + rightclickHandler = OpenStack.rightclickHandler + doubleclickHandler = OpenStack.doubleclickHandler + def canFlipCard(self): return 0 @@ -561,6 +580,7 @@ class Jane_Talon(OpenTalonStack): return c + class Jane(Klondike): Talon_Class = Jane_Talon Foundation_Class = StackWrapper(SS_FoundationStack, mod=13, base_rank=NO_RANK, min_cards=1) @@ -577,7 +597,7 @@ class Jane(Klondike): s.talon = self.Talon_Class(x, y, self, max_rounds=max_rounds) l.createText(s.talon, 'ss') x += l.XS - s.waste = WasteStack(l.XM+l.XS+40, l.YM, self) + s.waste = WasteStack(l.XM+l.XS, l.YM, self) x += 2*l.XS for i in range(4): @@ -615,7 +635,7 @@ class Jane(Klondike): s.cap.update(cap.__dict__) self.saveinfo.stack_caps.append((s.id, cap)) - shallHighlightMatch = Game._shallHighlightMatch_SSW + shallHighlightMatch = Game._shallHighlightMatch_ACW def _autoDeal(self, sound=1): return 0 @@ -672,19 +692,20 @@ class Senate(Jane): l.defaultStackGroups() - def startGame(self): self.s.talon.dealRow(rows=self.s.foundations, frames=0) self.startDealSample() self.s.talon.dealRow(rows=self.s.reserves) self.s.talon.dealRow() - 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.deck, c.suit))) + shallHighlightMatch = Game._shallHighlightMatch_SS + + class SenatePlus(Senate): def createGame(self): Senate.createGame(self, rows=5) @@ -732,6 +753,8 @@ class Phoenix(Klondike): class Arizona(Phoenix): RowStack_Class = RK_RowStack + shallHighlightMatch = Game._shallHighlightMatch_RK + # /*********************************************************************** # // Alternation @@ -923,6 +946,9 @@ class DoubleDot(Klondike): self.startDealSample() self.s.talon.dealRow() + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) == 2 + # /*********************************************************************** # // Seven Devils @@ -1119,12 +1145,45 @@ class GoldMine(Klondike): # // Lucky Piles # ************************************************************************/ -class LuckyThirteen(Klondike): - Talon_Class = InitialDealTalonStack - RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK, max_move=1) +class LuckyThirteen(Game): + RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK) - def createGame(self): - Klondike.createGame(self, waste=False, rows=13, max_rounds=1, texts=False) + def createGame(self, xoffset=0, playcards=0): + l, s = Layout(self), self.s + if xoffset: + xoffset = l.XOFFSET + w0 = l.XS+playcards*l.XOFFSET + self.setSize(l.XM + 5*w0+2*l.XS, l.YM+4*l.YS) + + x, y = l.XM, l.YM + for i in range(5): + stack = self.RowStack_Class(x, y, self, max_move=1) + s.rows.append(stack) + stack.CARD_XOFFSET = xoffset + stack.CARD_YOFFSET = 0 + x += w0 + x, y = l.XM+w0, l.YM+l.YS + for i in range(3): + stack = self.RowStack_Class(x, y, self, max_move=1) + s.rows.append(stack) + stack.CARD_XOFFSET = xoffset + stack.CARD_YOFFSET = 0 + x += w0 + x, y = l.XM, l.YM+2*l.YS + for i in range(5): + stack = self.RowStack_Class(x, y, self, max_move=1) + s.rows.append(stack) + stack.CARD_XOFFSET = xoffset + stack.CARD_YOFFSET = 0 + x += w0 + x, y = self.width-l.XS, l.YM + for i in range(4): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) + y += l.YS + x, y = l.XM, self.height-l.YS + s.talon = InitialDealTalonStack(x, y, self, max_rounds=1) + + l.defaultStackGroups() def startGame(self): self.s.talon.dealRow(frames=0) @@ -1133,12 +1192,17 @@ class LuckyThirteen(Klondike): self.startDealSample() self.s.talon.dealRow() - shallHighlightMatch = Game._shallHighlightMatch_SS + shallHighlightMatch = Game._shallHighlightMatch_RK class LuckyPiles(LuckyThirteen): RowStack_Class = StackWrapper(UD_SS_RowStack, base_rank=KING) + def createGame(self): + LuckyThirteen.createGame(self, xoffset=1, playcards=5) + + shallHighlightMatch = Game._shallHighlightMatch_SS + # register the game @@ -1262,4 +1326,8 @@ registerGame(GameInfo(585, LuckyThirteen, "Lucky Thirteen", GI.GT_NUMERICA, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(586, LuckyPiles, "Lucky Piles", GI.GT_NUMERICA, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(601, AmericanCanister, "American Canister", + GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(602, BritishCanister, "British Canister", + GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/numerica.py b/pysollib/games/numerica.py index cb00e699..f59a515e 100644 --- a/pysollib/games/numerica.py +++ b/pysollib/games/numerica.py @@ -213,6 +213,7 @@ class LastChance(LadyBetty): class PussInTheCorner_Talon(OpenTalonStack): rightclickHandler = OpenStack.rightclickHandler + doubleclickHandler = OpenStack.doubleclickHandler def canDealCards(self): if self.round != self.max_rounds: @@ -606,6 +607,7 @@ class Shifting(Numerica): class Strategerie_Talon(OpenTalonStack): rightclickHandler = OpenStack.rightclickHandler + doubleclickHandler = OpenStack.doubleclickHandler class Strategerie_RowStack(BasicRowStack): @@ -690,7 +692,7 @@ class AnnoDomini(Numerica): Hint_Class = AnnoDomini_Hint Foundation_Class = StackWrapper(SS_FoundationStack, suit=ANY_SUIT, mod=13) - RowStack_Class = AC_RowStack + RowStack_Class = StackWrapper(AC_RowStack, mod=13) def createGame(self): Numerica.createGame(self, max_rounds=3, waste_max_cards=UNLIMITED_CARDS) @@ -711,7 +713,7 @@ class AnnoDomini(Numerica): self.s.talon.dealRow() self.s.talon.dealCards() - shallHighlightMatch = Game._shallHighlightMatch_AC + shallHighlightMatch = Game._shallHighlightMatch_ACW diff --git a/pysollib/games/royalcotillion.py b/pysollib/games/royalcotillion.py index 7312d08e..ffb2e5f1 100644 --- a/pysollib/games/royalcotillion.py +++ b/pysollib/games/royalcotillion.py @@ -320,6 +320,8 @@ class Alhambra(Game): self.s.talon.dealRow(rows=self.s.reserves) self.s.talon.dealCards() + shallHighlightMatch = Game._shallHighlightMatch_SSW + class Granada(Alhambra): def createGame(self): @@ -463,6 +465,8 @@ class BritishConstitution(Game): self.s.waste.moveMove(1, stack) self.leaveState(old_state) + shallHighlightMatch = Game._shallHighlightMatch_AC + class NewBritishConstitution(BritishConstitution): RowStack_Class = StackWrapper(BritishConstitution_RowStack, base_rank=JACK) diff --git a/pysollib/games/royaleast.py b/pysollib/games/royaleast.py index 64f680af..9f7f34f0 100644 --- a/pysollib/games/royaleast.py +++ b/pysollib/games/royaleast.py @@ -116,6 +116,8 @@ class RoyalEast(Game): def _saveGameHook(self, p): p.dump(self.base_card.id) + shallHighlightMatch = Game._shallHighlightMatch_RKW + # register the game registerGame(GameInfo(93, RoyalEast, "Royal East", diff --git a/pysollib/games/siebenbisas.py b/pysollib/games/siebenbisas.py index b644fb14..bf85694c 100644 --- a/pysollib/games/siebenbisas.py +++ b/pysollib/games/siebenbisas.py @@ -154,6 +154,8 @@ class SiebenBisAs(Game): for r in stacks: self.moveMove(1, r, self.s.foundations[r.cards[-1].suit]) + shallHighlightMatch = Game._shallHighlightMatch_SSW + # /*********************************************************************** # // Maze diff --git a/pysollib/games/spider.py b/pysollib/games/spider.py index db3f23c4..cfbe4405 100644 --- a/pysollib/games/spider.py +++ b/pysollib/games/spider.py @@ -150,11 +150,8 @@ class RelaxedSpider(Game): self.s.talon.dealRow() shallHighlightMatch = Game._shallHighlightMatch_RK + getQuickPlayScore = Game._getSpiderQuickPlayScore - 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 # /*********************************************************************** # // Spider @@ -492,6 +489,8 @@ class RougeEtNoir(Game): self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:-1], reverse=reverse) + shallHighlightMatch = Game._shallHighlightMatch_AC + # /*********************************************************************** # // Mrs. Mop @@ -573,6 +572,9 @@ class Cicely(Game): self.s.talon.dealRow() + shallHighlightMatch = Game._shallHighlightMatch_SS + + # /*********************************************************************** # // Trillium # // Lily diff --git a/pysollib/games/sthelena.py b/pysollib/games/sthelena.py index 1a28b85a..1fb75243 100644 --- a/pysollib/games/sthelena.py +++ b/pysollib/games/sthelena.py @@ -154,6 +154,7 @@ class StHelena(Game): self.s.talon.dealRow() self.s.talon.dealRow(self.s.foundations) + shallHighlightMatch = Game._shallHighlightMatch_RK # /*********************************************************************** # // Box Kite @@ -164,6 +165,9 @@ class BoxKite(StHelena): Foundation_Class = SS_FoundationStack RowStack_Class = StackWrapper(UD_RK_RowStack, base_rank=NO_RANK, mod=13) + shallHighlightMatch = Game._shallHighlightMatch_RKW + + # register the game registerGame(GameInfo(302, StHelena, "St. Helena", diff --git a/pysollib/games/takeaway.py b/pysollib/games/takeaway.py index a4633c1d..1acdc3fc 100644 --- a/pysollib/games/takeaway.py +++ b/pysollib/games/takeaway.py @@ -105,6 +105,9 @@ class FourStacks(TakeAway): RowStack_Class = StackWrapper(AC_RowStack, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS) Foundation_Class = StackWrapper(AC_FoundationStack, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS, dir=-1) + shallHighlightMatch = Game._shallHighlightMatch_AC + + # register the game registerGame(GameInfo(334, TakeAway, "Take Away", diff --git a/pysollib/games/terrace.py b/pysollib/games/terrace.py index de2f579e..b24bdfaa 100644 --- a/pysollib/games/terrace.py +++ b/pysollib/games/terrace.py @@ -217,6 +217,8 @@ class Terrace(Game): break p.dump(base_rank) + shallHighlightMatch = Game._shallHighlightMatch_ACW + # /*********************************************************************** # // Queen of Italy diff --git a/pysollib/games/unionsquare.py b/pysollib/games/unionsquare.py index 4b912a66..eb8cefdf 100644 --- a/pysollib/games/unionsquare.py +++ b/pysollib/games/unionsquare.py @@ -171,6 +171,9 @@ class SolidSquare(UnionSquare): self.s.waste.moveMove(1, stack) self.leaveState(old_state) + shallHighlightMatch = Game._shallHighlightMatch_SSW + + # register the game registerGame(GameInfo(35, UnionSquare, "Union Square", diff --git a/pysollib/games/yukon.py b/pysollib/games/yukon.py index 41417bc8..ddeb02a7 100644 --- a/pysollib/games/yukon.py +++ b/pysollib/games/yukon.py @@ -628,6 +628,36 @@ class DoubleRussianSpider(RussianSpider, DoubleRussianSolitaire): DoubleRussianSolitaire.startGame(self) +# /*********************************************************************** +# // Brisbane +# ************************************************************************/ + +class Brisbane_RowStack(Yukon_AC_RowStack): + def _isSequence(self, c1, c2): + return (c1.rank + self.cap.dir) % self.cap.mod == c2.rank + def getHelp(self): + return _('Tableau. Build down regardless of suit, can move any face-up cards regardless of sequence.') + + +class Brisbane(Yukon): + RowStack_Class = Brisbane_RowStack + + 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) + for i in range(3): + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealRowAvail() + + def getHighlightPilesStacks(self): + return () + + shallHighlightMatch = Game._shallHighlightMatch_RK + + + # register the game registerGame(GameInfo(19, Yukon, "Yukon", GI.GT_YUKON, 1, 0, GI.SL_BALANCED)) @@ -684,3 +714,5 @@ registerGame(GameInfo(530, RussianSpider, "Russian Spider", altnames=('Ukrainian Solitaire',) )) registerGame(GameInfo(531, DoubleRussianSpider, "Double Russian Spider", GI.GT_SPIDER | GI.GT_ORIGINAL, 2, 0, GI.SL_BALANCED)) +registerGame(GameInfo(603, Brisbane, "Brisbane", + GI.GT_SPIDER, 1, 0, GI.SL_BALANCED)) diff --git a/pysollib/stack.py b/pysollib/stack.py index 8c03ad71..21cc6fc1 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -776,10 +776,17 @@ class Stack: # by default all open stacks are available for highlighting assert card in self.cards if not self.is_visible or not card.face_up: - return 0 + return False if card is self.cards[-1]: - return 1 - return self.is_open + return True + if not self.is_open: + return False + dx, dy = self.getOffsetFor(card) + if dx == 0 and dy <= 4: + return False + if dx <= 4 and dy == 0: + return False + return True def basicShallHighlightMatch(self, card): # by default all open stacks are available for highlighting @@ -1704,7 +1711,6 @@ class OpenStack(Stack): self.dragMove(drag, stack, sound=sound) def quickPlayHandler(self, event, from_stacks=None, to_stacks=None): - ##print 'quickPlayHandler', from_stacks, to_stacks # from_stacks and to_stacks are meant for possible # use in a subclasses if from_stacks is None: