#!/usr/bin/env python # -*- mode: python; coding: utf-8; -*- # ---------------------------------------------------------------------------## # # Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer # Copyright (C) 2003 Mt. Hood Playing Card Co. # Copyright (C) 2005-2009 Skomoroh # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # ---------------------------------------------------------------------------## # imports # PySol imports from pysollib.mygettext import _ from pysollib.gamedb import registerGame, GameInfo, GI import pysollib.game from pysollib.mfxutil import kwdefault from pysollib.game import Game from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint from pysollib.hint import BlackHoleSolverWrapper from pysollib.pysoltk import MfxCanvasText from pysollib.games.pileon import FourByFour_Hint from pysollib.util import ACE, ANY_RANK, ANY_SUIT, KING, NO_RANK, RANKS, \ SUITS, \ UNLIMITED_REDEALS from pysollib.stack import \ AbstractFoundationStack, \ BasicRowStack, \ DealRowTalonStack, \ InitialDealTalonStack, \ OpenStack, \ RK_FoundationStack, \ RK_RowStack, \ ReserveStack, \ SS_FoundationStack, \ SS_RowStack, \ Stack, \ TalonStack, \ UD_RK_RowStack, \ WasteStack, \ WasteTalonStack, \ isSameSuitSequence, \ StackWrapper # ************************************************************************ # * # ************************************************************************ class Golf_Hint(AbstractHint): # FIXME: this is very simple def computeHints(self): game = self.game # for each stack for r in game.sg.dropstacks: # try if we can drop a card to the Waste w, ncards = r.canDropCards(game.s.foundations) if not w: continue # this assertion must hold for Golf assert ncards == 1 # clone the Waste (including the card that will be dropped) to # form our new foundations ww = (self.ClonedStack(w, stackcards=w.cards+[r.cards[-1]]), ) # now search for a stack that would benefit from this card score, color = 10000 + r.id, None for t in game.sg.dropstacks: if not t.cards: continue if t is r: t = self.ClonedStack(r, stackcards=r.cards[:-1]) if t.canFlipCard(): score = score + 100 elif t.canDropCards(ww)[0]: score = score + 100 # add hint self.addHint(score, ncards, r, w, color) # ************************************************************************ # * # ************************************************************************ class Golf_Talon(WasteTalonStack): def canDealCards(self): if not WasteTalonStack.canDealCards(self): return False return not self.game.isGameWon() class Golf_Waste(WasteStack): def __init__(self, x, y, game, **cap): kwdefault(cap, max_move=0, max_accept=1) WasteStack.__init__(self, x, y, game, **cap) def acceptsCards(self, from_stack, cards): if not WasteStack.acceptsCards(self, from_stack, cards): return False # check cards r1, r2 = self.cards[-1].rank, cards[0].rank if self.game.getStrictness() == 1: # nothing on a King if r1 == KING: return False return (r1 + 1) % self.cap.mod == r2 or (r2 + 1) % self.cap.mod == r1 def getHelp(self): return _('Waste. Build up or down regardless of suit.') class Golf_RowStack(BasicRowStack): def clickHandler(self, event): return self.doubleclickHandler(event) def getHelp(self): return _('Tableau. No building.') # ************************************************************************ # * Golf # ************************************************************************ class Golf(Game): Waste_Class = Golf_Waste Hint_Class = Golf_Hint # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window playcards = 5 w1, w2 = 8*l.XS+l.XM, 2*l.XS if w2 + 52*l.XOFFSET > w1: l.XOFFSET = int((w1 - w2) / 52) self.setSize(w1, l.YM+3*l.YS+(playcards-1)*l.YOFFSET+l.TEXT_HEIGHT) # create stacks x, y = l.XM + l.XS // 2, l.YM for i in range(7): s.rows.append(Golf_RowStack(x, y, self)) x = x + l.XS x, y = l.XM, self.height - l.YS s.talon = Golf_Talon(x, y, self, max_rounds=1) l.createText(s.talon, "n") x = x + l.XS s.waste = self.Waste_Class(x, y, self) s.waste.CARD_XOFFSET = l.XOFFSET l.createText(s.waste, "n") # the Waste is also our only Foundation in this game s.foundations.append(s.waste) # define stack-groups (non default) self.sg.openstacks = [s.waste] self.sg.talonstacks = [s.talon] self.sg.dropstacks = s.rows # # game overrides # def startGame(self): self._startDealNumRows(4) self.s.talon.dealRow() self.s.talon.dealCards() # deal first card to WasteStack def isGameWon(self): for r in self.s.rows: if r.cards: return False return True shallHighlightMatch = Game._shallHighlightMatch_RK def getHighlightPilesStacks(self): return () def getAutoStacks(self, event=None): if event is None: # disable auto drop - this would ruin the whole gameplay return (self.sg.dropstacks, (), ()) else: # rightclickHandler return (self.sg.dropstacks, self.sg.dropstacks, ()) # ************************************************************************ # * # ************************************************************************ class DeadKingGolf(Golf): def getStrictness(self): return 1 def shallHighlightMatch(self, stack1, card1, stack2, card2): if card1.rank == KING: return False return Golf.shallHighlightMatch(self, stack1, card1, stack2, card2) class RelaxedGolf(Golf): Waste_Class = StackWrapper(Golf_Waste, mod=13) shallHighlightMatch = Game._shallHighlightMatch_RKW # ************************************************************************ # * Elevator - Relaxed Golf in a Pyramid layout # ************************************************************************ class Elevator_RowStack(Golf_RowStack): STEP = (1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6) def basicIsBlocked(self): r, step = self.game.s.rows, self.STEP i, n, mylen = self.id, 1, len(step) while i < mylen: i = i + step[i] n = n + 1 for j in range(i, i+n): if r[j].cards: return True return False class Elevator(RelaxedGolf): # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window self.setSize(9*l.XS+l.XM, 4*l.YS+l.YM) # create stacks for i in range(7): x = l.XM + (8-i) * l.XS // 2 y = l.YM + i * l.YS // 2 for j in range(i+1): s.rows.append(Elevator_RowStack(x, y, self)) x = x + l.XS x, y = l.XM, l.YM s.talon = Golf_Talon(x, y, self, max_rounds=1) l.createText(s.talon, "s") x = x + l.XS s.waste = self.Waste_Class(x, y, self) l.createText(s.waste, "s") # the Waste is also our only Foundation in this game s.foundations.append(s.waste) # define stack-groups (non default) self.sg.openstacks = [s.waste] self.sg.talonstacks = [s.talon] self.sg.dropstacks = s.rows # # game overrides # def startGame(self): self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:21], flip=0) self.s.talon.dealRow(rows=self.s.rows[21:]) self.s.talon.dealCards() # deal first card to WasteStack class Escalator(pysollib.game.StartDealRowAndCards, Elevator): pass # ************************************************************************ # * Black Hole # ************************************************************************ class BlackHole_Foundation(AbstractFoundationStack): def acceptsCards(self, from_stack, cards): if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): return False # check the rank if self.cards: r1, r2 = self.cards[-1].rank, cards[0].rank return (r1 + 1) % self.cap.mod == r2 or \ (r2 + 1) % self.cap.mod == r1 return True def getHelp(self): return _('Foundation. Build up or down regardless of suit.') class BlackHole_RowStack(ReserveStack): def clickHandler(self, event): return self.doubleclickHandler(event) def getHelp(self): return _('Tableau. No building.') class BlackHole(Game): RowStack_Class = StackWrapper( BlackHole_RowStack, max_accept=0, max_cards=3) Hint_Class = Golf_Hint Solver_Class = BlackHoleSolverWrapper(preset='black_hole') # # game layout # def createGame(self, playcards=5): # create layout l, s = Layout(self), self.s # set window w = max(2*l.XS, l.XS+(playcards-1)*l.XOFFSET) self.setSize(l.XM + 5*w, l.YM + 4*l.YS) # create stacks y = l.YM for i in range(5): x = l.XM + i*w s.rows.append(self.RowStack_Class(x, y, self)) for i in range(2): y = y + l.YS for j in (0, 1, 3, 4): x = l.XM + j*w s.rows.append(self.RowStack_Class(x, y, self)) y = y + l.YS for i in range(4): x = l.XM + i*w s.rows.append(self.RowStack_Class(x, y, self)) for r in s.rows: r.CARD_XOFFSET = l.XOFFSET r.CARD_YOFFSET = 0 x, y = l.XM + 2*w, l.YM + 3*l.YS//2 s.foundations.append(BlackHole_Foundation(x, y, self, suit=ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52)) l.createText(s.foundations[0], "s") x, y = l.XM + 4*w, self.height - l.YS s.talon = InitialDealTalonStack(x, y, self) # define stack-groups l.defaultStackGroups() # # game overrides # def _shuffleHook(self, cards): # move Ace to bottom of the Talon (i.e. last cards to be dealt) return self._shuffleHookMoveToBottom( cards, lambda c: (c.id == 13, c.suit), 1) def startGame(self): self._startDealNumRows(2) self.s.talon.dealRow() self.s.talon.dealRow(rows=self.s.foundations) def getAutoStacks(self, event=None): if event is None: # disable auto drop - this would ruin the whole gameplay return ((), (), self.sg.dropstacks) else: # rightclickHandler return ((), self.sg.dropstacks, self.sg.dropstacks) # ************************************************************************ # * Four Leaf Clovers # ************************************************************************ class FourLeafClovers_Foundation(AbstractFoundationStack): def acceptsCards(self, from_stack, cards): if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): return False # check the rank if self.cards: r1, r2 = self.cards[-1].rank, cards[0].rank return (r1 + 1) % self.cap.mod == r2 return True def getHelp(self): return _('Foundation. Build up regardless of suit.') class FourLeafClovers(Game): Hint_Class = CautiousDefaultHint # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window h = l.YS + 6*l.YOFFSET self.setSize(l.XM + 7*l.XS, l.YM + 2*h) # create stacks y = l.YM for i in range(7): x = l.XM + i*l.XS s.rows.append( UD_RK_RowStack(x, y, self, mod=13, base_rank=NO_RANK)) y = l.YM+h for i in range(6): x = l.XM + i*l.XS s.rows.append( UD_RK_RowStack(x, y, self, mod=13, base_rank=NO_RANK)) stack = FourLeafClovers_Foundation(l.XM+6*l.XS, self.height-l.YS, self, suit=ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52) s.foundations.append(stack) l.createText(stack, 'n') x, y = l.XM + 7*l.XS, self.height - l.YS s.talon = InitialDealTalonStack(x, y, self) # define stack-groups l.defaultStackGroups() def startGame(self): self._startDealNumRowsAndDealSingleRow(3) shallHighlightMatch = Game._shallHighlightMatch_RKW # ************************************************************************ # * All in a Row # ************************************************************************ class AllInARow(BlackHole): Solver_Class = BlackHoleSolverWrapper(preset='all_in_a_row') def createGame(self): # create layout l, s = Layout(self), self.s # set window h = l.YM+l.YS+4*l.YOFFSET self.setSize(l.XM+7*l.XS, 3*l.YM+2*h+l.YS) # create stacks x, y = l.XM, l.YM for i in range(7): s.rows.append(self.RowStack_Class(x, y, self)) x += l.XS x, y = l.XM, l.YM+h for i in range(6): s.rows.append(self.RowStack_Class(x, y, self)) x += l.XS for r in s.rows: r.CARD_XOFFSET, r.CARD_YOFFSET = 0, l.YOFFSET x, y = l.XM, self.height-l.YS stack = BlackHole_Foundation( x, y, self, ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52, base_rank=ANY_RANK) s.foundations.append(stack) stack.CARD_XOFFSET, stack.CARD_YOFFSET = (self.width-l.XS)//51, 0 l.createText(stack, 'n') x = self.width-l.XS s.talon = InitialDealTalonStack(x, y, self) # define stack-groups l.defaultStackGroups() def startGame(self): self._startDealNumRowsAndDealSingleRow(3) # ************************************************************************ # * Robert # * Wasatch # ************************************************************************ class Robert(Game): def createGame(self, max_rounds=3, num_deal=1): l, s = Layout(self), self.s self.setSize(l.XM+4*l.XS, l.YM+2*l.YS) x, y = l.XM+3*l.XS//2, l.YM stack = BlackHole_Foundation(x, y, self, ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52) s.foundations.append(stack) l.createText(stack, 'ne') x, y = l.XM+l.XS, l.YM+l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds, num_deal=num_deal) l.createText(s.talon, 'nw') if max_rounds > 0: l.createRoundText(self.s.talon, 'se', dx=l.XS) x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 'ne') # define stack-groups l.defaultStackGroups() def startGame(self): self.startDealSample() self.s.talon.dealRow(rows=self.s.foundations) self.s.talon.dealCards() class Wasatch(Robert): def createGame(self): Robert.createGame(self, max_rounds=UNLIMITED_REDEALS, num_deal=3) def startGame(self): self.startDealSample() self.s.talon.dealCards() # ************************************************************************ # * Diamond Mine # ************************************************************************ DIAMOND = 3 class DiamondMine_RowStack(RK_RowStack): def acceptsCards(self, from_stack, cards): if not RK_RowStack.acceptsCards(self, from_stack, cards): return False if cards[0].suit == DIAMOND: return False if self.cards: return self.cards[-1].suit != DIAMOND return True class DiamondMine(Game): def createGame(self): l, s = Layout(self), self.s self.setSize(l.XM+13*l.XS, l.YM+2*l.YS+15*l.YOFFSET) x, y = l.XM+6*l.XS, l.YM s.foundations.append(SS_FoundationStack(x, y, self, base_rank=ANY_RANK, suit=DIAMOND, mod=13)) x, y = l.XM, l.YM+l.YS for i in range(13): s.rows.append(DiamondMine_RowStack(x, y, self)) x += l.XS s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self) l.defaultAll() def startGame(self): for i in range(3): self.s.talon.dealRow(flip=0, frames=0) self._startAndDealRow() def isGameWon(self): if len(self.s.foundations[0].cards) != 13: return False for s in self.s.rows: if len(s.cards) == 0: continue if len(s.cards) != 13: return False if not isSameSuitSequence(s.cards): return False return True shallHighlightMatch = Game._shallHighlightMatch_RK # ************************************************************************ # * Dolphin # ************************************************************************ class Dolphin(Game): def createGame(self, rows=8, reserves=4, playcards=6): l, s = Layout(self), self.s self.setSize(l.XM+rows*l.XS, l.YM+3*l.YS+playcards*l.YOFFSET) dx = (self.width-l.XM-(reserves+1)*l.XS)//3 x, y = l.XM+dx, l.YM for i in range(reserves): s.reserves.append(ReserveStack(x, y, self)) x += l.XS x += dx max_cards = 52*self.gameinfo.decks s.foundations.append(RK_FoundationStack(x, y, self, base_rank=ANY_RANK, mod=13, max_cards=max_cards)) l.createText(s.foundations[0], 'ne') x, y = l.XM, l.YM+l.YS for i in range(rows): s.rows.append(BasicRowStack(x, y, self)) x += l.XS s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self) l.defaultAll() def startGame(self): self._startDealNumRows(5) self.s.talon.dealRow() self.s.talon.dealRowAvail() class DoubleDolphin(Dolphin): def createGame(self): Dolphin.createGame(self, rows=10, reserves=5, playcards=10) def startGame(self): self._startDealNumRows(9) self.s.talon.dealRow() self.s.talon.dealRowAvail() # ************************************************************************ # * Waterfall # ************************************************************************ class Waterfall_Foundation(AbstractFoundationStack): def acceptsCards(self, from_stack, cards): if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): return False c1 = cards[0] if not self.cards: return c1.rank == ACE and c1.suit == 0 c2 = self.cards[-1] if c2.rank == KING: suit = (c2.suit+1) % 4 rank = ACE else: suit = c2.suit rank = c2.rank+1 return c1.suit == suit and c1.rank == rank class Waterfall(Game): def createGame(self): rows = 8 l, s = Layout(self), self.s self.setSize(l.XM+rows*l.XS, l.YM+2*l.YS+20*l.YOFFSET) x, y = l.XM, l.YM for i in range(rows): s.rows.append(RK_RowStack(x, y, self)) x += l.XS x, y = l.XM+(rows-1)*l.XS//2, self.height-l.YS s.foundations.append(Waterfall_Foundation(x, y, self, suit=ANY_SUIT, max_cards=104)) stack = s.foundations[0] tx, ty, ta, tf = l.getTextAttr(stack, 'se') font = self.app.getFont('canvas_default') stack.texts.misc = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) x, y = self.width-l.XS, self.height-l.YS s.talon = DealRowTalonStack(x, y, self) l.createText(s.talon, 'sw') l.defaultStackGroups() def startGame(self): self._startDealNumRowsAndDealSingleRow(3) def updateText(self): if self.preview > 1: return f = self.s.foundations[0] if len(f.cards) == 104: t = '' elif len(f.cards) == 0: t = SUITS[0] else: c = f.cards[-1] if c.rank == KING: suit = (c.suit+1) % 4 else: suit = c.suit t = SUITS[suit] f.texts.misc.config(text=t) shallHighlightMatch = Game._shallHighlightMatch_RK # ************************************************************************ # * Vague # * Thirty Two Cards # ************************************************************************ class Vague_RowStack(BasicRowStack): clickHandler = BasicRowStack.doubleclickHandler class Vague(Game): Foundation_Classes = [StackWrapper(SS_FoundationStack, base_rank=ANY_RANK, mod=13)] def createGame(self, rows=3, columns=6): l, s = Layout(self), self.s decks = self.gameinfo.decks maxrows = max(columns, 2+decks*4) self.setSize(l.XM+maxrows*l.XS, l.YM+(rows+1)*l.YS) x, y = l.XM, l.YM s.talon = TalonStack(x, y, self) l.createText(s.talon, 'ne') x, y = l.XM+2*l.XS, l.YM for found in self.Foundation_Classes: for i in range(4): s.foundations.append(found(x, y, self, suit=i)) x += l.XS y = l.YM+l.YS for i in range(rows): x = l.XM + (maxrows-columns)*l.XS//2 for j in range(columns): s.rows.append(Vague_RowStack(x, y, self)) x += l.XS y += l.YS l.defaultStackGroups() def startGame(self): self.startDealSample() self.s.talon.dealRow() self.s.talon.flipMove() def fillStack(self, stack): if stack in self.s.rows and not stack.cards: if self.s.talon.cards: old_state = self.enterState(self.S_FILL) if not self.s.talon.cards[-1].face_up: self.s.talon.flipMove() self.s.talon.moveMove(1, stack) self.leaveState(old_state) def getAutoStacks(self, event=None): if event is None: # disable auto drop - this would ruin the whole gameplay return ((), (), self.sg.dropstacks) else: # rightclickHandler return ((), self.sg.dropstacks, self.sg.dropstacks) class ThirtyTwoCards(Vague): Foundation_Classes = [ SS_FoundationStack, StackWrapper(SS_FoundationStack, base_rank=KING, dir=-1)] def createGame(self): Vague.createGame(self, rows=4, columns=8) def startGame(self): self._startAndDealRow() # ************************************************************************ # * Devil's Solitaire # ************************************************************************ class DevilsSolitaire_Foundation(RK_FoundationStack): def acceptsCards(self, from_stack, cards): if not RK_FoundationStack.acceptsCards(self, from_stack, cards): return False if self.cards: return True if self.game.s.reserves[0].cards: c = self.game.s.reserves[0].cards[-1] return (c.rank+1) % 13 == cards[-1].rank return True class DevilsSolitaire_WasteStack(WasteStack): clickHandler = WasteStack.doubleclickHandler class DevilsSolitaire(Game): def createGame(self): l, s = Layout(self), self.s self.setSize(l.XM+9*l.XS, l.YM+3*l.YS+7*l.YOFFSET+2*l.TEXT_HEIGHT) x, y = l.XM+4*l.XS, l.YM stack = DevilsSolitaire_Foundation( x, y, self, suit=ANY_SUIT, base_rank=ANY_RANK, mod=13) tx, ty, ta, tf = l.getTextAttr(stack, 'nw') font = self.app.getFont('canvas_default') stack.texts.misc = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font) s.foundations.append(stack) x, y = self.width-l.XS, l.YM stack = AbstractFoundationStack( x, y, self, suit=ANY_SUIT, max_move=0, max_cards=104, max_accept=0, base_rank=ANY_RANK) l.createText(stack, 'nw') s.foundations.append(stack) x, y = l.XM, l.YM+l.YS for i in range(4): s.rows.append(Vague_RowStack(x, y, self)) x += l.XS x += l.XS for i in range(4): s.rows.append(Vague_RowStack(x, y, self)) x += l.XS x, y = l.XM+4*l.XS, l.YM+l.YS stack = OpenStack(x, y, self) stack.CARD_YOFFSET = l.YOFFSET s.reserves.append(stack) x, y = l.XM+4.5*l.XS, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') l.createRoundText(s.talon, 'nnn') x -= l.XS s.waste = DevilsSolitaire_WasteStack(x, y, self) l.createText(s.waste, 'n') l.defaultStackGroups() def startGame(self): for i in range(8): self.s.talon.dealRow(rows=self.s.reserves, frames=0) self.startDealSample() self.s.talon.dealRow() self.s.talon.dealCards() def fillStack(self, stack): old_state = self.enterState(self.S_FILL) if stack in self.s.rows and not stack.cards: if not self.s.waste.cards: self.s.talon.dealCards() if self.s.waste.cards: self.s.waste.moveMove(1, stack) f0 = self.s.foundations[0] if len(f0.cards) == 12: self.moveMove(1, self.s.reserves[0], f0, frames=4) f1 = self.s.foundations[1] for i in range(13): self.moveMove(1, f0, f1, frames=4) self.leaveState(old_state) def updateText(self): if self.preview > 1: return f = self.s.foundations[0] r = self.s.reserves[0] if not r.cards: t = '' else: c = r.cards[-1] t = RANKS[(c.rank+1) % 13] f.texts.misc.config(text=t) # ************************************************************************ # * Three Fir-trees # ************************************************************************ class ThreeFirTrees_RowStack(Golf_RowStack): def __init__(self, x, y, game): Golf_RowStack.__init__(self, x, y, game, max_accept=0, max_cards=1) self.CARD_YOFFSET = 0 self.blockmap = [] def basicIsBlocked(self): for r in self.blockmap: if r.cards: return True return False getBottomImage = Stack._getNoneBottomImage class FirTree_GameMethods: def _createFirTree(self, l, x0, y0): rows = [] # create stacks for i in range(11): x = x0 + ((i+1) % 2) * l.XS // 2 y = y0 + i * l.YS // 4 for j in range((i % 2) + 1): rows.append(ThreeFirTrees_RowStack(x, y, self)) x += l.XS # compute blocking n = 0 for i in range(10): if i % 2: rows[n].blockmap = [rows[n+2]] rows[n+1].blockmap = [rows[n+2]] n += 2 else: rows[n].blockmap = [rows[n+1], rows[n+2]] n += 1 return rows class ThreeFirTrees(Golf, FirTree_GameMethods): Hint_Class = CautiousDefaultHint Waste_Class = Golf_Waste def createGame(self): l, s = Layout(self), self.s self.setSize(l.XM+max(7*l.XS, 2*l.XS+26*l.XOFFSET), l.YM+5*l.YS) x0, y0 = (self.width-7*l.XS)//2, l.YM for i in range(3): s.rows += self._createFirTree(l, x0, y0) x0 += 2.5*l.XS x, y = l.XM, self.height - l.YS s.talon = Golf_Talon(x, y, self, max_rounds=1) l.createText(s.talon, 'n') x += l.XS s.waste = self.Waste_Class(x, y, self) s.waste.CARD_XOFFSET = l.XOFFSET//4 l.createText(s.waste, 'n') # the Waste is also our only Foundation in this game s.foundations.append(s.waste) # define stack-groups (non default) self.sg.openstacks = [s.waste] self.sg.talonstacks = [s.talon] self.sg.dropstacks = s.rows def startGame(self): self.startDealSample() self.s.talon.dealRow(frames=4) self.s.talon.dealCards() class RelaxedThreeFirTrees(ThreeFirTrees): Waste_Class = StackWrapper(Golf_Waste, mod=13) # ************************************************************************ # * Napoleon Takes Moscow # * Napoleon Leaves Moscow # ************************************************************************ class NapoleonTakesMoscow(Game, FirTree_GameMethods): RowStack_Class = StackWrapper(SS_RowStack, base_rank=KING, max_move=1) Hint_Class = CautiousDefaultHint def createGame(self): l, s = Layout(self), self.s self.setSize(l.XM+10*l.XS, l.YM+3*l.YS+15*l.YOFFSET) x, y = l.XM+l.XS, l.YM 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(2): for j in range(4): s.rows.append(self.RowStack_Class(x, y, self)) x += l.XS x += 2*l.XS x, y = l.XM+4*l.XS, l.YM+l.YS s.reserves += self._createFirTree(l, x, y) x, y = l.XM, self.height-l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=3) l.createText(s.talon, 'n') l.createRoundText(s.talon, 'nnn') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 'n') # define stack-groups l.defaultStackGroups() def startGame(self): self.s.talon.dealRow(rows=self.s.reserves, frames=0) self._startDealNumRows(3) self.s.talon.dealRow() self.s.talon.dealCards() shallHighlightMatch = Game._shallHighlightMatch_SS class NapoleonLeavesMoscow(NapoleonTakesMoscow): RowStack_Class = StackWrapper(SS_RowStack, base_rank=KING) Hint_Class = DefaultHint def startGame(self): self.s.talon.dealRow(rows=self.s.reserves, frames=0) self._startDealNumRows(4) self.s.talon.dealRow() self.s.talon.dealCards() # ************************************************************************ # * Flake # * Flake (2 decks) # ************************************************************************ class Flake(Game): Hint_Class = FourByFour_Hint # CautiousDefaultHint def createGame(self, rows=6, playcards=18): # create layout l, s = Layout(self), self.s # set window self.setSize(l.XM + rows*l.XS, l.YM + 2*l.YS + playcards*l.XOFFSET) # create stacks x, y, = l.XM, l.YM+l.YS for i in range(rows): s.rows.append(UD_RK_RowStack(x, y, self, mod=13)) x += l.XS x, y = l.XM + (rows-1)*l.XS//2, l.YM stack = BlackHole_Foundation(x, y, self, max_move=0, suit=ANY_SUIT, base_rank=ANY_RANK, dir=0, mod=13, max_cards=52*self.gameinfo.decks) s.foundations.append(stack) l.createText(stack, 'ne') x, y = l.XM, self.height-l.YS s.talon = InitialDealTalonStack(x, y, self) # define stack-groups l.defaultStackGroups() def startGame(self): self._startDealNumRows(7) self.s.talon.dealRow() self.s.talon.dealRowAvail() shallHighlightMatch = Game._shallHighlightMatch_RKW class Flake2Decks(Flake): def createGame(self): Flake.createGame(self, rows=8, playcards=22) def startGame(self): self._startDealNumRowsAndDealSingleRow(12) # ************************************************************************ # * Beacon # ************************************************************************ class Beacon(Game): def createGame(self, rows=8): # create layout l, s = Layout(self), self.s # set window playcards = 12 self.setSize(l.XM+rows*l.XS, l.YM+3*l.YS+playcards*l.YOFFSET) # create stacks x, y = l.XM + (rows-1)*l.XS//2, l.YM stack = RK_FoundationStack(x, y, self, base_rank=ANY_RANK, max_cards=52, mod=13) s.foundations.append(stack) l.createText(stack, 'ne') x, y = l.XM, l.YM+l.YS for i in range(rows): s.rows.append(RK_RowStack(x, y, self, base_rank=NO_RANK, mod=13)) x += l.XS x, y = l.XM, self.height-l.YS s.talon = TalonStack(x, y, self) l.createText(s.talon, 'se') # define stack-groups l.defaultStackGroups() def startGame(self): self._startDealNumRowsAndDealSingleRow(3) def fillStack(self, stack): if stack in self.s.rows and not stack.cards: if self.s.talon.cards: old_state = self.enterState(self.S_FILL) self.s.talon.flipMove() self.s.talon.moveMove(1, stack) self.leaveState(old_state) shallHighlightMatch = Game._shallHighlightMatch_RKW # register the game registerGame(GameInfo(36, Golf, "Golf", GI.GT_GOLF, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(259, DeadKingGolf, "Dead King Golf", GI.GT_GOLF, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(260, RelaxedGolf, "Relaxed Golf", GI.GT_GOLF | GI.GT_RELAXED, 1, 0, GI.SL_BALANCED, altnames=("Putt Putt",))) registerGame(GameInfo(40, Elevator, "Elevator", GI.GT_GOLF, 1, 0, GI.SL_BALANCED, altnames=("Egyptian Solitaire", "Pyramid Golf"))) registerGame(GameInfo(98, BlackHole, "Black Hole", GI.GT_GOLF | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(267, FourLeafClovers, "Four Leaf Clovers", GI.GT_GOLF | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(281, Escalator, "Escalator", GI.GT_GOLF, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(405, AllInARow, "All in a Row", GI.GT_GOLF | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(432, Robert, "Robert", GI.GT_GOLF, 1, 2, GI.SL_LUCK)) registerGame(GameInfo(551, DiamondMine, "Diamond Mine", GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(661, Dolphin, "Dolphin", GI.GT_GOLF | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(662, DoubleDolphin, "Double Dolphin", GI.GT_GOLF | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(709, Waterfall, "Waterfall", GI.GT_2DECK_TYPE | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(720, Vague, "Vague", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(723, DevilsSolitaire, "Devil's Solitaire", GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED, altnames=('Banner',))) registerGame(GameInfo(728, ThirtyTwoCards, "Thirty Two Cards", GI.GT_2DECK_TYPE, 2, 0, GI.SL_LUCK)) registerGame(GameInfo(731, ThreeFirTrees, "Three Fir-trees", GI.GT_GOLF, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(733, NapoleonTakesMoscow, "Napoleon Takes Moscow", GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) registerGame(GameInfo(734, NapoleonLeavesMoscow, "Napoleon Leaves Moscow", GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) registerGame(GameInfo(749, Flake, "Flake", GI.GT_GOLF | GI.GT_OPEN | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(750, Flake2Decks, "Flake (2 decks)", GI.GT_GOLF | GI.GT_OPEN | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(763, Wasatch, "Wasatch", GI.GT_1DECK_TYPE, 1, UNLIMITED_REDEALS, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(764, Beacon, "Beacon", GI.GT_1DECK_TYPE | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(768, RelaxedThreeFirTrees, "Relaxed Three Fir-trees", GI.GT_GOLF, 2, 0, GI.SL_BALANCED))