#!/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 . # # --------------------------------------------------------------------------- from pysollib.game import Game from pysollib.gamedb import GI, GameInfo, registerGame from pysollib.hint import CautiousDefaultHint from pysollib.hint import FreeCellSolverWrapper from pysollib.layout import Layout from pysollib.mygettext import _ from pysollib.pysoltk import MfxCanvasText from pysollib.stack import \ AC_FoundationStack, \ AC_RowStack, \ DealRowRedealTalonStack, \ DealRow_StackMethods, \ FullStackWrapper, \ InitialDealTalonStack, \ InvisibleStack, \ KingAC_RowStack, \ KingSS_RowStack, \ RK_RowStack, \ RedealTalonStack, \ ReserveStack, \ SS_FoundationStack, \ SS_RowStack, \ Stack, \ StackWrapper, \ SuperMoveSS_RowStack, \ TalonStack, \ UD_RK_RowStack, \ UD_SS_RowStack from pysollib.util import ACE, KING, NO_RANK, UNLIMITED_CARDS class Fan_Hint(CautiousDefaultHint): # FIXME: demo is not too clever in this game pass # ************************************************************************ # * Fan # ************************************************************************ class Fan(Game): Talon_Class = InitialDealTalonStack Foundation_Classes = [SS_FoundationStack] ReserveStack_Class = ReserveStack RowStack_Class = KingSS_RowStack Hint_Class = Fan_Hint # # game layout # def createGame(self, rows=(5, 5, 5, 3), playcards=9, reserves=0, texts=False): # create layout l, s = Layout(self), self.s # set window # (set size so that at least 9 cards are fully playable) w = max(2*l.XS, l.XS+(playcards-1)*l.XOFFSET) w = min(3*l.XS, w) w = (w + 1) & ~1 # print 2*l.XS, w self.setSize(l.XM + max(rows)*w, l.YM + (1+len(rows))*l.YS) # create stacks decks = self.gameinfo.decks if reserves: x, y = l.XM, l.YM for r in range(reserves): s.reserves.append(self.ReserveStack_Class(x, y, self)) x += l.XS x = (self.width - decks*4*l.XS) # - 2*l.XS) // 2 dx = l.XS else: dx = (self.width - decks*4*l.XS)//(decks*4+1) x, y = l.XM + dx, l.YM dx += l.XS for fnd_cls in self.Foundation_Classes: for i in range(4): s.foundations.append(fnd_cls(x, y, self, suit=i)) x += dx for i in range(len(rows)): x, y = l.XM, y + l.YS for j in range(rows[i]): stack = self.RowStack_Class( x, y, self, max_move=1, max_accept=1) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 s.rows.append(stack) x += w x, y = self.width - l.XS, self.height - l.YS s.talon = self.Talon_Class(x, y, self) if texts: l.createRoundText(s.talon, 'nn') # define stack-groups l.defaultStackGroups() return l # # game overrides # def startGame(self): for i in range(2): self.s.talon.dealRow(rows=self.s.rows[:17], frames=0) self._startAndDealRow() shallHighlightMatch = Game._shallHighlightMatch_SS def getHighlightPilesStacks(self): return () class FanGame(Fan): Solver_Class = FreeCellSolverWrapper(preset='fan') # ************************************************************************ # * Scotch Patience # ************************************************************************ class ScotchPatience(Fan): Foundation_Classes = [AC_FoundationStack] RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK) def createGame(self): Fan.createGame(self, playcards=8) shallHighlightMatch = Game._shallHighlightMatch_RK # ************************************************************************ # * Shamrocks # * Shamrocks II # ************************************************************************ class Shamrocks(Fan): RowStack_Class = StackWrapper( UD_RK_RowStack, base_rank=NO_RANK, max_cards=3) def createGame(self): Fan.createGame(self, playcards=4) shallHighlightMatch = Game._shallHighlightMatch_RK class ShamrocksII(Shamrocks): def _shuffleHook(self, cards): # move Kings to bottom of each stack i, n = 0, 17 kings = [] for c in cards: if c.rank == KING: kings.append(i) i += 1 for i in kings: if i == 51: continue j = i % n while j < i: if cards[j].rank != KING: cards[i], cards[j] = cards[j], cards[i] break j += n cards.reverse() return cards # ************************************************************************ # * La Belle Lucie (Midnight Oil) # ************************************************************************ class LaBelleLucie_Talon(TalonStack): def canDealCards(self): return self.round != self.max_rounds and not self.game.isGameWon() def dealCards(self, sound=False): n = self.redealCards1() if n == 0: return 0 self.redealCards2() if sound: self.game.startDealSample() self.redealCards3() if sound: self.game.stopSamples() return n # redeal step 1) - collect all cards, move them to the Talon def redealCards1(self): assert len(self.cards) == 0 num_cards = 0 for r in self.game.s.rows: if r.cards: num_cards = num_cards + len(r.cards) self.game.moveMove(len(r.cards), r, self, frames=0) assert len(self.cards) == num_cards return num_cards # redeal step 2) - shuffle def redealCards2(self): assert self.round != self.max_rounds assert self.cards self.game.shuffleStackMove(self) self.game.nextRoundMove(self) # redeal step 3) - redeal cards to stacks def redealCards3(self, face_up=1): # deal 3 cards to each row, and 1-3 cards to last row to_stacks = self.game.s.rows n = min(len(self.cards), 3*len(to_stacks)) for i in range(3): j = (n//3, (n+1)//3, (n+2)//3)[i] frames = (0, 0, 4)[i] for r in to_stacks[:j]: if self.cards[-1].face_up != face_up: self.game.flipMove(self) self.game.moveMove(1, self, r, frames=frames) 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) # ************************************************************************ # * Super Flower Garden # ************************************************************************ class SuperFlowerGarden(LaBelleLucie): RowStack_Class = StackWrapper(RK_RowStack, base_rank=NO_RANK) shallHighlightMatch = Game._shallHighlightMatch_RK # ************************************************************************ # * Three Shuffles and a Draw # ************************************************************************ class ThreeShufflesAndADraw_RowStack(SS_RowStack): def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): game, r = self.game, self.game.s.reserves[0] if to_stack is not r: SS_RowStack.moveMove( self, ncards, to_stack, frames=frames, shadow=shadow) return f = self._canDrawCard() assert f and game.draw_done == 0 and ncards == 1 # 1) top card from self to reserve game.updateStackMove(r, 2 | 16) # update view for undo game.moveMove(1, self, r, frames=frames, shadow=shadow) game.updateStackMove(r, 3 | 64) # update model game.updateStackMove(r, 1 | 16) # update view for redo # 2) second card from self to foundation/row if 1 or not game.demo: game.playSample("drop", priority=200) if frames == 0: frames = -1 game.moveMove(1, self, f, frames=frames, shadow=shadow) # 3) from reserve back to self # (need S_FILL because the move is normally not valid) old_state = game.enterState(game.S_FILL) game.moveMove(1, r, self, frames=frames, shadow=shadow) game.leaveState(old_state) def _canDrawCard(self): if len(self.cards) >= 2: pile = self.cards[-2:-1] for s in self.game.s.foundations + self.game.s.rows: if s is not self and s.acceptsCards(self, pile): return s return None class ThreeShufflesAndADraw_ReserveStack(ReserveStack): def acceptsCards(self, from_stack, cards): if not ReserveStack.acceptsCards(self, from_stack, cards): return False if from_stack not in self.game.s.rows: return False if self.game.draw_done or not from_stack._canDrawCard(): return False return True def updateModel(self, undo, flags): assert undo == self.game.draw_done self.game.draw_done = not self.game.draw_done def updateText(self): if self.game.preview > 1 or self.texts.misc is None: return t = (_("X"), _("Draw"))[self.game.draw_done == 0] self.texts.misc.config(text=t) def prepareView(self): ReserveStack.prepareView(self) if not self.is_visible or self.game.preview > 1: return images = self.game.app.images x, y = self.x + images.CARDW//2, self.y + images.CARDH//2 self.texts.misc = MfxCanvasText( self.game.canvas, x, y, anchor="center", font=self.game.app.getFont("canvas_default")) class ThreeShufflesAndADraw(LaBelleLucie): RowStack_Class = StackWrapper( ThreeShufflesAndADraw_RowStack, base_rank=NO_RANK) def createGame(self): lay = LaBelleLucie.createGame(self) s = self.s # add a reserve stack x, y = s.rows[3].x, s.rows[-1].y s.reserves.append(ThreeShufflesAndADraw_ReserveStack(x, y, self)) # redefine the stack-groups lay.defaultStackGroups() # extra settings self.draw_done = 0 def startGame(self): self.draw_done = 0 self.s.reserves[0].updateText() LaBelleLucie.startGame(self) def _restoreGameHook(self, game): self.draw_done = game.loadinfo.draw_done def _loadGameHook(self, p): self.loadinfo.addattr(draw_done=p.load()) def _saveGameHook(self, p): p.dump(self.draw_done) # ************************************************************************ # * Trefoil # ************************************************************************ class Trefoil(LaBelleLucie): GAME_VERSION = 2 Foundation_Classes = [StackWrapper(SS_FoundationStack, min_cards=1)] def createGame(self): return Fan.createGame(self, rows=(5, 5, 5, 1), texts=True) def _shuffleHook(self, cards): # move Aces to bottom of the Talon (i.e. last cards to be dealt) return self._shuffleHookMoveToBottom( cards, lambda c: (c.rank == 0, c.suit)) def startGame(self): self._startDealNumRows(2) self.s.talon.dealRow() self.s.talon.dealRow(rows=self.s.foundations) # ************************************************************************ # * Intelligence # ************************************************************************ class Intelligence_Talon(LaBelleLucie_Talon): # all Aces go to Foundations dealToStacks = TalonStack.dealToStacksOrFoundations # redeal step 1) - collect all cards, move them to the Talon (face down) def redealCards1(self): assert len(self.cards) == 0 r = self.game.s.reserves[0] num_cards = len(r.cards) if num_cards > 0: self.game.moveMove(len(r.cards), r, self, frames=0) for r in self.game.s.rows: num_cards = num_cards + len(r.cards) while r.cards: self.game.moveMove(1, r, self, frames=0) self.game.flipMove(self) assert len(self.cards) == num_cards return num_cards # redeal step 3) - redeal cards to stacks def redealCards3(self, face_up=1): for r in self.game.s.rows: while len(r.cards) < 3: self.dealToStacks([r], frames=4) if not self.cards: return # move all remaining cards to the reserve self.game.moveMove( len(self.cards), self, self.game.s.reserves[0], frames=0) # up or down in suit class Intelligence_RowStack(UD_SS_RowStack): def fillStack(self): if not self.cards: r = self.game.s.reserves[0] if r.cards: r.dealRow((self, self, self), sound=True) class Intelligence_ReserveStack(ReserveStack, DealRow_StackMethods): # all Aces go to Foundations (used in r.dealRow() above) dealToStacks = DealRow_StackMethods.dealToStacksOrFoundations def canFlipCard(self): return False class Intelligence(Fan): Foundation_Classes = [SS_FoundationStack, SS_FoundationStack] Talon_Class = StackWrapper(Intelligence_Talon, max_rounds=3) RowStack_Class = StackWrapper(Intelligence_RowStack, base_rank=NO_RANK) def createGame(self, rows=(5, 5, 5, 3)): lay = Fan.createGame(self, rows) s = self.s # add a reserve stack x, y = s.talon.x - lay.XS, s.talon.y s.reserves.append( Intelligence_ReserveStack( x, y, self, max_move=0, max_accept=0, max_cards=UNLIMITED_CARDS)) lay.createText(s.reserves[0], "sw") lay.createRoundText(s.talon, 'nn') # redefine the stack-groups lay.defaultStackGroups() def startGame(self): talon = self.s.talon self._startDealNumRows(2) talon.dealRow() # move all remaining cards to the reserve self.moveMove(len(talon.cards), talon, self.s.reserves[0], frames=0) class IntelligencePlus(Intelligence): def createGame(self): Intelligence.createGame(self, rows=(5, 5, 5, 4)) # ************************************************************************ # * House in the Wood # * House on the Hill # * (2 decks variants of Fan) # ************************************************************************ class HouseInTheWood(Fan): Foundation_Classes = [SS_FoundationStack, SS_FoundationStack] RowStack_Class = StackWrapper(UD_SS_RowStack, base_rank=NO_RANK) def createGame(self): Fan.createGame(self, rows=(6, 6, 6, 6, 6, 5)) def startGame(self): self.s.talon.dealRow(rows=self.s.rows[:34], frames=0) self.s.talon.dealRow(rows=self.s.rows[:35], frames=0) self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:35]) class HouseOnTheHill(HouseInTheWood): Foundation_Classes = [SS_FoundationStack, StackWrapper( SS_FoundationStack, base_rank=KING, dir=-1)] # ************************************************************************ # * Clover Leaf # ************************************************************************ class CloverLeaf_RowStack(UD_SS_RowStack): def acceptsCards(self, from_stack, cards): if not UD_SS_RowStack.acceptsCards(self, from_stack, cards): return False if not self.cards: return cards[0].rank in (ACE, KING) return True def _getBaseCard(self): return _('Base card - Ace or King.') class CloverLeaf(Game): Hint_Class = Fan_Hint # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window playcards = 7 w, h = l.XM+l.XS+4*(l.XS+(playcards-1)*l.XOFFSET), l.YM+4*l.YS self.setSize(w, h) # create stacks x, y = l.XM, l.YM for i in range(2): s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) y += l.YS for i in range(2): s.foundations.append(SS_FoundationStack(x, y, self, suit=i+2, base_rank=KING, dir=-1)) y += l.YS x = l.XM+l.XS for i in range(4): y = l.YM for j in range(4): stack = CloverLeaf_RowStack(x, y, self, max_move=1, max_accept=1) s.rows.append(stack) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 y += l.YS x += l.XS+(playcards-1)*l.XOFFSET s.talon = InitialDealTalonStack(w-l.XS, h-l.YS, self) # default l.defaultAll() # # game overrides # def startGame(self): self._startDealNumRows(2) self.s.talon.dealRow() self.s.talon.dealRow(rows=self.s.foundations) def _shuffleHook(self, cards): return self._shuffleHookMoveToBottom( cards, lambda c: ((c.rank == ACE and c.suit in (0, 1)) or (c.rank == KING and c.suit in (2, 3)), c.suit)) shallHighlightMatch = Game._shallHighlightMatch_SS # ************************************************************************ # * Free Fan # ************************************************************************ class FreeFan(Fan): RowStack_Class = FullStackWrapper(SuperMoveSS_RowStack, base_rank=KING) Solver_Class = FreeCellSolverWrapper(esf='kings', sbb='suit') def createGame(self): Fan.createGame(self, reserves=2, playcards=8) # ************************************************************************ # * Box Fan # ************************************************************************ class BoxFan(Fan): RowStack_Class = KingAC_RowStack Solver_Class = FreeCellSolverWrapper(esf='kings') def createGame(self): Fan.createGame(self, rows=(4, 4, 4, 4)) def startGame(self): self._startDealNumRows(2) self.s.talon.dealRow() self.s.talon.dealRow(rows=self.s.foundations) def _shuffleHook(self, cards): # move Aces to bottom of the Talon (i.e. last cards to be dealt) return self._shuffleHookMoveToBottom( cards, lambda c: (c.rank == 0, c.suit)) shallHighlightMatch = Game._shallHighlightMatch_AC # ************************************************************************ # * Troika # ************************************************************************ class Troika(Fan): RowStack_Class = StackWrapper(RK_RowStack, dir=0, base_rank=NO_RANK, max_cards=3) def createGame(self): Fan.createGame(self, rows=(6, 6, 6), playcards=4) def shallHighlightMatch(self, stack1, card1, stack2, card2): return card1.rank == card2.rank def startGame(self, ncards=3): self.startDealSample() for r in self.s.rows: for i in range(ncards): if not self.s.talon.cards: break c = self.s.talon.cards[-1] t = r if c.rank == ACE: t = self.s.foundations[c.suit] self.s.talon.dealRow(rows=[t], frames=4) class Quads_RowStack(RK_RowStack): getBottomImage = Stack._getReserveBottomImage class Quads(Troika): RowStack_Class = FullStackWrapper( Quads_RowStack, dir=0, # base_rank=NO_RANK, max_cards=4) def createGame(self): Fan.createGame(self, rows=(5, 5, 3), playcards=5) def startGame(self): Troika.startGame(self, ncards=4) class QuadsPlus(Quads): def _shuffleHook(self, cards): return self._shuffleHookMoveToTop(cards, lambda c: (c.rank == ACE, c.suit)) def startGame(self): self.s.talon.dealRow(rows=self.s.foundations, frames=0) for i in range(3): self.s.talon.dealRow(rows=self.s.rows[:-1], frames=0) self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:-1]) # ************************************************************************ # * Fascination Fan # ************************************************************************ class FascinationFan_Talon(RedealTalonStack): def dealCards(self, sound=False): RedealTalonStack.redealCards(self, shuffle=True, sound=sound) class FascinationFan(Fan): Talon_Class = StackWrapper(FascinationFan_Talon, max_rounds=7) # Talon_Class = StackWrapper(LaBelleLucie_Talon, max_rounds=7) RowStack_Class = StackWrapper(AC_RowStack, base_rank=NO_RANK) def createGame(self): Fan.createGame(self, texts=True) def startGame(self): for i in range(2): self.s.talon.dealRow(rows=self.s.rows[:17], flip=0, frames=0) self._startAndDealRow() def redealCards(self): r0 = r1 = len(self.s.talon.cards)//3 m = len(self.s.talon.cards) % 3 if m >= 1: r1 += 1 self.s.talon.dealRow(rows=self.s.rows[:r0], flip=0, frames=4) self.s.talon.dealRow(rows=self.s.rows[:r1], flip=0, frames=4) self.s.talon.dealRowAvail(frames=4) shallHighlightMatch = Game._shallHighlightMatch_AC # ************************************************************************ # * Crescent # ************************************************************************ class Crescent_Talon(RedealTalonStack): def dealCards(self, sound=False): old_state = self.game.enterState(self.game.S_DEAL) ncards = 0 intern1, intern2 = self.game.s.internals if sound and self.game.app.opt.animations: self.game.startDealSample() for r in self.game.s.rows: if len(r.cards) <= 1: continue ncards += len(r.cards) # move cards to internal stacks while len(r.cards) != 1: self.game.moveMove(1, r, intern1, frames=4) self.game.moveMove(1, r, intern2, frames=4) # move back while intern1.cards: self.game.moveMove(1, intern1, r, frames=4) self.game.moveMove(1, intern2, r, frames=4) self.game.nextRoundMove(self) if sound: self.game.stopSamples() self.game.leaveState(old_state) return ncards class Crescent(Game): Hint_Class = CautiousDefaultHint def createGame(self): l, s = Layout(self), self.s playcards = 10 w0 = l.XS+(playcards-1)*l.XOFFSET w, h = l.XM+max(4*w0, 9*l.XS), l.YM+5*l.YS self.setSize(w, h) x, y = l.XM, l.YM s.talon = Crescent_Talon(x, y, self, max_rounds=4) l.createRoundText(s.talon, 'ne') x, y = w-8*l.XS, l.YM for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) x += l.XS for i in range(4): s.foundations.append(SS_FoundationStack(x, y, self, suit=i, base_rank=KING, dir=-1)) x += l.XS y = l.YM+l.YS for i in range(4): x = l.XM for j in range(4): stack = UD_SS_RowStack(x, y, self, base_rank=NO_RANK, mod=13) s.rows.append(stack) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 x += w0 y += l.YS self.s.internals.append(InvisibleStack(self)) self.s.internals.append(InvisibleStack(self)) l.defaultStackGroups() def _shuffleHook(self, cards): return self._shuffleHookMoveToTop( cards, lambda c: (c.rank in (ACE, KING) and c.deck == 0, (c.rank, c.suit))) def startGame(self): self.s.talon.dealRow(rows=self.s.foundations, frames=0) self._startDealNumRowsAndDealSingleRow(5) shallHighlightMatch = Game._shallHighlightMatch_SSW # ************************************************************************ # * School # ************************************************************************ class School(Fan): Talon_Class = StackWrapper(LaBelleLucie_Talon, max_rounds=3) RowStack_Class = StackWrapper(RK_RowStack, dir=0, base_rank=NO_RANK) def createGame(self): Fan.createGame(self, rows=(4, 4, 4, 4), playcards=10, texts=True) def startGame(self): self._startDealNumRows(2) self.s.talon.dealRow() self.s.talon.dealRow(rows=self.s.foundations) def _shuffleHook(self, cards): # move Aces to bottom of the Talon (i.e. last cards to be dealt) return self._shuffleHookMoveToBottom(cards, lambda c: (c.rank == ACE, c.suit)) def shallHighlightMatch(self, stack1, card1, stack2, card2): return card1.rank == card2.rank # ************************************************************************ # * Forest Glade # ************************************************************************ class ForestGlade_Talon(DealRowRedealTalonStack): def _redeal(self, rows=None, frames=0): # move all cards to the talon num_cards = 0 if rows is None: rows = self.game.s.rows for r in rows: for i in range(len(r.cards)): num_cards += 1 self.game.moveMove(1, r, self, frames=frames, shadow=0) if self.cards[-1].face_up: self.game.flipMove(self) return num_cards def canDealCards(self): if self.round == self.max_rounds: if not self.cards: return False for r in self.game.s.rows: if not r.cards: return True return False return True def dealCards(self, sound=False): rows = [r for r in self.game.s.rows if not r.cards] if not rows or not self.cards: if sound and self.game.app.opt.animations: self.game.startDealSample() # move all cards to the talon ncards = self._redeal(frames=4) # shuffle self.game.shuffleStackMove(self) # deal if self.cards: for r in self.game.s.rows: for i in range(3): if not self.cards: break ncards += self.dealRowAvail(rows=[r], frames=4) # self.game.nextRoundMove(self) if sound: self.game.stopSamples() return ncards # if sound and self.game.app.opt.animations: self.game.startDealSample() ncards = 0 for r in rows: for i in range(3): if not self.cards: break ncards += self.dealRowAvail(rows=[r], sound=False) if sound: self.game.stopSamples() return ncards class ForestGlade(Game): Hint_Class = CautiousDefaultHint def createGame(self): l, s = Layout(self), self.s playcards = 7 w0 = l.XS+(playcards-1)*l.XOFFSET w, h = l.XM + 3*w0 + 4*l.XS, l.YM+6*l.YS self.setSize(w, h) x1, x2 = l.XM, self.width - 2*l.XS for i in range(2): y = l.YM for j in range(4): s.foundations.append(SS_FoundationStack(x1, y, self, suit=j, dir=2, max_cards=7)) s.foundations.append(SS_FoundationStack(x2, y, self, base_rank=1, suit=j, dir=2, max_cards=6)) y += l.YS x1 += l.XS x2 += l.XS x, y = l.XM + 3*l.XS, l.YM for i in (0, 1): stack = SS_RowStack(x, y, self, max_move=1, base_rank=KING) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 s.rows.append(stack) x += w0 y = l.YM+l.YS for i in range(4): x = l.XM + 2*l.XS for j in range(3): stack = SS_RowStack(x, y, self, max_move=1, base_rank=KING) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 s.rows.append(stack) x += w0 y += l.YS x, y = l.XM + 3*l.XS, l.YM + 5*l.YS for i in (0, 1): stack = SS_RowStack(x, y, self, max_move=1, base_rank=KING) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 s.rows.append(stack) x += w0 x, y = l.XM, self.height - l.YS s.talon = ForestGlade_Talon(x, y, self, max_rounds=3) l.createText(s.talon, 'ne') l.createRoundText(s.talon, 'se') l.defaultStackGroups() def startGame(self): self._startDealNumRowsAndDealSingleRow(2) shallHighlightMatch = Game._shallHighlightMatch_SS # register the game registerGame(GameInfo(56, FanGame, "Fan", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(87, ScotchPatience, "Scotch Patience", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(57, Shamrocks, "Shamrocks", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(901, LaBelleLucie, "La Belle Lucie", # was: 32, 82 GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 2, GI.SL_MOSTLY_SKILL, altnames=("Fair Lucy", "Midnight Oil"))) registerGame(GameInfo(132, SuperFlowerGarden, "Super Flower Garden", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 2, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(128, ThreeShufflesAndADraw, "Three Shuffles and a Draw", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 2, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(88, Trefoil, "Trefoil", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 2, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(227, Intelligence, "Intelligence", GI.GT_FAN_TYPE, 2, 2, GI.SL_BALANCED)) registerGame(GameInfo(340, IntelligencePlus, "Intelligence +", GI.GT_FAN_TYPE, 2, 2, GI.SL_BALANCED)) registerGame(GameInfo(268, HouseInTheWood, "House in the Wood", GI.GT_FAN_TYPE | GI.GT_OPEN, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(317, HouseOnTheHill, "House on the Hill", GI.GT_FAN_TYPE | GI.GT_OPEN, 2, 0, GI.SL_MOSTLY_SKILL, rules_filename='houseinthewood.html')) registerGame(GameInfo(320, CloverLeaf, "Clover Leaf", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(347, FreeFan, "Free Fan", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(385, BoxFan, "Box Fan", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(516, Troika, "Troika", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(517, Quads, "Quads", GI.GT_FAN_TYPE | GI.GT_OPEN | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(625, FascinationFan, "Fascination Fan", GI.GT_FAN_TYPE, 1, 6, GI.SL_BALANCED, altnames=('Demon Fan',))) registerGame(GameInfo(647, Crescent, "Crescent", GI.GT_FAN_TYPE, 2, 3, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(714, ShamrocksII, "Shamrocks II", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(719, School, "School", GI.GT_FAN_TYPE, 1, 2, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(739, ForestGlade, "Forest Glade", GI.GT_FAN_TYPE, 2, 2, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(767, QuadsPlus, "Quads +", GI.GT_FAN_TYPE | GI.GT_OPEN | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL))