From 06ac5b6386d6fdc86a1808b5606ec4e148a7ca59 Mon Sep 17 00:00:00 2001 From: skomoroh Date: Wed, 26 Jul 2006 21:10:13 +0000 Subject: [PATCH] + new file pysollib/games/grandduchess.py + 7 new games * misc. improvements git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@28 39dd0a4e-7c14-0410-91b3-c4f2d318f732 --- pysollib/app.py | 2 + pysollib/games/__init__.py | 1 + pysollib/games/auldlangsyne.py | 153 +++++++++++++------------------ pysollib/games/fortythieves.py | 60 +++++++++++- pysollib/games/grandduchess.py | 139 ++++++++++++++++++++++++++++ pysollib/games/klondike.py | 6 +- pysollib/games/numerica.py | 29 ++++-- pysollib/games/pileon.py | 87 ++++++++++++++++-- pysollib/games/royalcotillion.py | 23 ++++- pysollib/games/sultan.py | 77 ++++++++-------- pysollib/games/windmill.py | 55 +++++++++-- pysollib/layout.py | 20 ++-- pysollib/stack.py | 9 +- 13 files changed, 495 insertions(+), 166 deletions(-) create mode 100644 pysollib/games/grandduchess.py diff --git a/pysollib/app.py b/pysollib/app.py index 3ca6b47f..e1e49439 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -688,6 +688,8 @@ class Application: else: self.requestCompatibleCardsetType(self.nextgame.id) finally: + # hide main window + self.wm_withdraw() # update options self.opt.last_gameid = id # save options diff --git a/pysollib/games/__init__.py b/pysollib/games/__init__.py index d5b56af9..064b3243 100644 --- a/pysollib/games/__init__.py +++ b/pysollib/games/__init__.py @@ -22,6 +22,7 @@ import fortythieves import freecell import glenwood import golf +import grandduchess import grandfathersclock import gypsy import harp diff --git a/pysollib/games/auldlangsyne.py b/pysollib/games/auldlangsyne.py index fb3a92b2..06e905ca 100644 --- a/pysollib/games/auldlangsyne.py +++ b/pysollib/games/auldlangsyne.py @@ -32,7 +32,6 @@ __all__ = [] # imports -import sys # PySol imports from pysollib.gamedb import registerGame, GameInfo, GI @@ -41,6 +40,8 @@ from pysollib.stack import * from pysollib.game import Game from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from pysollib.pysoltk import MfxCanvasText + # /*********************************************************************** # // Tam O'Shanter @@ -48,26 +49,40 @@ from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint class TamOShanter(Game): Talon_Class = DealRowTalonStack + Foundation_Class = RK_FoundationStack RowStack_Class = StackWrapper(BasicRowStack, max_move=1, max_accept=0) - def createGame(self): + def createGame(self, rows=4, texts=False, yoffset=None): # create layout l, s = Layout(self), self.s # set window - self.setSize(l.XM + 6*l.XS, l.YM + 4*l.YS) + if yoffset is None: + yoffset = l.YOFFSET + max_rows = max(rows, 4*self.gameinfo.decks) + self.setSize(l.XM+(2+max_rows)*l.XS, l.YM+2*l.YS+12*yoffset) # create stacks - x, y, = l.XM, l.YM + if texts: + x, y, = l.XM, l.YM+l.YS/2 + else: + x, y, = l.XM, l.YM s.talon = self.Talon_Class(x, y, self) l.createText(s.talon, "ss") + if texts: + tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') + font = self.app.getFont('canvas_default') + s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, + anchor=ta, font=font) x, y = l.XM+2*l.XS, l.YM - for i in range(4): - s.foundations.append(RK_FoundationStack(x, y, self)) + for i in range(4*self.gameinfo.decks): + s.foundations.append(self.Foundation_Class(x, y, self, suit=i%4)) x += l.XS x, y = l.XM+2*l.XS, l.YM+l.YS - for i in range(4): - s.rows.append(self.RowStack_Class(x, y, self)) + for i in range(rows): + stack = self.RowStack_Class(x, y, self) + s.rows.append(stack) + stack.CARD_YOFFSET = yoffset x += l.XS # define stack-groups @@ -345,25 +360,15 @@ class Colorado(Game): # // Amazons # ************************************************************************/ -class Amazons_Talon(DealRowTalonStack): +class Amazons_Talon(RedealTalonStack): + def canDealCards(self): - ## FIXME: this is to avoid loops in the demo - if self.game.demo and self.game.moves.index >= 100: - return False - if self.round == self.max_rounds: - return False return not self.game.isGameWon() def dealCards(self, sound=0): - self.game.startDealSample() if not self.cards: - self.game.nextRoundMove(self) - n = self._moveAllToTalon() - self.game.stopSamples() - return n - n = self.dealRowAvail() - self.game.stopSamples() - return n + RedealTalonStack.redealCards(self, frames=4, sound=sound) + return self.dealRowAvail(sound=sound) def dealRowAvail(self, rows=None, flip=1, reverse=0, frames=-1, sound=0): if rows is None: @@ -373,19 +378,9 @@ class Amazons_Talon(DealRowTalonStack): if len(f.cards) < 7: rows.append(self.game.s.rows[i]) i += 1 - return DealRowTalonStack.dealRowAvail(self, rows=rows, flip=flip, + return RedealTalonStack.dealRowAvail(self, rows=rows, flip=flip, reverse=reverse, frames=frames, sound=sound) - def _moveAllToTalon(self): - # move all cards to the Talon - num_cards = 0 - for r in self.game.s.rows: - for i in range(len(r.cards)): - num_cards += 1 - self.game.moveMove(1, r, self, frames=4) - self.game.flipMove(self) - return num_cards - class Amazons_Foundation(AbstractFoundationStack): def acceptsCards(self, from_stack, cards): @@ -407,80 +402,60 @@ class Amazons_Foundation(AbstractFoundationStack): return i == j -class Amazons(Game): - - def createGame(self): - # create layout - l, s = Layout(self), self.s - - # set window - self.setSize(l.XM + 6*l.XS, l.YM + 4*l.YS) - - # create stacks - x, y, = l.XM, l.YM - s.talon = Amazons_Talon(x, y, self, max_rounds=-1) - l.createText(s.talon, "ss") - x, y = l.XM+2*l.XS, l.YM - for i in range(4): - s.foundations.append(Amazons_Foundation(x, y, self, suit=i, max_cards=7)) - x += l.XS - x, y = l.XM+2*l.XS, l.YM+l.YS - for i in range(4): - s.rows.append(BasicRowStack(x, y, self, max_move=1, max_accept=0)) - x += l.XS - - # define stack-groups - l.defaultStackGroups() +class Amazons(AuldLangSyne): + Talon_Class = StackWrapper(Amazons_Talon, max_rounds=-1) + Foundation_Class = StackWrapper(Amazons_Foundation, max_cards=7) + def _shuffleHook(self, cards): + return cards def startGame(self): self.startDealSample() self.s.talon.dealRow() - def getAutoStacks(self, event=None): - return ((), (), self.sg.dropstacks) - - # /*********************************************************************** +# // Scuffle # // Acquaintance # ************************************************************************/ -class Acquaintance_Talon(TalonStack): # TalonStack +class Scuffle_Talon(RedealTalonStack): def canDealCards(self): - if self.round == self.max_rounds and not self.cards: - return False + if self.round == self.max_rounds: + return len(self.cards) != 0 return not self.game.isGameWon() - def _redeal(self): - # move all cards to the Talon - lr = len(self.game.s.rows) - num_cards = 0 - assert len(self.cards) == 0 - rows = self.game.s.rows - for r in rows: - for i in range(len(r.cards)): - num_cards = num_cards + 1 - self.game.moveMove(1, r, self, frames=4) - self.game.flipMove(self) - assert len(self.cards) == num_cards - if num_cards == 0: # game already finished - return - self.game.nextRoundMove(self) + def dealCards(self, sound=0, shuffle=True): + if self.cards: + return self.dealRowAvail(sound=sound) + RedealTalonStack.redealCards(self, frames=4, + shuffle=shuffle, sound=sound) + return self.dealRowAvail(sound=sound) + +class Scuffle(AuldLangSyne): + Talon_Class = StackWrapper(Scuffle_Talon, max_rounds=3) + def createGame(self): + AuldLangSyne.createGame(self, texts=True, yoffset=0) + + +class Acquaintance_Talon(Scuffle_Talon): def dealCards(self, sound=0): - if sound: - self.game.startDealSample() - if len(self.cards) == 0: - self._redeal() - n = self.dealRowAvail(sound=sound) - if sound: - self.game.stopSamples() - return n + Scuffle_Talon.dealCards(self, sound=sound, shuffle=False) + class Acquaintance(AuldLangSyne): Talon_Class = StackWrapper(Acquaintance_Talon, max_rounds=3) + def createGame(self, texts=False, yoffset=None): + AuldLangSyne.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) + # register the game @@ -500,4 +475,8 @@ registerGame(GameInfo(406, Amazons, "Amazons", )) registerGame(GameInfo(490, Acquaintance, "Acquaintance", GI.GT_NUMERICA, 1, 2, GI.SL_BALANCED)) +registerGame(GameInfo(553, Scuffle, "Scuffle", + GI.GT_NUMERICA, 1, 2, GI.SL_MOSTLY_LUCK)) +registerGame(GameInfo(560, DoubleAcquaintance, "Double Acquaintance", + GI.GT_NUMERICA, 2, 2, GI.SL_BALANCED)) diff --git a/pysollib/games/fortythieves.py b/pysollib/games/fortythieves.py index 51d6c484..e764b6fc 100644 --- a/pysollib/games/fortythieves.py +++ b/pysollib/games/fortythieves.py @@ -107,10 +107,12 @@ class FortyThieves(Game): s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds, num_deal=num_deal) l.createText(s.talon, "n") if max_rounds > 1: + tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") + font = self.app.getFont("canvas_default") s.talon.texts.rounds = MfxCanvasText(self.canvas, - x + l.CW / 2, y - l.TEXT_HEIGHT, - anchor="s", - font=self.app.getFont("canvas_default")) + tx, ty-l.TEXT_MARGIN, + anchor=ta, + font=font) x = x - l.XS s.waste = WasteStack(x, y, self) s.waste.CARD_XOFFSET = -l.XOFFSET @@ -799,6 +801,55 @@ class Waterloo(FortyThieves): return 0 +# /*********************************************************************** +# // Junction +# ************************************************************************/ + +from gypsy import DieRussische_Foundation + +class Junction(Game): + + def createGame(self, rows=7): + + l, s = Layout(self), self.s + + self.setSize(l.XM+10*l.XS, l.YM+3*l.YS+12*l.YOFFSET) + + y = l.YM + for i in range(2): + x = l.XM+2*l.XS + for j in range(8): + s.foundations.append(DieRussische_Foundation(x, y, self, + suit=j%4, max_cards=8)) + x += l.XS + y += l.YS + + x, y = l.XM+(10-rows)*l.XS/2, l.YM+2*l.YS + for i in range(rows): + s.rows.append(AC_RowStack(x, y, self)) + x += l.XS + + x, y = l.XM, l.YM + s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 'ne') + y += l.YS + s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'ne') + + l.defaultStackGroups() + + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() + + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return card1.color != card2.color and abs(card1.rank-card2.rank) == 1 + + + # register the game registerGame(GameInfo(13, FortyThieves, "Forty Thieves", GI.GT_FORTY_THIEVES, 2, 0, GI.SL_MOSTLY_SKILL, @@ -887,5 +938,8 @@ registerGame(GameInfo(529, SanJuanHill, "San Juan Hill", GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(540, Waterloo, "Waterloo", GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED)) +registerGame(GameInfo(556, Junction, "Junction", + GI.GT_FORTY_THIEVES, 4, 0, GI.SL_MOSTLY_SKILL, + ranks=(0, 6, 7, 8, 9, 10, 11, 12) )) diff --git a/pysollib/games/grandduchess.py b/pysollib/games/grandduchess.py new file mode 100644 index 00000000..57f92061 --- /dev/null +++ b/pysollib/games/grandduchess.py @@ -0,0 +1,139 @@ +##---------------------------------------------------------------------------## +## +## PySol -- a Python Solitaire game +## +## 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 2 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; see the file COPYING. +## If not, write to the Free Software Foundation, Inc., +## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +##---------------------------------------------------------------------------## + +__all__ = [] + +# imports +import sys + +# PySol imports +from pysollib.gamedb import registerGame, GameInfo, GI +from pysollib.util import * +from pysollib.mfxutil import kwdefault +from pysollib.stack import * +from pysollib.game import Game +from pysollib.layout import Layout +from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from pysollib.pysoltk import MfxCanvasText + + +# /*********************************************************************** +# // Grand Duchess +# ************************************************************************/ + +class GrandDuchess_Talon(RedealTalonStack): + + def canDealCards(self): + if self.round == self.max_rounds: + return len(self.cards) != 0 + return not self.game.isGameWon() + + def dealCards(self, sound=0): + rows = self.game.s.rows + reserves = self.game.s.reserves + if not self.cards: + RedealTalonStack.redealCards(self, rows=rows+reserves, sound=0) + if sound and not self.game.demo: + self.game.startDealSample() + num_cards = 0 + if self.round != 4: + num_cards += self.dealRowAvail(rows=[reserves[0]], flip=0) + num_cards += self.dealRowAvail() + if self.round != 4: + num_cards += self.dealRowAvail(rows=[reserves[1]], flip=0) + if not self.cards: + for s in reserves: + self.game.flipAllMove(s) + if sound and not self.game.demo: + self.game.stopSamples() + return num_cards + + +class GrandDuchess_Reserve(ArbitraryStack): + def canFlipCard(self): + return False + + +class GrandDuchess(Game): + + # + # game layout + # + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + w, h = l.XM+9*l.XS, l.YM+2*l.YS+18*l.YOFFSET + 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)) + 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 + x, y = l.XM+2*l.XS, l.YM+l.YS + for i in range(4): + stack = BasicRowStack(x, y, self, max_move=1, max_accept=0) + stack.CARD_YOFFSET = l.YOFFSET + s.rows.append(stack) + x += l.XS + x, y = l.XM, l.YM+l.YS + s.reserves.append(GrandDuchess_Reserve(x, y, self)) + x, y = l.XM+7*l.XS, l.YM+l.YS + s.reserves.append(GrandDuchess_Reserve(x, y, self)) + + x, y = self.width-l.XS, self.height-l.YS + s.talon = GrandDuchess_Talon(x, y, self, max_rounds=4) + l.createText(s.talon, 'n') + tx, ty, ta, tf = l.getTextAttr(s.talon, "nn") + font = self.app.getFont("canvas_default") + s.talon.texts.rounds = MfxCanvasText(self.canvas, + tx, ty-l.TEXT_MARGIN, + anchor=ta, font=font) + # define stack-groups + l.defaultStackGroups() + + + # + # game overrides + # + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow(rows=[self.s.reserves[0]], flip=0) + self.s.talon.dealRow() + self.s.talon.dealRow(rows=[self.s.reserves[1]], flip=0) + + + def getAutoStacks(self, event=None): + return ((), (), self.sg.dropstacks) + + +registerGame(GameInfo(557, GrandDuchess, "Grand Duchess", + GI.GT_2DECK_TYPE, 2, 3)) + + diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py index c61ff190..22985c82 100644 --- a/pysollib/games/klondike.py +++ b/pysollib/games/klondike.py @@ -356,7 +356,8 @@ class AgnesSorel(Klondike): def shallHighlightMatch(self, stack1, card1, stack2, card2): return (card1.color == card2.color and - ((card1.rank + 1) % 13 == card2.rank or (card2.rank + 1) % 13 == card1.rank)) + ((card1.rank + 1) % 13 == card2.rank or + (card2.rank + 1) % 13 == card1.rank)) # /*********************************************************************** @@ -638,7 +639,8 @@ class Jane(Klondike): def shallHighlightMatch(self, stack1, card1, stack2, card2): return (card1.suit == card2.suit and - ((card1.rank + 1) % 13 == card2.rank or (card2.rank + 1) % 13 == card1.rank)) + ((card1.rank + 1) % 13 == card2.rank or + (card2.rank + 1) % 13 == card1.rank)) def _autoDeal(self, sound=1): return 0 diff --git a/pysollib/games/numerica.py b/pysollib/games/numerica.py index ed8d8db8..bc2f0072 100644 --- a/pysollib/games/numerica.py +++ b/pysollib/games/numerica.py @@ -106,29 +106,33 @@ class Numerica(Game): def createGame(self, rows=4): # 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) - self.setSize(l.XM+(1.5+rows)*l.XS+l.XM, l.YM + l.YS + h) + 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 - x, y = x0 + (rows-4)*l.XS/2, l.YM - for i in range(4): + 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, 999999, 999999)) + self.setRegion(s.rows, (x0-l.XS/2, y-l.CH/2, 999999, 999999)) x = l.XM s.talon = WasteTalonStack(x, y, self, max_rounds=1) - s.talon.texts.ncards = MfxCanvasText(self.canvas, - x + l.CW / 2, y - l.YM, - anchor="s", - font=self.app.getFont("canvas_default")) + l.createText(s.talon, 'n') y = y + l.YS s.waste = WasteStack(x, y, self, max_cards=1) @@ -153,6 +157,11 @@ class Numerica(Game): return () +class Numerica2Decks(Numerica): + def createGame(self): + Numerica.createGame(self, rows=6) + + # /*********************************************************************** # // Lady Betty # ************************************************************************/ @@ -642,3 +651,7 @@ registerGame(GameInfo(435, Shifting, "Shifting", GI.GT_NUMERICA, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(472, Strategerie, "Strategerie", GI.GT_NUMERICA, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(558, Numerica2Decks, "Numerica (2 decks)", + GI.GT_NUMERICA, 2, 0, GI.SL_BALANCED)) + + diff --git a/pysollib/games/pileon.py b/pysollib/games/pileon.py index 5ac50258..875019eb 100644 --- a/pysollib/games/pileon.py +++ b/pysollib/games/pileon.py @@ -43,7 +43,7 @@ from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint # /*********************************************************************** -# // +# // PileOn # ************************************************************************/ class PileOn_RowStack(RK_RowStack): @@ -127,10 +127,81 @@ class SmallPileOn(PileOn): PLAYCARDS = 4 -class PileOn2Decks(PileOn): - TWIDTH = 4 - NSTACKS = 15 - PLAYCARDS = 8 +## class PileOn2Decks(PileOn): +## TWIDTH = 4 +## NSTACKS = 15 +## PLAYCARDS = 8 +## registerGame(GameInfo(341, PileOn2Decks, "PileOn (2 decks)", +## GI.GT_2DECK_TYPE | GI.GT_OPEN,, 2, 0)) + + +# /*********************************************************************** +# // Foursome +# // Quartets +# ************************************************************************/ + +class Foursome(Game): + Hint_Class = CautiousDefaultHint + Talon_Class = DealRowTalonStack + + def createGame(self, rows=6, texts=True): + l, s = Layout(self), self.s + max_rows = max(6, rows) + self.setSize(l.XM+max_rows*l.XS, l.YM+3*l.YS+13*l.YOFFSET) + x, y = l.XM+(max_rows-6)*l.XS/2, l.YM + for i in range(4): + s.reserves.append(ReserveStack(x, y, self)) + x += l.XS + x = l.XM+(max_rows-1)*l.XS + s.foundations.append(AbstractFoundationStack(x, y, self, + suit=ANY_SUIT, max_cards=52, max_accept=0)) + x, y = l.XM, l.YM+l.YS + for i in range(rows): + s.rows.append(UD_AC_RowStack(x, y, self, mod=13)) + x += l.XS + s.talon = self.Talon_Class(self.width-l.XS, self.height-l.YS, self) + if texts: + l.createText(s.talon, 'n') + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow(rows=self.s.reserves) + self.s.talon.dealRow() + + def fillStack(self, stack): + if not self.s.reserves[0].cards: + return + rank = self.s.reserves[0].cards[0].rank + for r in self.s.reserves[1:]: + if not r.cards or r.cards[0].rank != rank: + return + old_state = self.enterState(self.S_FILL) + self.playSample("droppair", priority=200) + for r in self.s.reserves: + self.moveMove(1, r, self.s.foundations[0], frames=4) + self.flipMove(self.s.foundations[0]) + self.leaveState(old_state) + + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return (card1.color != card2.color and + ((card1.rank + 1) % 13 == card2.rank or + (card2.rank + 1) % 13 == card1.rank)) + + +class Quartets(Foursome): + Talon_Class = InitialDealTalonStack + + def createGame(self): + Foursome.createGame(self, rows=8, texts=False) + + def startGame(self): + for i in range(5): + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealRowAvail() # register the game @@ -141,7 +212,9 @@ registerGame(GameInfo(289, SmallPileOn, "Small PileOn", GI.GT_1DECK_TYPE | GI.GT_OPEN | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL, ranks=(0, 5, 6, 7, 8, 9, 10, 11, 12), rules_filename = "pileon.html")) -## registerGame(GameInfo(341, PileOn2Decks, "PileOn (2 decks)", -## GI.GT_2DECK_TYPE | GI.GT_OPEN,, 2, 0)) +registerGame(GameInfo(554, Foursome, "Foursome", + GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(555, Quartets, "Quartets", + GI.GT_1DECK_TYPE | GI.GT_OPEN | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/royalcotillion.py b/pysollib/games/royalcotillion.py index 0f405275..b68a7c4d 100644 --- a/pysollib/games/royalcotillion.py +++ b/pysollib/games/royalcotillion.py @@ -222,11 +222,32 @@ class Kingdom(RoyalCotillion): # // Granada # ************************************************************************/ + +class Alhambra_Hint(CautiousDefaultHint): + def _getDropCardScore(self, score, color, r, t, ncards): + return 93000, color + + class Alhambra_RowStack(UD_SS_RowStack): def getBottomImage(self): return self.game.app.images.getReserveBottom() +class Alhambra_Talon__(RedealTalonStack): + + def canDealCards(self): + if self.round == self.max_rounds: + return len(self.cards) != 0 + return not self.game.isGameWon() + + def dealCards(self, sound=0): + if self.cards: + return self.dealRowAvail(sound=sound) + RedealTalonStack.redealCards(self, frames=0, + shuffle=False, sound=sound) + return self.dealRowAvail(sound=sound) + + class Alhambra_Talon(DealRowTalonStack): def canDealCards(self): r_cards = sum([len(r.cards) for r in self.game.s.rows]) @@ -259,7 +280,7 @@ class Alhambra_Talon(DealRowTalonStack): class Alhambra(Game): - Hint_Class = CautiousDefaultHint + Hint_Class = Alhambra_Hint def createGame(self, rows=1): # create layout diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py index 40cdc204..0b38af90 100644 --- a/pysollib/games/sultan.py +++ b/pysollib/games/sultan.py @@ -731,64 +731,63 @@ class CornerSuite(Game): # /*********************************************************************** -# // Scuffle +# // Marshal # ************************************************************************/ -class Scuffle_Talon(RedealTalonStack): - - def canDealCards(self): - if self.round == self.max_rounds: - return len(self.cards) != 0 - return not self.game.isGameWon() - - def dealCards(self, sound=0): - if self.cards: - return self.dealRowAvail(sound=sound) - RedealTalonStack.redealCards(self, shuffle=True, sound=sound) - return self.dealRowAvail(sound=sound) +class Marshal_Hint(CautiousDefaultHint): + def _getDropCardScore(self, score, color, r, t, ncards): + return 93000, color -class Scuffle_RowStack(BasicRowStack): - ##clickHandler = BasicRowStack.doubleclickHandler - pass +class Marshal(Game): - -class Scuffle(Game): + Hint_Class = Marshal_Hint def createGame(self): l, s = Layout(self), self.s - self.setSize(l.XM+6*l.XS, l.YM+2*l.YS) + self.setSize(l.XM+8*l.XS, l.YM+5*l.YS) - s.talon = Scuffle_Talon(l.XM, l.YM+l.YS/2, self, max_rounds=3) - l.createText(s.talon, 's') - tx, ty, ta, tf = l.getTextAttr(s.talon, 'nn') - font = self.app.getFont('canvas_default') - s.talon.texts.rounds = MfxCanvasText(self.canvas, tx, ty, - anchor=ta, font=font) - - x, y = l.XM+2*l.XS, l.YM + x, y = l.XM, l.YM for i in range(4): - s.foundations.append(RK_FoundationStack(x, y, self)) + s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) x += l.XS - x, y = l.XM+2*l.XS, l.YM+l.YS for i in range(4): - stack = Scuffle_RowStack(x, y, self, max_move=1) - s.rows.append(stack) - stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 + s.foundations.append(SS_FoundationStack(x, y, self, + suit=i, base_rank=KING, dir=-1)) x += l.XS + x, y = l.XM, l.YM+l.YS + s.talon = TalonStack(x, y, self) + l.createText(s.talon, 'se') + y = l.YM+l.YS + for i in range(4): + x = l.XM+2*l.XS + for j in range(6): + stack = UD_SS_RowStack(x, y, self, base_rank=NO_RANK) + s.rows.append(stack) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 + x += l.XS + y += l.YS l.defaultStackGroups() - def _shuffleHook(self, cards): - return self._shuffleHookMoveToTop(cards, - lambda c: (c.rank == ACE, c.suit)) - def startGame(self): self.startDealSample() - self.s.talon.dealRow(rows=self.s.foundations) self.s.talon.dealRow() + 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.flipMove(self.s.talon) + self.moveMove(1, self.s.talon, stack) + self.leaveState(old_state) + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + return (card1.suit == card2.suit and + (abs(card1.rank-card2.rank) == 1)) + + # register the game registerGame(GameInfo(330, Sultan, "Sultan", @@ -818,5 +817,5 @@ registerGame(GameInfo(438, SixesAndSevens, "Sixes and Sevens", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(477, CornerSuite, "Corner Suite", GI.GT_2DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) -registerGame(GameInfo(553, Scuffle, "Scuffle", - GI.GT_1DECK_TYPE, 1, 2, GI.SL_MOSTLY_LUCK)) +registerGame(GameInfo(559, Marshal, "Marshal", + GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED)) diff --git a/pysollib/games/windmill.py b/pysollib/games/windmill.py index 1d2057c3..bc267c86 100644 --- a/pysollib/games/windmill.py +++ b/pysollib/games/windmill.py @@ -42,6 +42,9 @@ from pysollib.game import Game from pysollib.layout import Layout from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint +from golf import BlackHole_Foundation + + # /*********************************************************************** # // # ************************************************************************/ @@ -63,10 +66,18 @@ class Windmill_RowStack(ReserveStack): # /*********************************************************************** # // Windmill +# // Dutch Solitaire # ************************************************************************/ class Windmill(Game): + Foundation_Classes = [ + StackWrapper(Windmill_Foundation, mod=13, min_cards=1, max_cards=52), + StackWrapper(Windmill_Foundation, base_rank=KING, dir=-1), + ] + RowStack_Class = Windmill_RowStack + + ROWS_LAYOUT = ((2,0), (2,1), (0,2), (1,2), (3,2), (4,2), (2,3), (2,4)) FILL_STACK = True # @@ -89,16 +100,18 @@ class Windmill(Game): s.waste = WasteStack(x, y, self) l.createText(s.waste, "ss") x0, y0 = x + l.XS, y - for d in ((2,0), (2,1), (0,2), (1,2), (3,2), (4,2), (2,3), (2,4)): + for d in self.ROWS_LAYOUT: x, y = x0 + d[0] * l.XS, y0 + d[1] * l.YS - s.rows.append(Windmill_RowStack(x, y, self)) + stack = self.RowStack_Class(x, y, self) + s.rows.append(stack) + stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 0 x, y = x0 + 2 * l.XS, y0 + 2 * l.YS - s.foundations.append(Windmill_Foundation(x, y, self, - mod=13, min_cards=1, max_cards=52)) + fnd_cls = self.Foundation_Classes[0] + s.foundations.append(fnd_cls(x, y, self)) + fnd_cls = self.Foundation_Classes[1] for d in ((1,0.6), (3,0.6), (1,3.4), (3,3.4)): x, y = x0 + d[0] * l.XS, y0 + d[1] * l.YS - s.foundations.append(Windmill_Foundation(x, y, self, - base_rank=KING, dir=-1)) + s.foundations.append(fnd_cls(x, y, self)) # define stack-groups l.defaultStackGroups() @@ -138,6 +151,34 @@ class Windmill(Game): return ((), (), ()) +class DutchSolitaire_RowStack(UD_RK_RowStack): + def getBottomImage(self): + return self.game.app.images.getReserveBottom() + + +class DutchSolitaire(Windmill): + Foundation_Classes = [ + StackWrapper(BlackHole_Foundation, suit=ANY_SUIT, mod=13, max_cards=UNLIMITED_CARDS), + StackWrapper(BlackHole_Foundation, suit=ANY_SUIT, mod=13, max_cards=UNLIMITED_CARDS), + ] + RowStack_Class = DutchSolitaire_RowStack + + ##ROWS_LAYOUT = ((2,0), (2,1), (0,2), (1,2), (3,2), (4,2), (2,3), (2,4)) + ROWS_LAYOUT = ((2,0), (2,1), (1,2), (3,2), (2,3), (2,4)) + FILL_STACK = False + + def _shuffleHook(self, cards): + return cards + + def startGame(self): + self.startDealSample() + #self.s.talon.dealRow(rows=(self.s.foundations[0],)) + #self.s.talon.dealRow() + self.s.talon.dealCards() # deal first card to WasteStack + + def getAutoStacks(self, event=None): + return (self.sg.dropstacks, self.sg.dropstacks, self.sg.dropstacks) + # /*********************************************************************** # // Napoleon's Tomb @@ -330,4 +371,6 @@ registerGame(GameInfo(483, Czarina, "Czarina", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(484, FourSeasons, "Four Seasons", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) +registerGame(GameInfo(561, DutchSolitaire, "Dutch Solitaire", + GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/layout.py b/pysollib/layout.py index 3b66ca15..aa3e02ce 100644 --- a/pysollib/layout.py +++ b/pysollib/layout.py @@ -121,9 +121,10 @@ class Layout: ##self.RIGHT_MARGIN = layout_x_margin-layout_card_x_space ##self.BOTTOM_MARGIN = layout_y_margin-layout_card_y_space - self.TEXT_MARGIN = 10 - ##self.TEXT_HEIGHT = 30 font = game.app.getFont("canvas_default") + ##self.TEXT_MARGIN = 10 + self.TEXT_MARGIN = font[1] + ##self.TEXT_HEIGHT = 30 self.TEXT_HEIGHT = 18+font[1] self.__dict__.update(kw) @@ -150,29 +151,30 @@ class Layout: def getTextAttr(self, stack, anchor): x, y = 0, 0 + delta_x, delta_y = 4, 4 if stack is not None: x, y = stack.x, stack.y if anchor == "n": - return (x+self.CW/2, y-4, "s", "%d") + return (x+self.CW/2, y-delta_y, "s", "%d") if anchor == "nn": return (x+self.CW/2, y-self.TEXT_MARGIN, "s", "%d") if anchor == "s": - return (x+self.CW/2, y+self.CH+4, "n", "%d") + return (x+self.CW/2, y+self.CH+delta_y, "n", "%d") if anchor == "ss": return (x+self.CW/2, y+self.CH+self.TEXT_MARGIN, "n", "%d") if anchor == "nw": - return (x-self.TEXT_MARGIN, y, "ne", "%d") + return (x-delta_x, y, "ne", "%d") if anchor == "sw": - return (x-self.TEXT_MARGIN, y+self.CH, "se", "%d") + return (x-delta_x, y+self.CH, "se", "%d") f = "%2d" if self.game.gameinfo.decks > 1: f = "%3d" if anchor == "ne": - return (x+self.CW+self.TEXT_MARGIN, y, "nw", f) + return (x+self.CW+delta_x, y, "nw", f) if anchor == "se": - return (x+self.CW+self.TEXT_MARGIN, y+self.CH, "sw", f) + return (x+self.CW+delta_x, y+self.CH, "sw", f) if anchor == "e": - return (x+self.CW+self.TEXT_MARGIN, y+self.CH/2, "w", f) + return (x+self.CW+delta_x, y+self.CH/2, "w", f) raise Exception, anchor def createText(self, stack, anchor, dx=0, dy=0, text_format=""): diff --git a/pysollib/stack.py b/pysollib/stack.py index abaf86c2..3da4d72a 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -1398,7 +1398,8 @@ class DealBaseCard_StackMethods: class RedealCards_StackMethods: - def redealCards(self, rows=None, sound=0, shuffle=False, reverse=False, frames=4): + def redealCards(self, rows=None, sound=0, + shuffle=False, reverse=False, frames=0): if sound and self.game.app.opt.animations: self.game.startDealSample() lr = len(self.game.s.rows) @@ -1413,7 +1414,7 @@ class RedealCards_StackMethods: for r in rows: for i in range(len(r.cards)): num_cards += 1 - self.game.moveMove(1, r, self, frames=0) + self.game.moveMove(1, r, self, frames=frames) if self.cards[-1].face_up: self.game.flipMove(self) assert len(self.cards) == num_cards @@ -1798,11 +1799,11 @@ class SS_FoundationStack(AbstractFoundationStack): # A Rank_FoundationStack builds up in rank and ignores color and suit. class RK_FoundationStack(SS_FoundationStack): def __init__(self, x, y, game, suit=ANY_SUIT, **cap): - apply(SS_FoundationStack.__init__, (self, x, y, game, suit), cap) + apply(SS_FoundationStack.__init__, (self, x, y, game, ANY_SUIT), cap) def assertStack(self): SS_FoundationStack.assertStack(self) - assert self.cap.suit == ANY_SUIT + ##assert self.cap.suit == ANY_SUIT assert self.cap.color == ANY_COLOR def getHelp(self):