class Scuffle(AuldLangSyne): Talon_Class = StackWrapper(Scuffle_Talon, max_rounds=3) def createGame(self): AuldLangSyne.createGame(self, texts=True, yoffset=0)
class Fortunes(AcesUp): RowStack_Class = StackWrapper(AcesUp_RowStack, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS)
class ExiledKings(Citadel): Hint_Class = BeleagueredCastleType_Hint Solver_Class = FreeCellSolverWrapper(sbb='rank', esf='kings') RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING)
class Hiranyaksha(AbstractDashavataraGame): RowStack_Class = StackWrapper(Dashavatara_RK_RowStack, base_rank=NO_RANK) # # game layout # def createGame(self, rows=11, reserves=10): # create layout l, s = Layout(self), self.s # set size maxrows = max(rows, reserves) self.setSize(l.XM + (maxrows + 2) * l.XS, l.YM + 6 * l.YS) # playcards = 4 * l.YS // l.YOFFSET xoffset, yoffset = [], [] for i in range(playcards): xoffset.append(0) yoffset.append(l.YOFFSET) for i in range(96 * self.gameinfo.decks - playcards): xoffset.append(l.XOFFSET) yoffset.append(0) # create stacks x, y = l.XM + (maxrows - reserves) * l.XS // 2, l.YM for i in range(reserves): s.reserves.append(ReserveStack(x, y, self)) x = x + l.XS x, y = l.XM + (maxrows - rows) * l.XS // 2, l.YM + l.YS self.setRegion(s.reserves, (-999, -999, 999999, y - l.YM // 2)) for i in range(rows): stack = self.RowStack_Class(x, y, self, yoffset=l.YOFFSET) stack.CARD_XOFFSET = xoffset stack.CARD_YOFFSET = yoffset s.rows.append(stack) x = x + l.XS x, y = l.XM + maxrows * l.XS, l.YM for i in range(2): for suit in range(5): s.foundations.append( SS_FoundationStack(x, y, self, suit=suit + (5 * i))) y = y + l.YS x, y = x + l.XS, l.YM self.setRegion(self.s.foundations, (x - l.XS * 2, -999, 999999, self.height - (l.YS + l.YM)), priority=1) s.talon = InitialDealTalonStack(self.width - 3 * l.XS // 2, self.height - l.YS, self) # define stack-groups l.defaultStackGroups() # # game overrides # def startGame(self): self.startDealSample() i = 0 while self.s.talon.cards: if self.s.talon.cards[-1].rank == 11: if self.s.rows[i].cards: i = i + 1 self.s.talon.dealRow(rows=[self.s.rows[i]], frames=4) # must look at cards def _getClosestStack(self, cx, cy, stacks, dragstack): closest, cdist = None, 999999999 for stack in stacks: if stack.cards and stack is not dragstack: dist = (stack.cards[-1].x - cx)**2 + \ (stack.cards[-1].y - cy)**2 else: dist = (stack.x - cx)**2 + (stack.y - cy)**2 if dist < cdist: closest, cdist = stack, dist return closest def shallHighlightMatch(self, stack1, card1, stack2, card2): row = self.s.rows[0] sequence = row.isRankSequence return (sequence([card1, card2]) or sequence([card2, card1]))
class Shifting(Numerica): Hint_Class = Shifting_Hint RowStack_Class = StackWrapper(Shifting_RowStack, max_accept=1)
class Camelot(Game): Talon_Class = Camelot_Talon RowStack_Class = StackWrapper(Camelot_RowStack, max_move=0) Hint_Class = Camelot_Hint # game variables is_fill = False # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window w = l.XS self.setSize(l.XM + w + 4*l.XS + w + l.XS, l.YM + 4*l.YS) # create stacks stackNum = 0 font = self.app.getFont("canvas_default") for i in range(4): for j in range(4): x, y = l.XM + w + j*l.XS, l.YM + i*l.YS stack = self.RowStack_Class(x, y, self) if self.preview <= 1: stack.texts.misc = MfxCanvasText(self.canvas, x + l.CW // 2, y + l.CH // 2, anchor="center", font=font) if stackNum in (0, 3, 12, 15): stack.texts.misc.config(text="K") elif stackNum in (1, 2, 13, 14): stack.texts.misc.config(text="Q") elif stackNum in (4, 7, 8, 11): stack.texts.misc.config(text="J") s.rows.append(stack) stackNum += 1 x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, 's') x, y = l.XM + w + 4*l.XS + w, l.YM s.foundations.append(Camelot_Foundation(x, y, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_accept=0, max_move=0, max_cards=52)) l.createText(s.foundations[0], 's') # define stack-groups l.defaultStackGroups() return l # # game overrides # def startGame(self): self.is_fill = False self.s.talon.fillStack() def isGameWon(self): for i in (5, 6, 9, 10): if len(self.s.rows[i].cards) != 0: return False return len(self.s.talon.cards) == 0 def isRowsFill(self): if len(self.s.talon.cards) == 0: return True for i in range(16): if len(self.s.rows[i].cards) == 0: return False return True def _restoreGameHook(self, game): self.is_fill = game.loadinfo.is_fill def _loadGameHook(self, p): self.loadinfo.addattr(is_fill=p.load()) def _saveGameHook(self, p): p.dump(self.is_fill) def getAutoStacks(self, event=None): return ((), (), ()) def setState(self, state): # restore saved vars (from undo/redo) self.is_fill = state[0] def getState(self): # save vars (for undo/redo) return [self.is_fill]
class Alhambra(Game): Hint_Class = Alhambra_Hint RowStack_Class = StackWrapper(Alhambra_RowStack, base_rank=ANY_RANK) def createGame(self, rows=1, reserves=8, playcards=3): # create layout l, s = Layout(self), self.s # set window w, h = l.XM + 8 * l.XS, l.YM + 3.5 * l.YS + playcards * l.YOFFSET h += l.TEXT_HEIGHT self.setSize(w, h) # create stacks x, y, = l.XM, l.YM for i in range(4): s.foundations.append( SS_FoundationStack(x, y, self, suit=i, max_move=0)) x += l.XS for i in range(4): s.foundations.append( SS_FoundationStack(x, y, self, suit=i, max_move=0, base_rank=KING, dir=-1)) x += l.XS x, y, = l.XM + (8 - reserves) * l.XS // 2, y + l.YS for i in range(reserves): stack = OpenStack(x, y, self, max_accept=0) stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, l.YOFFSET s.reserves.append(stack) x += l.XS x, y = l.XM + (8 - 1 - rows) * l.XS // 2, self.height - l.YS s.talon = Alhambra_Talon(x, y, self, max_rounds=3) if rows == 1: l.createText(s.talon, 'sw') else: l.createText(s.talon, 'n') anchor = 'nn' if rows > 1: anchor = 'nnn' l.createRoundText(s.talon, anchor) x += l.XS for i in range(rows): stack = self.RowStack_Class(x, y, self, mod=13, max_accept=1) stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 s.rows.append(stack) x += l.XS if rows == 1: l.createText(stack, 'se') else: l.createText(stack, 'n') # define stack-groups (non default) l.defaultStackGroups() # # game overrides # def _shuffleHook(self, cards): # move one Aces and Kings of first deck to top of the Talon (i.e. first # card to be dealt) return self._shuffleHookMoveToTop( cards, lambda c: (c.deck == 0 and c.rank in (ACE, KING), (c.rank, c.suit)), 8) def startGame(self): self.s.talon.dealRow(rows=self.s.foundations, frames=0) for i in range(3): self.s.talon.dealRow(rows=self.s.reserves, frames=0) self.startDealSample() self.s.talon.dealRow(rows=self.s.reserves) self.s.talon.dealCards() shallHighlightMatch = Game._shallHighlightMatch_SSW
class ThreePeaks(Game): Waste_Class = StackWrapper(Golf_Waste, mod=13) Hint_Class = Golf_Hint SCORING = 1 # # Game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window # compute best XOFFSET xoffset = int(l.XS * 8 / self.gameinfo.ncards) if xoffset < l.XOFFSET: l.XOFFSET = xoffset # Set window size w, h = l.XM + l.XS * 10, l.YM + l.YS * 4 self.setSize(w, h) # Extra settings self.game_score = 0 self.hand_score = self.sequence = 0 self.score_counted = False self.peaks = [0] * 3 # Create rows x, y = l.XM + l.XS * 1.5, l.YM for i in range(3): s.rows.append(ThreePeaks_RowStack(x, y, self)) x = x + l.XS * 3 x, y = l.XM + l.XS, y + l.YS * .5 for i in range(3): s.rows.append(ThreePeaks_RowStack(x, y, self)) x = x + l.XS s.rows.append(ThreePeaks_RowStack(x, y, self)) x = x + l.XS * 2 x, y = l.XM + l.XS * .5, y + l.YS * .5 for i in range(9): s.rows.append(ThreePeaks_RowStack(x, y, self)) x = x + l.XS x, y = l.XM, y + l.YS * .5 for i in range(10): s.rows.append(ThreePeaks_RowStack(x, y, self)) x = x + l.XS # Create talon x, y = l.XM, y + l.YM + l.YS s.talon = ThreePeaks_TalonStack(x, y, self, num_deal=1, max_rounds=1) l.createText(s.talon, "s") x = x + l.XS s.waste = self.Waste_Class(x, y, self) s.waste.CARD_XOFFSET = l.XOFFSET s.foundations.append(s.waste) l.createText(s.waste, "s") # Create text for scores if self.preview <= 1: self.texts.info = MfxCanvasText( self.canvas, l.XM + l.XS * 3, h - l.YM, anchor="sw", font=self.app.getFont("canvas_default")) # Define stack groups l.defaultStackGroups() # # Game over rides # def startGame(self): assert len(self.s.talon.cards) == self.gameinfo.ncards self.game_score = self.game_score + self.hand_score self.hand_score = -52 self.peaks = [0] * 3 self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:18], flip=0, frames=4) self.s.talon.dealRow(rows=self.s.rows[18:], flip=1, frames=4) self.s.talon.dealCards() def isGameWon(self): for r in self.s.rows: if r.cards: return False if self.sequence: self.hand_score = self.hand_score + len(self.s.talon.cards) * 10 self.computeHandScore() self.score_counted = True self.updateText() self.sequence = 0 return True def updateText(self): if self.preview > 1 or not self.texts.info or not self.SCORING: return t = _('Score:\011This hand: ') + str(self.hand_score) t = t + _('\011This game: ') + str(self.game_score) self.texts.info.config(text=t) def shallHighlightMatch(self, stack1, card1, stack2, card2): if stack1 == self.s.waste or stack2 == self.s.waste: return ((card1.rank + 1) % 13 == card2.rank or (card1.rank - 1) % 13 == card2.rank) return False def computeHandScore(self): score, i = self.hand_score, 1 # First count the empty peaks for r in self.s.rows[:3]: if not r.cards: i = i * 2 # Now give credit for newly emptied peaks for r in self.s.rows[:3]: if not r.cards and not self.peaks[r.id]: score, self.peaks[r.id] = score + 5 * i, 1 # Now give credit for the sequence length if self.sequence and len(self.s.waste.cards) - 1: score = score + i * 2**int((self.sequence - 1) / 4) self.hand_score = score # print 'getHandScore: score:', score def canUndo(self): return False def _restoreGameHook(self, game): self.game_score = game.loadinfo.game_score self.hand_score = game.loadinfo.hand_score self.sequence = game.loadinfo.sequence self.peaks = game.loadinfo.peaks def _loadGameHook(self, p): self.loadinfo.addattr(game_score=0) self.loadinfo.game_score = p.load() self.loadinfo.addattr(hand_score=0) self.loadinfo.hand_score = p.load() self.loadinfo.addattr(sequence=0) self.loadinfo.sequence = p.load() self.loadinfo.addattr(peaks=[0] * 3) self.loadinfo.peaks = p.load() def _saveGameHook(self, p): p.dump(self.game_score) p.dump(self.hand_score) p.dump(self.sequence) p.dump(self.peaks)
class ChineseKlondike(DoubleKlondike): RowStack_Class = StackWrapper(BO_RowStack, base_rank=KING) def createGame(self): DoubleKlondike.createGame(self, rows=12)
class SuperFlowerGarden(LaBelleLucie): RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK) shallHighlightMatch = Game._shallHighlightMatch_RK
class HouseOnTheHill(HouseInTheWood): Foundation_Classes = [ SS_FoundationStack, StackWrapper(SS_FoundationStack, base_rank=KING, dir=-1) ]
class LaBelleLucie(Fan): Talon_Class = StackWrapper(LaBelleLucie_Talon, max_rounds=3) RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK) def createGame(self): return Fan.createGame(self, texts=True)
class DoubleAcquaintance(AuldLangSyne): Talon_Class = StackWrapper(Acquaintance_Talon, max_rounds=3) def createGame(self): AuldLangSyne.createGame(self, rows=8, texts=True)
class Acquaintance(AuldLangSyne): Talon_Class = StackWrapper(Acquaintance_Talon, max_rounds=3) def createGame(self, texts=False, yoffset=None): AuldLangSyne.createGame(self, texts=True)
class PokerSquareWaste(PokerSquare): NUM_RESERVE = 1 RESERVE_STACK = StackWrapper(ReserveStack, max_cards=5, max_move=0)
class DoubleKingsley(DoubleKlondike): Foundation_Class = StackWrapper(SS_FoundationStack, base_rank=KING, dir=-1) RowStack_Class = StackWrapper(KingAC_RowStack, base_rank=ACE, dir=1) def createGame(self): DoubleKlondike.createGame(self, max_rounds=1)
class PokerSquare(Game): Talon_Class = OpenTalonStack RowStack_Class = StackWrapper(PokerSquare_RowStack, max_move=0) Hint_Class = None WIN_SCORE = 100 NUM_RESERVE = 0 RESERVE_STACK = StackWrapper(ReserveStack, max_cards=5) # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # create texts 1) ta = "ss" x, y = l.XM, l.YM + 2*l.YS if self.preview <= 1: t = MfxCanvasText(self.canvas, x, y, anchor="nw", font=self.app.getFont("canvas_default"), text=_('''\ Royal Flush Straight Flush 4 of a Kind Full House Flush Straight 3 of a Kind Two Pair One Pair''')) self.texts.list.append(t) bb = t.bbox() x = bb[1][0] + l.CW * 1.3 h = bb[1][1] - bb[0][1] if h >= 2*l.YS: ta = "e" t.move(0, -l.YS) y = y - l.YS t = MfxCanvasText(self.canvas, x, y, anchor="nw", font=self.app.getFont("canvas_default"), text="100\n75\n50\n25\n20\n15\n10\n5\n2") self.texts.list.append(t) x = t.bbox()[1][0] + l.CW * .6 self.texts.misc = MfxCanvasText( self.canvas, x, y, anchor="nw", font=self.app.getFont("canvas_default"), text="0\n"*8+"0") x = self.texts.misc.bbox()[1][0] + 32 # set window w = max(2 * l.XS, x, ((self.NUM_RESERVE + 1) * l.XS) + (4 * l.XM)) self.setSize(l.XM + w + 5 * l.XS + 50, l.YM + 5 * l.YS + 30) # create stacks for i in range(5): for j in range(5): x, y = l.XM + w + j*l.XS, l.YM + i*l.YS s.rows.append(self.RowStack_Class(x, y, self)) x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, anchor=ta) s.internals.append(InvisibleStack(self)) # for _swapPairMove() for i in range(self.NUM_RESERVE): x, y = ((i + 1) * l.XS) + (2 * l.XM), l.YM s.reserves.append(self.RESERVE_STACK(x, y, self)) # create texts 2) if self.preview <= 1: for i in (4, 9, 14, 19, 24): tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="e") t = MfxCanvasText(self.canvas, tx+8, ty, anchor=ta, font=self.app.getFont("canvas_default")) self.texts.list.append(t) for i in range(20, 25): tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="ss") t = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=self.app.getFont("canvas_default")) self.texts.list.append(t) self.texts.score = MfxCanvasText( self.canvas, l.XM, 5*l.YS, anchor="sw", font=self.app.getFont("canvas_large")) # define hands for scoring r = s.rows self.poker_hands = [ r[0:5], r[5:10], r[10:15], r[15:20], r[20:25], (r[0], r[0+5], r[0+10], r[0+15], r[0+20]), (r[1], r[1+5], r[1+10], r[1+15], r[1+20]), (r[2], r[2+5], r[2+10], r[2+15], r[2+20]), (r[3], r[3+5], r[3+10], r[3+15], r[3+20]), (r[4], r[4+5], r[4+10], r[4+15], r[4+20]), ] self.poker_hands = list(map(tuple, self.poker_hands)) # define stack-groups l.defaultStackGroups() return l # # game overrides # def startGame(self): self.moveMove(27 - (5 * self.NUM_RESERVE), self.s.talon, self.s.internals[0], frames=0) self.s.talon.fillStack() def isBoardFull(self): for i in range(25): if len(self.s.rows[i].cards) == 0: return False return True def isGameWon(self): if self.isBoardFull(): return self.getGameScore() >= self.WIN_SCORE return False def getAutoStacks(self, event=None): return ((), (), ()) # # scoring # def updateText(self): if self.preview > 1: return score = 0 count = [0] * 9 for i in range(10): type, value = self.getHandScore(self.poker_hands[i]) if 0 <= type <= 8: count[type] += 1 self.texts.list[i+2].config(text=str(value)) score += value t = '\n'.join(map(str, count)) self.texts.misc.config(text=t) # t = "" if score >= self.WIN_SCORE: t = _("WON\n\n") if not self.isBoardFull(): t += _("Points: %d") % score else: t += _("Total: %d") % score self.texts.score.config(text=t) def getGameScore(self): score = 0 for hand in self.poker_hands: type, value = self.getHandScore(hand) score = score + value return score def getHandScore(self, hand): same_rank = [0] * 13 same_suit = [0] * 4 ranks = [] for s in hand: if s.cards: rank, suit = s.cards[0].rank, s.cards[0].suit same_rank[rank] = same_rank[rank] + 1 same_suit[suit] = same_suit[suit] + 1 ranks.append(rank) # straight = 0 if same_rank.count(1) == 5: d = max(ranks) - min(ranks) if d == 4: straight = 1 # normal straight elif d == 12 and same_rank[-4:].count(1) == 4: straight = 2 # straight with Ace ranked high # if max(same_suit) == 5: if straight: if straight == 2: return 0, 100 # Royal Flush return 1, 75 # Straight Flush return 4, 20 # Flush # if straight: return 5, 15 # Straight # if max(same_rank) >= 2: same_rank.sort() if same_rank[-1] == 4: return 2, 50 # Four of a Kind if same_rank[-1] == 3: if same_rank[-2] == 2: return 3, 25 # Full House return 6, 10 # Three of a Kind if same_rank[-2] == 2: return 7, 5 # Two Pairs return 8, 2 # Pair # return -1, 0
class Canfield(Game): Talon_Class = WasteTalonStack Foundation_Class = SS_FoundationStack RowStack_Class = StackWrapper(Canfield_AC_RowStack, mod=13) ReserveStack_Class = OpenStack Hint_Class = Canfield_Hint INITIAL_RESERVE_CARDS = 13 INITIAL_RESERVE_FACEUP = 0 FILL_EMPTY_ROWS = 1 SEPARATE_FOUNDATIONS = True # # game layout # def createGame(self, rows=4, max_rounds=-1, num_deal=3, text=True, round_text=False, dir=-1): # create layout lay, s = Layout(self), self.s decks = self.gameinfo.decks # set window if self.INITIAL_RESERVE_FACEUP == 1: yoffset = lay.YOFFSET # min(lay.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 * lay.YS, lay.YS + self.INITIAL_RESERVE_CARDS * yoffset) if round_text: h += lay.TEXT_HEIGHT self.setSize(lay.XM + (2 + max(rows, 4 * decks)) * lay.XS + lay.XM, lay.YM + lay.YS + lay.TEXT_HEIGHT + h) # extra settings self.base_card = None # create stacks x, y = lay.XM, lay.YM s.talon = self.Talon_Class(x, y, self, max_rounds=max_rounds, num_deal=num_deal) lay.createText(s.talon, "s") if round_text: lay.createRoundText(s.talon, 'sss') x += lay.XS s.waste = WasteStack(x, y, self) lay.createText(s.waste, "s") x += lay.XM y = lay.YM if (self.SEPARATE_FOUNDATIONS): for i in range(4): for j in range(decks): x += lay.XS s.foundations.append( self.Foundation_Class(x, y, self, i, mod=13, max_move=0)) else: x += (lay.XS * rows) s.foundations.append(self.Foundation_Class(x, y, self, -1)) if text: if rows > 4 * decks: tx, ty, ta, tf = lay.getTextAttr(None, "se") tx, ty = x + tx + lay.XM, y + ty else: tx, ty, ta, tf = lay.getTextAttr(None, "s") tx, ty = x + tx, y + ty font = self.app.getFont("canvas_default") self.texts.info = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) x, y = lay.XM, lay.YM + lay.YS + lay.TEXT_HEIGHT if round_text: y += lay.TEXT_HEIGHT s.reserves.append(self.ReserveStack_Class(x, y, self)) s.reserves[0].CARD_YOFFSET = yoffset x, y = lay.XM + 2 * lay.XS + lay.XM, lay.YM + lay.YS if text: y += lay.TEXT_HEIGHT for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self, dir=dir)) x += lay.XS # define stack-groups lay.defaultStackGroups() # # game extras # def updateText(self): if self.preview > 1: return if not self.texts.info: return if not self.base_card: t = "" else: t = RANKS[self.base_card.rank] self.texts.info.config(text=t) # # game overrides # def startGame(self): self.startDealSample() self.base_card = None self.updateText() if (self.SEPARATE_FOUNDATIONS): # 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.gameinfo.decks if self.s.foundations[n].cards: assert self.gameinfo.decks > 1 n = n + 1 self.flipMove(self.s.talon) self.moveMove(1, self.s.talon, self.s.foundations[n]) self.updateText() # fill the Reserve for i in range(self.INITIAL_RESERVE_CARDS): if self.INITIAL_RESERVE_FACEUP: self.flipMove(self.s.talon) self.moveMove(1, self.s.talon, self.s.reserves[0], frames=4, shadow=0) if self.s.reserves[0].canFlipCard(): self.flipMove(self.s.reserves[0]) self.s.talon.dealRow(reverse=1) self.s.talon.dealCards() # deal first 3 cards to WasteStack def fillStack(self, stack): if stack in self.s.rows and self.s.reserves: if self.FILL_EMPTY_ROWS: if not stack.cards and self.s.reserves[0].cards: if not self.s.reserves[0].cards[-1].face_up: self.s.reserves[0].flipMove() self.s.reserves[0].moveMove(1, stack) 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)
class PictureGallery(Game): Hint_Class = PictureGallery_Hint Foundation_Class = PictureGallery_Foundation TableauStack_Classes = [ StackWrapper( PictureGallery_TableauStack, base_rank=3, max_cards=4, dir=3), StackWrapper( PictureGallery_TableauStack, base_rank=2, max_cards=4, dir=3), StackWrapper( PictureGallery_TableauStack, base_rank=1, max_cards=4, dir=3), ] RowStack_Class = StackWrapper(PictureGallery_RowStack, max_accept=1) Talon_Class = DealRowTalonStack # # game layout # def createGame(self, waste=False, numstacks=8): rows = len(self.TableauStack_Classes) # create layout l, s = Layout(self), self.s numtableau = (4 * self.gameinfo.decks) TABLEAU_YOFFSET = min(numtableau + 1, max(3, l.YOFFSET // 3)) # set window th = l.YS + ((numtableau + 4) // rows - 1) * TABLEAU_YOFFSET # (set piles so that at least 2/3 of a card is visible with 10 cards) h = ((numtableau + 2) - 1) * l.YOFFSET + l.CH * 2 // 3 self.setSize((numtableau + 2) * l.XS + l.XM, l.YM + 3 * th + l.YM + h) # create stacks s.addattr(tableaux=[]) # register extra stack variable x = l.XM + numtableau * l.XS + l.XS // 2 y = l.YM + l.CH // 2 s.foundations.append(self.Foundation_Class(x, y, self)) y = l.YM for cl in self.TableauStack_Classes: x = l.XM for j in range(numtableau): s.tableaux.append(cl(x, y, self, yoffset=TABLEAU_YOFFSET)) x = x + l.XS y = y + th x, y = l.XM, y + l.YM for i in range(numstacks): s.rows.append(self.RowStack_Class(x, y, self)) x = x + l.XS # self.setRegion(s.rows, (-999, -999, x - l.CW // 2, 999999)) x = l.XM + numstacks * l.XS + l.XS // 2 y = self.height - l.YS s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, "se") if waste: y -= l.YS s.waste = WasteStack(x, y, self) l.createText(s.waste, "se") self.setRegion(s.foundations, (x - l.CW // 2, -999, 999999, y - l.CH)) # define stack-groups if waste: ws = [s.waste] else: ws = [] self.sg.openstacks = s.foundations + s.tableaux + s.rows + ws self.sg.talonstacks = [s.talon] + ws self.sg.dropstacks = s.tableaux + s.rows + ws # # game overrides # def startGame(self): self.s.talon.dealRow(rows=self.s.tableaux, frames=0) self._startAndDealRow() def isGameWon(self): if len(self.s.foundations[0].cards) != (4 * self.gameinfo.decks): return False for stack in self.s.tableaux: if len(stack.cards) != 4: return False return True def fillStack(self, stack): if self.s.talon.cards: if stack in self.s.rows and len(stack.cards) == 0: self.s.talon.dealRow(rows=[stack]) def shallHighlightMatch(self, stack1, card1, stack2, card2): if card1.rank == ACE or card2.rank == ACE: return False return (card1.suit == card2.suit and (card1.rank + 3 == card2.rank or card2.rank + 3 == card1.rank)) def getHighlightPilesStacks(self): return ()
class CribbageSquareWaste(CribbageSquare): NUM_RESERVE = 1 RESERVE_STACK = StackWrapper(ReserveStack, max_cards=5, max_move=0)
class NewBritishConstitution(BritishConstitution): RowStack_Class = StackWrapper(NewBritishConstitution_RowStack, base_rank=JACK) shallHighlightMatch = Game._shallHighlightMatch_RK
class CribbageSquare(Game): Talon_Class = CribbageSquare_Talon RowStack_Class = StackWrapper(CribbageSquare_RowStack, max_move=0) Hint_Class = None WIN_SCORE = 61 NUM_RESERVE = 0 RESERVE_STACK = StackWrapper(ReserveStack, max_cards=5) # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # create texts 1) ta = "ss" x, y = l.XM, l.YM + 2 * l.YS # set window w = max(2 * l.XS, x, ((self.NUM_RESERVE + 1) * l.XS) + (4 * l.XM)) self.setSize(l.XM + w + 4 * l.XS + 50, l.YM + 4 * l.YS + 30) # create stacks for i in range(4): for j in range(4): x, y = l.XM + w + j * l.XS, l.YM + i * l.YS s.rows.append(self.RowStack_Class(x, y, self)) x, y = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, anchor=ta) s.internals.append(InvisibleStack(self)) # for _swapPairMove() for i in range(self.NUM_RESERVE): x, y = ((i + 1) * l.XS) + (2 * l.XM), l.YM s.reserves.append(self.RESERVE_STACK(x, y, self)) # create texts 2) if self.preview <= 1: for i in (3, 7, 11, 15): tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="e") t = MfxCanvasText(self.canvas, tx + 8, ty, anchor=ta, font=self.app.getFont("canvas_default")) self.texts.list.append(t) for i in range(12, 16): tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="ss") t = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=self.app.getFont("canvas_default")) self.texts.list.append(t) self.texts.score = MfxCanvasText( self.canvas, l.XM, 4 * l.YS, anchor="sw", font=self.app.getFont("canvas_large")) # define hands for scoring r = s.rows self.cribbage_hands = [ r[0:4], r[4:8], r[8:12], r[12:16], (r[0], r[0 + 4], r[0 + 8], r[0 + 12]), (r[1], r[1 + 4], r[1 + 8], r[1 + 12]), (r[2], r[2 + 4], r[2 + 8], r[2 + 12]), (r[3], r[3 + 4], r[3 + 8], r[3 + 12]) ] self.cribbage_hands = list(map(tuple, self.cribbage_hands)) # define stack-groups l.defaultStackGroups() return l # # game overrides # def startGame(self): self.moveMove(35 - (5 * self.NUM_RESERVE), self.s.talon, self.s.internals[0], frames=0) self.s.talon.fillStack() def isBoardFull(self): for i in range(16): if len(self.s.rows[i].cards) == 0: return False return True def isGameWon(self): if self.isBoardFull(): return self.getGameScore() >= self.WIN_SCORE return False def getAutoStacks(self, event=None): return ((), (), ()) # # scoring # def updateText(self): if self.preview > 1: return score = 0 for i in range(8): value = self.getHandScore(self.cribbage_hands[i]) self.texts.list[i].config(text=str(value)) score += value # score = self.checkHisHeels(score) t = "" if score >= self.WIN_SCORE: t = _("WON\n\n") if not self.isBoardFull(): t += _("Points: %d") % score else: t += _("Total: %d") % score self.texts.score.config(text=t) def getGameScore(self): score = 0 for hand in self.cribbage_hands: value = self.getHandScore(hand) score += value score = self.checkHisHeels(score) return score def getAllCombinations(self, hand): if hand == (): return ((), ) x = self.getAllCombinations(hand[1:]) return x + tuple([(hand[0], ) + y for y in x]) def getHandScore(self, hand): same_suit = [0] * 4 hand_score = 0 upcard = None upcard_talon = None if self.isBoardFull(): upcard = self.s.talon.cards[0] upcard_talon = self.s.talon # First get flushes and his nobs, as these can only be # scored once per hand. for s in hand: if s.cards: suit = s.cards[0].suit same_suit[suit] = same_suit[suit] + 1 if upcard is not None and s.cards[0].rank == 10 \ and s.cards[0].suit == upcard.suit: hand_score += 1 # His nobs # if max(same_suit) == 4: hand_score += 4 # Flush if upcard is not None and upcard.suit == hand[0].cards[0].suit: hand_score += 1 # Flush of five if upcard is not None: hand = hand + (upcard_talon, ) combos = self.getAllCombinations(hand) longest_run = 3 run_score = 0 # The remaining hands can be scored for every combination. for c in combos: c_same_rank = [0] * 13 c_ranks = [] total = 0 incomplete = False for s in c: if s.cards: rank = s.cards[0].rank c_same_rank[rank] = c_same_rank[rank] + 1 c_ranks.append(rank) if rank < 10: total += (rank + 1) else: total += 10 else: incomplete = True break if incomplete: continue if total == 15: hand_score += 2 # Fifteen if len(c) == 2 and max(c_same_rank) == 2: hand_score += 2 # Pair # For runs, we only want to consider the longest run if len(c) >= longest_run: if c_same_rank.count(1) == len(c): d = max(c_ranks) - min(c_ranks) if d == len(c) - 1: if len(c) > longest_run: run_score = 0 longest_run = len(c) run_score += longest_run # Runs hand_score += run_score return hand_score def checkHisHeels(self, score): if self.isBoardFull() and self.s.talon.cards[0].rank == 10: return score + 2 return score
class Numerica(Game): Hint_Class = Numerica_Hint Foundation_Class = StackWrapper(RK_FoundationStack, suit=ANY_SUIT) RowStack_Class = StackWrapper(Numerica_RowStack, max_accept=1) # # game layout # def createGame(self, rows=4, reserve=False, max_rounds=1, waste_max_cards=1): # create layout l, s = Layout(self), self.s decks = self.gameinfo.decks foundations = 4*decks # set window # (piles up to 20 cards are playable in default window size) h = max(2*l.YS, 20*l.YOFFSET) max_rows = max(rows, foundations) self.setSize(l.XM+(1.5+max_rows)*l.XS+l.XM, l.YM + l.YS + h) # create stacks x0 = l.XM + l.XS * 3 / 2 if decks == 1: x = x0 + (rows-4)*l.XS/2 else: x = x0 y = l.YM for i in range(foundations): s.foundations.append(self.Foundation_Class(x, y, self, suit=i)) x = x + l.XS x, y = x0, l.YM + l.YS for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) x = x + l.XS self.setRegion(s.rows, (x0-l.XS/2, y-l.CH/2, 999999, 999999)) x, y = l.XM, l.YM+l.YS+l.YS/2*int(reserve) s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds) if reserve or waste_max_cards > 1: l.createText(s.talon, 'ne') else: l.createText(s.talon, 'n') y = y + l.YS s.waste = WasteStack(x, y, self, max_cards=waste_max_cards) if waste_max_cards > 1: l.createText(s.waste, 'ne') if reserve: s.reserves.append(self.ReserveStack_Class(l.XM, l.YM, self)) # define stack-groups l.defaultStackGroups() return l # # game overrides # def startGame(self): self.startDealSample() self.s.talon.dealCards() # deal first card to WasteStack shallHighlightMatch = Game._shallHighlightMatch_SS def getHighlightPilesStacks(self): return ()
class MonteCarlo(Game): Talon_Class = MonteCarlo_Talon Foundation_Class = StackWrapper(AbstractFoundationStack, max_accept=0) RowStack_Class = MonteCarlo_RowStack Hint_Class = MonteCarlo_Hint FILL_STACKS_AFTER_DROP = False # # game layout # def createGame(self, rows=5, cols=5): # create layout l, s = Layout(self), self.s # set window self.setSize(l.XM + (cols + 1.5) * l.XS, l.YM + rows * l.YS) # create stacks for i in range(rows): for j in range(cols): x, y = l.XM + j * l.XS, l.YM + i * l.YS s.rows.append( self.RowStack_Class(x, y, self, max_accept=1, max_cards=2, dir=0, base_rank=NO_RANK)) x, y = self.width - l.XS, l.YM s.foundations.append( self.Foundation_Class(x, y, self, suit=ANY_SUIT, max_move=0, base_rank=ANY_RANK, max_cards=self.gameinfo.ncards)) l.createText(s.foundations[0], "s") y += 2 * l.YS s.talon = self.Talon_Class(x, y, self, max_rounds=1) l.createText(s.talon, "s", text_format="%D") # define stack-groups l.defaultStackGroups() # # game overrides # def startGame(self): self.startDealSample() self.s.talon.dealRow() def getAutoStacks(self, event=None): return ((), (), self.sg.dropstacks) def shallHighlightMatch(self, stack1, card1, stack2, card2): return card1.rank == card2.rank # # game extras # def isNeighbour(self, stack1, stack2): if not (0 <= stack1.id <= 24 and 0 <= stack2.id <= 24): return False column = stack2.id % 5 diff = stack1.id - stack2.id if column == 0: return diff in (-5, -4, 1, 5, 6) elif column == 4: return diff in (-6, -5, -1, 4, 5) else: return diff in (-6, -5, -4, -1, 1, 4, 5, 6) def fillEmptyStacks(self): free, n = 0, 0 self.startDealSample() for r in self.s.rows: assert len(r.cards) <= 1 if not r.cards: free += 1 elif free > 0: to_stack = self.allstacks[r.id - free] self.moveMove(1, r, to_stack, frames=4, shadow=0) if free > 0: for r in self.s.rows: if not r.cards: if not self.s.talon.cards: break self.flipMove(self.s.talon) self.moveMove(1, self.s.talon, r) n += 1 self.stopSamples() return n + free
class DoubleMeasure(Measure): Foundation_Class = StackWrapper(RK_FoundationStack, max_cards=104) def createGame(self, rows=8): Measure.createGame(self, rows=10)
class Fourteen(Game): Foundation_Class = StackWrapper(AbstractFoundationStack, max_accept=0) RowStack_Class = Fourteen_RowStack FILL_STACKS_AFTER_DROP = False # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window self.setSize(l.XM + 7 * l.XS, l.YM + 5 * l.YS) # create stacks for i in (0, 2.5): for j in range(6): x, y = l.XM + j * l.XS, l.YM + i * l.YS s.rows.append( self.RowStack_Class(x, y, self, max_move=1, max_accept=1, dir=0, base_rank=NO_RANK)) x, y = l.XM + 6 * l.XS, l.YM s.foundations.append( self.Foundation_Class(x, y, self, suit=ANY_SUIT, max_move=0, max_cards=52, base_rank=ANY_RANK)) l.createText(s.foundations[0], "s") x, y = self.width - l.XS, self.height - l.YS s.talon = InitialDealTalonStack(x, y, self) # define stack-groups l.defaultStackGroups() # # game overrides # def startGame(self): for i in range(3): self.s.talon.dealRow(frames=0) self.startDealSample() self.s.talon.dealRow() self.s.talon.dealRow(rows=self.s.rows[:4]) def getAutoStacks(self, event=None): return ((), (), self.sg.dropstacks) def shallHighlightMatch(self, stack1, card1, stack2, card2): return card1.rank + card2.rank == 12
class AcesUp(Game): Foundation_Class = AcesUp_Foundation Talon_Class = DealRowTalonStack RowStack_Class = StackWrapper(AcesUp_RowStack, max_accept=1) # # game layout # def createGame(self, rows=4, reserve=False, **layout): # create layout l, s = Layout(self), self.s # set window self.setSize(l.XM + (rows + 3) * l.XS, l.YM + 4 * l.YS) # create stacks x, y, = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) if reserve: l.createText(s.talon, "ne") else: l.createText(s.talon, "s") x = x + 3 * l.XS // 2 for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) x = x + l.XS x = x + l.XS // 2 stack = self.Foundation_Class(x, y, self, suit=ANY_SUIT, max_move=0, dir=0, base_rank=ANY_RANK, max_cards=48) l.createText(stack, "s") s.foundations.append(stack) if reserve: x, y = l.XM, l.YM + l.YS s.reserves.append(self.ReserveStack_Class(x, y, self)) # define stack-groups l.defaultStackGroups() # # game overrides # def startGame(self): self._startAndDealRow() def isGameWon(self): if len(self.s.foundations[0].cards) != 48: return False for s in self.s.rows: if len(s.cards) != 1 or s.cards[0].rank != ACE: return False return True def getAutoStacks(self, event=None): if event is None: # disable auto drop - this would ruin the whole gameplay return (self.sg.dropstacks, (), self.sg.dropstacks) else: # rightclickHandler return (self.sg.dropstacks, self.sg.dropstacks, self.sg.dropstacks)
class Nestor(Game): Foundation_Class = StackWrapper(AbstractFoundationStack, max_accept=0) RowStack_Class = Nestor_RowStack FILL_STACKS_AFTER_DROP = False # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window self.setSize(l.XM + 8 * l.XS, l.YM + 2 * l.YS + 12 * l.YOFFSET) # create stacks x, y = l.XM, l.YM for i in range(8): s.rows.append( self.RowStack_Class(x, y, self, max_move=1, max_accept=1, dir=0, base_rank=NO_RANK)) x += l.XS x, y = l.XM + 2 * l.XS, self.height - l.YS for i in range(4): s.rows.append( self.RowStack_Class(x, y, self, max_move=1, max_accept=1, dir=0, base_rank=NO_RANK)) x += l.XS x, y = self.width - l.XS, self.height - l.YS s.foundations.append( self.Foundation_Class(x, y, self, suit=ANY_SUIT, max_move=0, max_cards=52, base_rank=ANY_RANK)) l.createText(s.foundations[0], "n") x, y = l.XM, self.height - l.YS s.talon = InitialDealTalonStack(x, y, self) # define stack-groups l.defaultStackGroups() # # game overrides # def _checkRow(self, cards): for i in range(len(cards)): for j in range(i): if cards[i].rank == cards[j].rank: return j return -1 def _shuffleHook(self, cards): # no row will have two cards of the same rank for i in range(8): for t in range(1000): # just in case j = self._checkRow(cards[i * 6:(i + 1) * 6]) if j < 0: break j += i * 6 k = self.random.choice(list(range((i + 1) * 6, 52))) cards[j], cards[k] = cards[k], cards[j] cards.reverse() return cards def startGame(self): for r in self.s.rows[:8]: for j in range(6): self.s.talon.dealRow(rows=[r], frames=0) self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[8:]) def getAutoStacks(self, event=None): return ((), (), self.sg.dropstacks) def shallHighlightMatch(self, stack1, card1, stack2, card2): return card1.rank == card2.rank
class PenelopesWeb(StreetsAndAlleys): RowStack_Class = StackWrapper(RK_RowStack, base_rank=KING) Solver_Class = FreeCellSolverWrapper(sbb='rank', esf='kings')
class Interregnum(Game): GAME_VERSION = 2 Talon_Class = DealRowTalonStack RowStack_Class = StackWrapper(BasicRowStack, max_accept=0, max_move=1) # # game layout # def createGame(self, rows=8, playcards=12, texts=False): # create layout l, s = Layout(self), self.s # set window self.setSize(l.XM + max(9, rows) * l.XS, l.YM + 3 * l.YS + playcards * l.YOFFSET) # extra settings self.base_cards = None # create stacks for i in range(8): x, y, = l.XM + i * l.XS, l.YM s.reserves.append(ReserveStack(x, y, self, max_accept=0)) for i in range(8): x, y, = l.XM + i * l.XS, l.YM + l.YS s.foundations.append( Interregnum_Foundation(x, y, self, mod=13, max_move=0)) for i in range(rows): x, y, = l.XM + (2 * i + 8 - rows) * l.XS // 2, l.YM + 2 * l.YS s.rows.append(self.RowStack_Class(x, y, self)) s.talon = self.Talon_Class(self.width - l.XS, self.height - l.YS, self) if texts: l.createRoundText(s.talon, 'nn') else: l.createText(s.talon, "n") # define stack-groups l.defaultStackGroups() # # game overrides # def startGame(self): self.startDealSample() self.s.talon.dealRow() # deal base_cards to reserves, update foundations cap.base_rank self.base_cards = [] for i in range(8): self.base_cards.append(self.s.talon.getCard()) self.s.foundations[i].cap.base_rank = \ (self.base_cards[i].rank + 1) % 13 self.flipMove(self.s.talon) self.moveMove(1, self.s.talon, self.s.reserves[i]) def getAutoStacks(self, event=None): return ((), (), self.sg.dropstacks) shallHighlightMatch = Game._shallHighlightMatch_RKW def _restoreGameHook(self, game): self.base_cards = [None] * 8 for i in range(8): id = game.loadinfo.base_card_ids[i] self.base_cards[i] = self.cards[id] self.s.foundations[i].cap.base_rank = \ (self.base_cards[i].rank + 1) % 13 def _loadGameHook(self, p): ids = [] for i in range(8): ids.append(p.load()) self.loadinfo.addattr(base_card_ids=ids) # register extra load var. def _saveGameHook(self, p): for c in self.base_cards: p.dump(c.id)