From d7ec0c66ba5c1ff9db8f0ccb3ae97dd3eb246d05 Mon Sep 17 00:00:00 2001 From: skomoroh Date: Sat, 12 Aug 2006 21:15:56 +0000 Subject: [PATCH] + 6 new games * misc. improvements git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@45 efabe8c0-fbe8-4139-b769-b5e6d273206e --- pysollib/game.py | 3 + pysollib/games/calculation.py | 18 +- pysollib/games/picturegallery.py | 3 +- pysollib/games/pushpin.py | 81 ++++++-- pysollib/games/pyramid.py | 332 +++++++++++++++++++++++++++++-- pysollib/games/sultan.py | 89 +-------- pysollib/games/takeaway.py | 83 ++++++++ pysollib/games/windmill.py | 81 +++++++- pysollib/stack.py | 15 +- 9 files changed, 576 insertions(+), 129 deletions(-) diff --git a/pysollib/game.py b/pysollib/game.py index f53bbeca..de1f209d 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -1478,6 +1478,9 @@ for %d moves. sx0, sy0 = s.getOffsetFor(c1) x1, y1 = s.getPositionFor(c1) x2, y2 = x1, y1 + if c1 is s.cards[-1]: + # last card in the stack (for Pyramid-like games) + tkraise = True else: # highlight pile if len(s.CARD_XOFFSET) > 1: diff --git a/pysollib/games/calculation.py b/pysollib/games/calculation.py index b2c61ba1..8cfad24d 100644 --- a/pysollib/games/calculation.py +++ b/pysollib/games/calculation.py @@ -392,30 +392,20 @@ class SeniorWrangler_RowStack(BasicRowStack): class SeniorWrangler(Game): def createGame(self): - # create layout l, s = Layout(self), self.s - # set window - self.setSize(l.XM+9.5*l.XS, l.YM+3*l.YS+l.TEXT_HEIGHT) + self.setSize(l.XM+9.5*l.XS, l.YM+3*l.YS) - # create stacks x, y = l.XM+1.5*l.XS, l.YM for i in range(8): 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, y = l.XM+1.5*l.XS, l.YM+l.YS - for i in range(8): - stack = BetsyRoss_Foundation(x, y, self, base_rank=(2*i+3)%13, - mod=13, dir=i+1, - max_cards=12, max_move=0) + mod=13, dir=i+1, max_move=0) tx, ty, ta, tf = l.getTextAttr(stack, "s") font = self.app.getFont("canvas_default") stack.texts.misc = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) s.foundations.append(stack) x = x + l.XS - x, y = l.XM+1.5*l.XS, l.YM+2*l.YS+l.TEXT_HEIGHT + x, y = l.XM+1.5*l.XS, l.YM+2*l.YS for i in range(8): stack = SeniorWrangler_RowStack(x, y, self, max_accept=0) s.rows.append(stack) @@ -436,7 +426,7 @@ class SeniorWrangler(Game): top = [] ranks = [] for c in cards[:]: - if c.rank in range(1,9) and c.rank not in ranks: + if c.rank in range(8) and c.rank not in ranks: ranks.append(c.rank) cards.remove(c) top.append(c) diff --git a/pysollib/games/picturegallery.py b/pysollib/games/picturegallery.py index b1582fbe..8b8a8115 100644 --- a/pysollib/games/picturegallery.py +++ b/pysollib/games/picturegallery.py @@ -581,7 +581,8 @@ registerGame(GameInfo(398, MountOlympus, "Mount Olympus", registerGame(GameInfo(399, Zeus, "Zeus", GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(546, RoyalParade, "Royal Parade", - GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL)) + GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL, + rules_filename='virginiareel.html')) registerGame(GameInfo(547, VirginiaReel, "Virginia Reel", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/pushpin.py b/pysollib/games/pushpin.py index 4f491ff5..f0710104 100644 --- a/pysollib/games/pushpin.py +++ b/pysollib/games/pushpin.py @@ -22,12 +22,10 @@ __all__ = [] # imports -import sys, types # PySol imports from pysollib.gamedb import registerGame, GameInfo, GI from pysollib.util import * -from pysollib.mfxutil import kwdefault from pysollib.stack import * from pysollib.game import Game from pysollib.layout import Layout @@ -91,8 +89,7 @@ class PushPin_RowStack(ReserveStack): def acceptsCards(self, from_stack, cards): if not self.cards: - return from_stack.id > self.id - return True + return False if abs(self.id - from_stack.id) != 1: return False ps = min(self.id, from_stack.id)-1 @@ -128,6 +125,7 @@ class PushPin_RowStack(ReserveStack): class PushPin(Game): Hint_Class = PushPin_Hint + RowStack_Class = PushPin_RowStack # # game layout @@ -154,7 +152,7 @@ class PushPin(Game): if i%2: k = xx-j-1 x, y = l.XM + k*l.XS, l.YM + i*l.YS - s.rows.append(PushPin_RowStack(x, y, self)) + s.rows.append(self.RowStack_Class(x, y, self)) s.talon = PushPin_Talon(l.XM, l.YM, self) s.foundations.append(PushPin_Foundation(l.XM, h-l.YS, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, @@ -171,9 +169,7 @@ class PushPin(Game): def isGameWon(self): return len(self.s.foundations[0].cards) == 50 - def fillEmptyStacks(self): - if not self.demo: - self.startDealSample() + def _fillOne(self): rows = self.s.rows i = 0 for r in rows: @@ -185,14 +181,21 @@ class PushPin(Game): if r.cards: break j += 1 - for r in rows[j:]: - if not r.cards: + else: + return 0 + self.moveMove(1, rows[j], rows[i], frames=2, shadow=0) + return 1 + + def fillEmptyStacks(self): + if not self.demo: + self.startDealSample() + old_state = self.enterState(self.S_FILL) + while True: + if not self._fillOne(): break - self.moveMove(1, r, rows[i], frames=2, shadow=0) - i += 1 + self.leaveState(old_state) if not self.demo: self.stopSamples() - return 0 def getAutoStacks(self, event=None): return ((), (), ()) @@ -223,9 +226,61 @@ class Queens(PushPin): self.s.talon.dealRow() +# /*********************************************************************** +# // Accordion +# ************************************************************************/ + +class Accordion_Hint(AbstractHint): + + def computeHints(self): + game = self.game + rows = game.s.rows + for i in range(len(rows)-3): + r1, r2 = rows[i], rows[i+1] + if r1.cards and r2.cards: + c1, c2 = r1.cards[0], r2.cards[0] + if c1.rank == c2.rank or c1.suit == c2.suit: + self.addHint(5000, 1, r1, r2) + r1, r2 = rows[i], rows[i+3] + if r1.cards and r2.cards: + c1, c2 = r1.cards[0], r2.cards[0] + if c1.rank == c2.rank or c1.suit == c2.suit: + self.addHint(6000, 1, r1, r2) + + +class Accordion_RowStack(PushPin_RowStack): + + def acceptsCards(self, from_stack, cards): + if not self.cards: + return False + if abs(self.id - from_stack.id) not in (1,3): + return False + c1, c2 = self.cards[-1], cards[0] + if c1.rank == c2.rank: + return True + return c1.suit == c2.suit + + clickHandler = ReserveStack.clickHandler + + +class Accordion(PushPin): + Hint_Class = Accordion_Hint + RowStack_Class = Accordion_RowStack + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow(rows=self.s.rows[:2]) + + def isGameWon(self): + return len(self.s.foundations[0].cards) == 52 + + registerGame(GameInfo(287, PushPin, "Push Pin", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(288, RoyalMarriage, "Royal Marriage", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) ## registerGame(GameInfo(303, Queens, "Queens", ## GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0)) +registerGame(GameInfo(656, Accordion, "Accordion", + GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED, + altnames=('Idle Year', 'Methuselah', 'Tower of Babel') )) diff --git a/pysollib/games/pyramid.py b/pysollib/games/pyramid.py index 5a23824c..c180554a 100644 --- a/pysollib/games/pyramid.py +++ b/pysollib/games/pyramid.py @@ -168,7 +168,10 @@ class Pyramid_RowStack(Pyramid_StackMethods, OpenStack): class Pyramid(Game): Hint_Class = Pyramid_Hint + Foundation_Class = Pyramid_Foundation Talon_Class = StackWrapper(Pyramid_Talon, max_rounds=3, max_accept=1) + RowStack_Class = Pyramid_RowStack + WasteStack_Class = Pyramid_Waste # # game layout @@ -191,25 +194,26 @@ class Pyramid(Game): x = l.XM + (8-i) * l.XS / 2 y = l.YM + i * l.YS / 2 for j in range(i+1): - s.rows.append(Pyramid_RowStack(x, y, self)) + s.rows.append(self.RowStack_Class(x, y, self)) x = x + l.XS x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) if texts: 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) + 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) if waste: y = y + l.YS - s.waste = Pyramid_Waste(x, y, self, max_accept=1) + s.waste = self.WasteStack_Class(x, y, self, max_accept=1) l.createText(s.waste, "se") x, y = self.width - l.XS, l.YM - s.foundations.append(Pyramid_Foundation(x, y, self, - suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, - max_move=0, max_cards=52)) + s.foundations.append(self.Foundation_Class(x, y, self, + suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, + max_move=0, max_cards=52)) if reserves: x, y = l.XM+(max_rows-reserves)*l.XS/2, l.YM+4*l.YS for i in range(reserves): @@ -222,6 +226,7 @@ class Pyramid(Game): l.defaultStackGroups() self.sg.openstacks.append(s.talon) self.sg.dropstacks.append(s.talon) + self.sg.openstacks.append(s.waste) # @@ -280,7 +285,6 @@ class Giza(Pyramid): # // FIXME: UNFINISHED # // (this doesn't work yet as 2 cards of the Waste should be playable) # ************************************************************************/ -# Thirteen #89404422185320919548 class Thirteen(Pyramid): @@ -306,7 +310,7 @@ class Thirteen(Pyramid): s.talon = WasteTalonStack(x, y, self, max_rounds=1) l.createText(s.talon, "s") x = x + l.XS - s.waste = Pyramid_Waste(x, y, self) + s.waste = Pyramid_Waste(x, y, self, max_accept=1) l.createText(s.waste, "s") s.waste.CARD_XOFFSET = 14 x, y = self.width - l.XS, l.YM @@ -484,6 +488,11 @@ class Elevens(Pyramid): self.leaveState(old_state) + def shallHighlightMatch(self, stack1, card1, stack2, card2): + # FIXME + return False + + class ElevensToo(Elevens): def fillStack(self, stack): @@ -676,6 +685,297 @@ class TripleAlliance(Game): return len(self.s.foundations[0].cards) == 51 +# /*********************************************************************** +# // Pharaohs +# ************************************************************************/ + +class Pharaohs_RowStack(Pyramid_RowStack): + + def acceptsCards(self, from_stack, cards): + if not self.basicAcceptsCards(from_stack, cards): + return False + if not self.cards: + return False + r0, r1 = cards[0].rank, self.cards[-1].rank + if r0+r1 == 11: + return True + return r0 == r1 + + def basicIsBlocked(self): + for r in self.blockmap: + if r.cards: + return True + return False + + +class Pharaohs(Pyramid): + + Talon_Class = InitialDealTalonStack + RowStack_Class = Pharaohs_RowStack + + PYRAMID_Y_FACTOR = 3 + + def _createPyramid(self, l, x0, y0, size): + rows = [] + # create stacks + for i in range(size): + x = x0 + (size-1-i) * l.XS / 2 + y = y0 + i * l.YS / self.PYRAMID_Y_FACTOR + for j in range(i+1): + stack = self.RowStack_Class(x, y, self) + rows.append(stack) + stack.blockmap = [] + x = x + l.XS + # compute blocking + n = 0 + lr = len(rows) + for i in range(size-1): + for j in range(i+1): + k = n+i+1 + rows[n].blockmap = [rows[k],rows[k+1]] + n += 1 + return rows + + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + w = l.XM + 9*l.XS + h = l.YM + 5.67*l.YS + self.setSize(w, h) + + # create stacks + x, y = l.XM, l.YM + s.rows += self._createPyramid(l, x, y, 2) + x, y = l.XM+2*l.XS, l.YM + s.rows += self._createPyramid(l, x, y, 7) + x, y = l.XM+2.5*l.XS, l.YM+3*l.YS + s.rows += self._createPyramid(l, x, y, 6) + + x, y = l.XM, self.height-l.YS + s.talon = self.Talon_Class(x, y, self) + x, y = self.width - l.XS, l.YM + s.foundations.append(Pyramid_Foundation(x, y, self, + suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, + max_move=0, max_cards=52)) + + # define stack-groups + l.defaultStackGroups() + + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow(frames=4) + + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return (card1.rank + card2.rank == 11 or + card1.rank == card2.rank) + + +# /*********************************************************************** +# // Baroness +# ************************************************************************/ + +class Baroness_Talon(DealRowTalonStack): + def dealCards(self, sound=0): + rows = self.game.s.rows + if len(self.cards) == 7: + rows += self.game.s.reserves + return self.dealRowAvail(rows=rows, sound=sound) + + +class Baroness_RowStack(Giza_Reserve): + + def acceptsCards(self, from_stack, cards): + if not self.basicAcceptsCards(from_stack, cards): + return False + if not self.cards: + return True + return cards[0].rank + self.cards[-1].rank == 11 + + def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): + if to_stack in self.game.s.rows and not to_stack.cards: + return OpenStack.moveMove(self, ncards, to_stack, frames, shadow) + return Giza_Reserve.moveMove(self, ncards, to_stack, frames, shadow) + + +class Baroness(Pyramid): + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + self.setSize(l.XM+9*l.XS, l.YM+max(3.5*l.YS, l.YS+12*l.YOFFSET)) + + # create stacks + x, y = l.XM, l.YM + s.talon = Baroness_Talon(x, y, self) + l.createText(s.talon, 's') + + x += 2*l.XS + for i in range(5): + stack = Baroness_RowStack(x, y, self, max_accept=1) + s.rows.append(stack) + stack.CARD_YOFFSET = l.YOFFSET + x += l.XS + x += l.XS + s.foundations.append(Pyramid_Foundation(x, y, self, + suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, + max_move=0, max_cards=52)) + x, y = l.XM, self.height-l.YS + s.reserves.append(Giza_Reserve(x, y, self, max_accept=1)) + y -= l.YS + s.reserves.append(Giza_Reserve(x, y, self, max_accept=1)) + + # define stack-groups + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + + +# /*********************************************************************** +# // Apophis +# ************************************************************************/ + +class Apophis_Hint(Pyramid_Hint): + def computeHints(self): + DefaultHint.computeHints(self) + if self.hints: + return + reserves = self.game.s.reserves + for i in range(3): + for j in range(i+1,3): + r1 = reserves[i] + r2 = reserves[j] + if r1.cards and r2.acceptsCards(r1, r1.cards[-1:]): + self.addHint(50000+len(r1.cards)+len(r2.cards), 1, r1, r2) + + +class Apophis_RowStack(Pharaohs_RowStack): + def acceptsCards(self, from_stack, cards): + if not self.basicAcceptsCards(from_stack, cards): + return False + if not self.cards: + return False + r0, r1 = cards[0].rank, self.cards[-1].rank + return r0+r1 == 11 + + +class Apophis_Talon(RedealTalonStack): + def canDealCards(self): + r_cards = sum([len(r.cards) for r in self.game.s.reserves]) + if self.cards: + return True + elif r_cards and self.round != self.max_rounds: + return True + return False + + def dealCards(self, sound=0): + num_cards = 0 + if sound and self.game.app.opt.animations: + self.game.startDealSample() + if not self.cards: + num_cards = self._redeal(rows=self.game.s.reserves, frames=4) + self.game.nextRoundMove(self) + num_cards += self.dealRowAvail(rows=self.game.s.reserves, sound=0) + if sound: + self.game.stopSamples() + return num_cards + + +class Apophis(Pharaohs): + Hint_Class = Apophis_Hint + RowStack_Class = Apophis_RowStack + + PYRAMID_Y_FACTOR = 2 + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + w = l.XM + 9*l.XS + h = l.YM + 4*l.YS + self.setSize(w, h) + + # create stacks + x, y = l.XM+1.5*l.XS, l.YM + s.rows = self._createPyramid(l, x, y, 7) + + x, y = l.XM, l.YM + s.talon = Apophis_Talon(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) + y += l.YS + for i in range(3): + stack = Pyramid_Waste(x, y, self, max_accept=1) + s.reserves.append(stack) + l.createText(stack, 'se') + y += l.YS + x, y = self.width - l.XS, l.YM + s.foundations.append(Pyramid_Foundation(x, y, self, + suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, + max_move=0, max_cards=52)) + + # define stack-groups + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow(frames=3) + self.s.talon.dealCards() + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return card1.rank + card2.rank == 11 + +# /*********************************************************************** +# // Cheops +# ************************************************************************/ + +class Cheops_StackMethods(Pyramid_StackMethods): + def acceptsCards(self, from_stack, cards): + if self.basicIsBlocked(): + return 0 + if from_stack is self or not self.cards or len(cards) != 1: + return 0 + c = self.cards[-1] + return (c.face_up and cards[0].face_up and + abs(cards[0].rank-c.rank) in (0,1)) + +class Cheops_Talon(Cheops_StackMethods, Pyramid_Talon): + def clickHandler(self, event): + return FaceUpWasteTalonStack.clickHandler(self, event) + +class Cheops_Waste(Cheops_StackMethods, Pyramid_Waste): + def clickHandler(self, event): + return WasteStack.clickHandler(self, event) + +class Cheops_RowStack(Cheops_StackMethods, Pyramid_RowStack): + def clickHandler(self, event): + return OpenStack.clickHandler(self, event) + + +class Cheops(Pyramid): + + Foundation_Class = AbstractFoundationStack + Talon_Class = StackWrapper(Cheops_Talon, max_rounds=1, max_accept=1) + RowStack_Class = Cheops_RowStack + WasteStack_Class = Cheops_Waste + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return abs(card1.rank-card2.rank) in (0,1) + + + # register the game registerGame(GameInfo(38, Pyramid, "Pyramid", GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK)) @@ -697,5 +997,13 @@ registerGame(GameInfo(597, Fifteens, "Fifteens", GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(619, TripleAlliance, "Triple Alliance", GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_SKILL)) - +registerGame(GameInfo(655, Pharaohs, "Pharaohs", + GI.GT_PAIRING_TYPE, 1, 0, GI.SL_BALANCED)) +registerGame(GameInfo(657, Baroness, "Baroness", + GI.GT_PAIRING_TYPE, 1, 0, GI.SL_BALANCED, + altnames=('Five Piles',) )) +registerGame(GameInfo(658, Apophis, "Apophis", + GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK)) +registerGame(GameInfo(659, Cheops, "Cheops", + GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py index abaeeefc..26ab7c0e 100644 --- a/pysollib/games/sultan.py +++ b/pysollib/games/sultan.py @@ -189,32 +189,32 @@ class CaptiveQueens(Game): def createGame(self): l, s = Layout(self), self.s - self.setSize(l.XM+5*l.XS, max(l.YM+3*l.YS, l.YM+2*l.YS+3*l.TEXT_HEIGHT)) + self.setSize(l.XM+5.5*l.XS, l.YM+3*l.YS) - x, y = l.XM, l.YM+l.TEXT_HEIGHT + x, y = l.XM, l.YM+l.YS/2 s.talon = WasteTalonStack(x, y, self, max_rounds=3) - l.createText(s.talon, "s") + 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) - y += l.YS+l.TEXT_HEIGHT + y += l.YS s.waste = WasteStack(x, y, self) - l.createText(s.waste, "s") + l.createText(s.waste, "se") - x, y = l.XM+l.XS, l.YM + x, y = l.XM+1.5*l.XS, l.YM for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i, mod=13, max_cards=6, base_rank=4, dir=-1)) x += l.XS - x, y = l.XM+l.XS, l.YM+l.YS + 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)) x += l.XS - x, y = l.XM+l.XS, l.YM+2*l.YS + x, y = l.XM+1.5*l.XS, l.YM+2*l.YS for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i, mod=13, max_cards=6, base_rank=5)) @@ -224,7 +224,7 @@ class CaptiveQueens(Game): def startGame(self): self.startDealSample() - self.s.talon.dealCards() # deal first card to WasteStack + self.s.talon.dealCards() def isGameWon(self): return (len(self.s.talon.cards) + len(self.s.waste.cards)) == 0 @@ -562,75 +562,6 @@ class Patriarchs(PicturePatience): self.s.talon.dealCards() -# /*********************************************************************** -# // Simplicity -# ************************************************************************/ - -class Simplicity(Game): - Hint_Class = CautiousDefaultHint - - def createGame(self, max_rounds=2): - - l, s = Layout(self), self.s - self.setSize(l.XM+8*l.XS, l.YM+4*l.YS) - - self.base_card = None - - i = 0 - for x, y in ((l.XM, l.YM), - (l.XM+7*l.XS, l.YM), - (l.XM, l.YM+3*l.YS), - (l.XM+7*l.XS, l.YM+3*l.YS), - ): - s.foundations.append(SS_FoundationStack(x, y, self, suit=i, mod=13)) - i += 1 - y = l.YM+l.YS - for i in range(2): - x = l.XM+l.XS - for j in range(6): - stack = AC_RowStack(x, y, self, max_move=1, mod=13) - stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 - s.rows.append(stack) - x += l.XS - y += l.YS - x, y = l.XM+3*l.XS, l.YM - s.talon = WasteTalonStack(x, y, self, max_rounds=1) - l.createText(s.talon, 'sw') - x += l.XS - s.waste = WasteStack(x, y, self) - l.createText(s.waste, 'se') - - l.defaultStackGroups() - - - def startGame(self): - self.startDealSample() - # 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() - - - shallHighlightMatch = Game._shallHighlightMatch_ACW - - - 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) - - # /*********************************************************************** # // Sixes and Sevens # ************************************************************************/ @@ -997,8 +928,6 @@ registerGame(GameInfo(424, Matrimony, "Matrimony", GI.GT_2DECK_TYPE, 2, 16, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(429, Patriarchs, "Patriarchs", GI.GT_2DECK_TYPE, 2, 1, GI.SL_MOSTLY_LUCK)) -registerGame(GameInfo(437, Simplicity, "Simplicity", - GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(438, SixesAndSevens, "Sixes and Sevens", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(477, CornerSuite, "Corner Suite", diff --git a/pysollib/games/takeaway.py b/pysollib/games/takeaway.py index 1acdc3fc..c9773c14 100644 --- a/pysollib/games/takeaway.py +++ b/pysollib/games/takeaway.py @@ -108,12 +108,95 @@ class FourStacks(TakeAway): shallHighlightMatch = Game._shallHighlightMatch_AC +# /*********************************************************************** +# // Striptease +# ************************************************************************/ + +class Striptease_RowStack(UD_RK_RowStack): + def acceptsCards(self, from_stack, cards): + if not self.basicAcceptsCards(from_stack, cards): + return False + if not self.cards: + return True + r1, r2 = self.cards[-1].rank, cards[0].rank + if ((r1 == JACK and r2 == KING) or + (r2 == JACK and r1 == KING)): + return True + return ((r1+1) % 13 == r2 or (r2+1) % 13 == r1) + def getBottomImage(self): + return self.game.app.images.getReserveBottom() + + +class Striptease_Reserve(OpenStack): + def canFlipCard(self): + if not OpenStack.canFlipCard(self): + return False + for r in self.game.s.reserves: + if len(r.cards) > 2: + return False + return True + + +class Striptease(TakeAway): + + def createGame(self): + l, s = Layout(self), self.s + w, h = l.XM+9*l.XS, l.YM+l.YS+16*l.YOFFSET + self.setSize(w, h) + + x, y = l.XM, l.YM + for i in range(4): + stack = Striptease_Reserve(x, y, self, max_move=1, + min_cards=1, max_accept=0) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, l.YOFFSET + s.reserves.append(stack) + x += l.XS + x += l.XS + for i in range(4): + stack = Striptease_RowStack(x, y, self, max_move=0) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, l.YOFFSET + s.rows.append(stack) + x += l.XS + s.talon = InitialDealTalonStack(w-l.XS, h-l.YS, self) + + l.defaultAll() + + def _shuffleHook(self, cards): + return self._shuffleHookMoveToTop(cards, + lambda c: (c.rank == QUEEN, None)) + + def startGame(self): + self.s.talon.dealRow(rows=self.s.reserves, frames=0) + self.s.talon.dealRow(rows=self.s.reserves, flip=0, frames=0) + for i in range(8): + self.s.talon.dealRow(rows=self.s.reserves, frames=0) + self.startDealSample() + for i in range(3): + self.s.talon.dealRow(rows=self.s.reserves) + + def isGameWon(self): + for r in self.s.reserves: + if len(r.cards) != 1: + return False + return True + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + r1, r2 = card1.rank, card2.rank + if r1 == QUEEN or r2 == QUEEN: + return False + if ((r1 == JACK and r2 == KING) or + (r2 == JACK and r1 == KING)): + return True + return ((r1+1) % 13 == r2 or (r2+1) % 13 == r1) + # register the game registerGame(GameInfo(334, TakeAway, "Take Away", GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(335, FourStacks, "Four Stacks", GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(654, Striptease, "Striptease", + GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/windmill.py b/pysollib/games/windmill.py index 4588b398..5a78cab3 100644 --- a/pysollib/games/windmill.py +++ b/pysollib/games/windmill.py @@ -376,17 +376,92 @@ class FourSeasons(Czarina): pass +# /*********************************************************************** +# // Simplicity +# ************************************************************************/ + +class Simplicity(Game): + Hint_Class = CautiousDefaultHint + + def createGame(self, max_rounds=2): + + l, s = Layout(self), self.s + self.setSize(l.XM+8*l.XS, l.YM+4*l.YS) + + self.base_card = None + + i = 0 + for x, y in ((l.XM, l.YM), + (l.XM+7*l.XS, l.YM), + (l.XM, l.YM+3*l.YS), + (l.XM+7*l.XS, l.YM+3*l.YS), + ): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i, mod=13)) + i += 1 + y = l.YM+l.YS + for i in range(2): + x = l.XM+l.XS + for j in range(6): + stack = AC_RowStack(x, y, self, max_move=1, mod=13) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 + s.rows.append(stack) + x += l.XS + y += l.YS + x, y = l.XM+3*l.XS, l.YM + s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 'sw') + x += l.XS + s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'se') + + l.defaultStackGroups() + + + def startGame(self): + self.startDealSample() + # 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() + + + shallHighlightMatch = Game._shallHighlightMatch_ACW + + + 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) + + # register the game registerGame(GameInfo(30, Windmill, "Windmill", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(277, NapoleonsTomb, "Napoleon's Tomb", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(417, Corners, "Corners", - GI.GT_1DECK_TYPE, 1, 2, GI.SL_MOSTLY_LUCK)) + GI.GT_1DECK_TYPE, 1, 2, GI.SL_MOSTLY_LUCK, + rules_filename='fourseasons.html')) +registerGame(GameInfo(437, Simplicity, "Simplicity", + GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK, + rules_filename='fourseasons.html')) registerGame(GameInfo(483, Czarina, "Czarina", - GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) + GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK, + rules_filename='fourseasons.html')) registerGame(GameInfo(484, FourSeasons, "Four Seasons", - GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) + GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK, + altnames=('Corner Card', 'Vanishing Cross') )) registerGame(GameInfo(561, DutchSolitaire, "Dutch Solitaire", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/stack.py b/pysollib/stack.py index 031f6574..dabb02c6 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -1422,11 +1422,7 @@ class DealBaseCard_StackMethods: class RedealCards_StackMethods: - def redealCards(self, rows=None, sound=0, - shuffle=False, reverse=False, frames=0): - if sound and self.game.app.opt.animations: - self.game.startDealSample() - lr = len(self.game.s.rows) + def _redeal(self, rows=None, reverse=False, frames=0): # move all cards to the Talon num_cards = 0 assert len(self.cards) == 0 @@ -1438,10 +1434,17 @@ class RedealCards_StackMethods: for r in rows: for i in range(len(r.cards)): num_cards += 1 - self.game.moveMove(1, r, self, frames=frames) + self.game.moveMove(1, r, self, frames=frames, shadow=0) if self.cards[-1].face_up: self.game.flipMove(self) assert len(self.cards) == num_cards + return num_cards + + def redealCards(self, rows=None, sound=0, + shuffle=False, reverse=False, frames=0): + if sound and self.game.app.opt.animations: + self.game.startDealSample() + num_cards = self._redeal(rows=rows, reverse=reverse, frames=frames) if num_cards == 0: # game already finished return 0 if shuffle: