1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
PySolFC/pysollib/games/fan.py
Shlomi Fish b44d11c281 flake8
2017-04-19 12:03:45 +03:00

1004 lines
34 KiB
Python

#!/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 <http://www.gnu.org/licenses/>.
#
# ---------------------------------------------------------------------------
__all__ = []
# imports
# PySol imports
from pysollib.mygettext import _
from pysollib.gamedb import registerGame, GameInfo, GI
from pysollib.game import Game
from pysollib.layout import Layout
from pysollib.hint import CautiousDefaultHint
from pysollib.hint import FreeCellSolverWrapper
from pysollib.pysoltk import MfxCanvasText
from pysollib.util import ACE, KING, NO_RANK, UNLIMITED_CARDS
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, \
SuperMoveSS_RowStack, \
TalonStack, \
UD_RK_RowStack, \
UD_SS_RowStack, \
StackWrapper
# ************************************************************************
# *
# ************************************************************************
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.startDealSample()
self.s.talon.dealRow()
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):
l = 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
l.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):
for i in range(2):
self.s.talon.dealRow(frames=0)
self.startDealSample()
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)):
l = Fan.createGame(self, rows)
s = self.s
# add a reserve stack
x, y = s.talon.x - l.XS, s.talon.y
s.reserves.append(
Intelligence_ReserveStack(
x, y, self, max_move=0, max_accept=0,
max_cards=UNLIMITED_CARDS))
l.createText(s.reserves[0], "sw")
l.createRoundText(s.talon, 'nn')
# redefine the stack-groups
l.defaultStackGroups()
def startGame(self):
talon = self.s.talon
for i in range(2):
talon.dealRow(frames=0)
self.startDealSample()
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):
for i in range(2):
self.s.talon.dealRow(frames=0)
self.startDealSample()
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):
for i in range(2):
self.s.talon.dealRow(frames=0)
self.startDealSample()
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.startDealSample()
self.s.talon.dealRow()
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)
for i in range(5):
self.s.talon.dealRow(frames=0)
self.startDealSample()
self.s.talon.dealRow()
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):
for i in range(2):
self.s.talon.dealRow(frames=0)
self.startDealSample()
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):
for i in range(2):
self.s.talon.dealRow(frames=0)
self.startDealSample()
self.s.talon.dealRow()
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))