1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00

+ 4 new games

+ added `close stack' (Game.closeStackMove, Stack.closeStackMove, ACloseStackMove)
+ option `shade_filled_stacks'
+ new stack RedealTalonStack and new Game method redealCards
* added closeStackMove to PileOn and PictureGallery (used flipAllMove)


git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@21 39dd0a4e-7c14-0410-91b3-c4f2d318f732
This commit is contained in:
skomoroh 2006-07-19 21:17:01 +00:00
parent e97a944692
commit d71672694a
26 changed files with 366 additions and 80 deletions

View file

@ -146,3 +146,10 @@ class AbstractCard:
def updateCardBackground(self, image): def updateCardBackground(self, image):
raise SubclassResponsibility raise SubclassResponsibility
def close(self):
pass
def unclose(self):
pass

View file

@ -122,6 +122,7 @@ class PysolMenubarActions:
animations = IntVar(), animations = IntVar(),
shadow = BooleanVar(), shadow = BooleanVar(),
shade = BooleanVar(), shade = BooleanVar(),
shade_filled_stacks = BooleanVar(),
toolbar = IntVar(), toolbar = IntVar(),
toolbar_style = StringVar(), toolbar_style = StringVar(),
toolbar_relief = StringVar(), toolbar_relief = StringVar(),
@ -164,6 +165,7 @@ class PysolMenubarActions:
tkopt.highlight_cards.set(opt.highlight_cards) tkopt.highlight_cards.set(opt.highlight_cards)
tkopt.highlight_samerank.set(opt.highlight_samerank) tkopt.highlight_samerank.set(opt.highlight_samerank)
tkopt.highlight_not_matching.set(opt.highlight_not_matching) tkopt.highlight_not_matching.set(opt.highlight_not_matching)
tkopt.shade_filled_stacks.set(opt.shade_filled_stacks)
tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed) tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed)
tkopt.shisen_show_hint.set(opt.shisen_show_hint) tkopt.shisen_show_hint.set(opt.shisen_show_hint)
tkopt.sound.set(opt.sound) tkopt.sound.set(opt.sound)
@ -853,6 +855,12 @@ class PysolMenubarActions:
self.app.opt.highlight_not_matching = self.tkopt.highlight_not_matching.get() self.app.opt.highlight_not_matching = self.tkopt.highlight_not_matching.get()
##self.game.updateMenus() ##self.game.updateMenus()
def mOptShadeFilledStacks(self, *args):
if self._cancelDrag(break_pause=False): return
self.app.opt.shade_filled_stacks = self.tkopt.shade_filled_stacks.get()
self.game.endGame(bookmark=1)
self.game.quitGame(bookmark=1)
def mOptMahjonggShowRemoved(self, *args): def mOptMahjonggShowRemoved(self, *args):
if self._cancelDrag(): return if self._cancelDrag(): return
self.app.opt.mahjongg_show_removed = self.tkopt.mahjongg_show_removed.get() self.app.opt.mahjongg_show_removed = self.tkopt.mahjongg_show_removed.get()

View file

@ -102,6 +102,7 @@ class Options:
self.animations = 2 # default to Timer based self.animations = 2 # default to Timer based
self.shadow = 1 self.shadow = 1
self.shade = 1 self.shade = 1
self.shade_filled_stacks = True
self.demo_logo = 1 self.demo_logo = 1
self.demo_score = 0 self.demo_score = 0
self.toolbar = 1 self.toolbar = 1

View file

@ -62,6 +62,7 @@ from pysoltk import Card
from move import AMoveMove, AFlipMove, ATurnStackMove from move import AMoveMove, AFlipMove, ATurnStackMove
from move import ANextRoundMove, ASaveSeedMove, AShuffleStackMove from move import ANextRoundMove, ASaveSeedMove, AShuffleStackMove
from move import AUpdateStackMove, AFlipAllMove, ASaveStateMove from move import AUpdateStackMove, AFlipAllMove, ASaveStateMove
from move import ACloseStackMove
from hint import DefaultHint from hint import DefaultHint
from help import helpAbout from help import helpAbout
@ -177,6 +178,12 @@ class Game:
if self.s.talon: if self.s.talon:
assert hasattr(self.s.talon, "round") assert hasattr(self.s.talon, "round")
assert hasattr(self.s.talon, "max_rounds") assert hasattr(self.s.talon, "max_rounds")
if self.app.debug and self.s.foundations:
ncards = 0
for stack in self.s.foundations:
ncards += stack.cap.max_cards
if ncards != self.gameinfo.ncards:
print 'WARNING: invalid sum of foundations.max_cards:', self.__class__.__name__, ncards, self.gameinfo.ncards
# optimize regions # optimize regions
self.optimizeRegions() self.optimizeRegions()
# create cards # create cards
@ -987,6 +994,8 @@ class Game:
def getCardBackImage(self, deck, suit, rank): def getCardBackImage(self, deck, suit, rank):
return self.app.images.getBack(deck, suit, rank) return self.app.images.getBack(deck, suit, rank)
def getCardShadeImage(self):
return self.app.images.getShade()
# #
# layout support # layout support
@ -1085,6 +1094,10 @@ class Game:
def fillStack(self, stack): def fillStack(self, stack):
pass pass
# redeal cards (used in RedealTalonStack; all cards already in talon)
def redealCards(self):
pass
# the actual hint class (or None) # the actual hint class (or None)
Hint_Class = DefaultHint Hint_Class = DefaultHint
@ -1931,7 +1944,7 @@ for %d moves.
# move type 8 # move type 8
def flipAllMove(self, stack): def flipAllMove(self, stack):
assert stack assert stack
am = AFlipAllMove(self, stack) am = AFlipAllMove(stack)
self.__storeMove(am) self.__storeMove(am)
am.do(self) am.do(self)
self.hints.list = None self.hints.list = None
@ -1943,6 +1956,13 @@ for %d moves.
am.do(self) am.do(self)
##self.hints.list = None ##self.hints.list = None
# move type 10
def closeStackMove(self, stack):
assert stack
am = ACloseStackMove(stack)
self.__storeMove(am)
am.do(self)
# Finish the current move. # Finish the current move.
def finishMove(self): def finishMove(self):
@ -2244,7 +2264,10 @@ Please report this bug."""))
if not game.canLoadGame(version_tuple, game_version): if not game.canLoadGame(version_tuple, game_version):
destruct(game) destruct(game)
game = None game = None
assert game is not None, "Cannot load this game from version " + version + "\nas the game rules have changed\nin the current implementation." assert game is not None, '''\
Cannot load this game from version %s
as the game rules have changed
in the current implementation.''' % version
game.version = version game.version = version
game.version_tuple = version_tuple game.version_tuple = version_tuple
# #

View file

@ -422,7 +422,7 @@ class Amazons(Game):
l.createText(s.talon, "ss") l.createText(s.talon, "ss")
x, y = l.XM+2*l.XS, l.YM x, y = l.XM+2*l.XS, l.YM
for i in range(4): for i in range(4):
s.foundations.append(Amazons_Foundation(x, y, self, suit=i)) s.foundations.append(Amazons_Foundation(x, y, self, suit=i, max_cards=7))
x += l.XS x += l.XS
x, y = l.XM+2*l.XS, l.YM+l.YS x, y = l.XM+2*l.XS, l.YM+l.YS
for i in range(4): for i in range(4):

View file

@ -174,7 +174,7 @@ class Braid(Game):
s.foundations.append(cl(x, y, self, suit=i)) s.foundations.append(cl(x, y, self, suit=i))
x += l.XS x += l.XS
y = y + l.YS y = y + l.YS
x = 8*l.XS+decks*l.XS/2 x = 8*l.XS+decks*l.XS/2+l.XM/2
self.texts.info = MfxCanvasText(self.canvas, self.texts.info = MfxCanvasText(self.canvas,
x, y, anchor="n", x, y, anchor="n",
font=self.app.getFont("canvas_default")) font=self.app.getFont("canvas_default"))

View file

@ -241,7 +241,7 @@ class Arachnida(CurdsAndWhey):
s.rows.append(stack) s.rows.append(stack)
x += l.XS x += l.XS
s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT, s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT,
max_accept=0)) max_accept=0, max_cards=104))
l.createText(s.foundations[0], "ss") l.createText(s.foundations[0], "ss")
# define stack-groups # define stack-groups

View file

@ -98,7 +98,7 @@ class DieBoeseSieben(Game):
# create stacks # create stacks
for i in range(8): for i in range(8):
x, y, = l.XM + i*l.XS, l.YM x, y, = l.XM + i*l.XS, l.YM
s.foundations.append(DieRussische_Foundation(x, y, self, i/2, max_move=0)) s.foundations.append(DieRussische_Foundation(x, y, self, i/2, max_move=0, max_cards=8))
for i in range(rows): for i in range(rows):
x, y, = l.XM + (2*i+8-rows)*l.XS/2, l.YM + l.YS x, y, = l.XM + (2*i+8-rows)*l.XS/2, l.YM + l.YS
s.rows.append(AC_RowStack(x, y, self)) s.rows.append(AC_RowStack(x, y, self))

View file

@ -768,6 +768,36 @@ class Squadron(FortyThieves):
self.s.talon.dealCards() # deal first card to WasteStack self.s.talon.dealCards() # deal first card to WasteStack
# /***********************************************************************
# // Waterloo
# ************************************************************************/
class Waterloo(FortyThieves):
RowStack_Class = Spider_SS_RowStack
ROW_MAX_MOVE = UNLIMITED_MOVES
DEAL = (0, 1)
def createGame(self):
FortyThieves.createGame(self, rows=6)
def _shuffleHook(self, cards):
# move Aces to top of the Talon (i.e. first cards to be dealt)
return self._shuffleHookMoveToTop(cards,
lambda c: (c.rank == ACE, (c.deck, c.suit)))
def startGame(self):
self.startDealSample()
self.s.talon.dealRow(rows=self.s.foundations)
self.s.talon.dealRow()
self.s.talon.dealCards() # deal first card to WasteStack
def getQuickPlayScore(self, ncards, from_stack, to_stack):
if to_stack.cards:
return int(from_stack.cards[-1].suit == to_stack.cards[-1].suit)+1
return 0
# register the game # register the game
registerGame(GameInfo(13, FortyThieves, "Forty Thieves", registerGame(GameInfo(13, FortyThieves, "Forty Thieves",
@ -855,5 +885,7 @@ registerGame(GameInfo(528, FinalBattle, "Final Battle",
GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED)) GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(529, SanJuanHill, "San Juan Hill", registerGame(GameInfo(529, SanJuanHill, "San Juan Hill",
GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED)) GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(540, Waterloo, "Waterloo",
GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED))

View file

@ -543,6 +543,19 @@ class OceanTowers(TripleFreecell):
return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1 return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1
# /***********************************************************************
# // KingCell
# ************************************************************************/
class KingCell_RowStack(RK_RowStack):
def canMoveCards(self, cards):
max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
return len(cards) <= max_move and RK_RowStack.canMoveCards(self, cards)
class KingCell(FreeCell):
Hint_Class = FreeCellType_Hint
RowStack_Class = StackWrapper(KingCell_RowStack, base_rank=KING)
# register the game # register the game
registerGame(GameInfo(5, RelaxedFreeCell, "Relaxed FreeCell", registerGame(GameInfo(5, RelaxedFreeCell, "Relaxed FreeCell",
@ -585,4 +598,6 @@ registerGame(GameInfo(513, OceanTowers, "Ocean Towers",
GI.GT_FREECELL | GI.GT_OPEN | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) GI.GT_FREECELL | GI.GT_OPEN | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(520, GermanFreeCell, "German FreeCell", registerGame(GameInfo(520, GermanFreeCell, "German FreeCell",
GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_SKILL)) GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_SKILL))
registerGame(GameInfo(542, KingCell, "KingCell",
GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))

View file

@ -188,7 +188,7 @@ class DieRussische_RowStack(AC_RowStack):
class DieRussische(Gypsy): class DieRussische(Gypsy):
Talon_Class = InitialDealTalonStack Talon_Class = InitialDealTalonStack
Foundation_Class = StackWrapper(DieRussische_Foundation, min_cards=1) Foundation_Class = StackWrapper(DieRussische_Foundation, min_cards=1, max_cards=8)
RowStack_Class = DieRussische_RowStack RowStack_Class = DieRussische_RowStack
def createGame(self): def createGame(self):

View file

@ -323,6 +323,21 @@ class Canister(Klondike):
self.s.talon.dealRow(rows=self.s.rows[2:6]) self.s.talon.dealRow(rows=self.s.rows[2:6])
class Usk(Somerset):
Talon_Class = RedealTalonStack
RowStack_Class = StackWrapper(AC_RowStack, base_rank=KING)
def createGame(self):
Klondike.createGame(self, max_rounds=2, rows=10, waste=0, texts=0)
def redealCards(self):
n = 0
while self.s.talon.cards:
self.s.talon.dealRowAvail(rows=self.s.rows[n:], frames=4)
n += 1
# /*********************************************************************** # /***********************************************************************
# // Agnes Sorel # // Agnes Sorel
# ************************************************************************/ # ************************************************************************/
@ -376,6 +391,7 @@ class AchtmalAcht(EightTimesEight):
# /*********************************************************************** # /***********************************************************************
# // Batsford # // Batsford
# // Batsford Again
# ************************************************************************/ # ************************************************************************/
class Batsford_ReserveStack(ReserveStack): class Batsford_ReserveStack(ReserveStack):
@ -389,7 +405,8 @@ class Batsford_ReserveStack(ReserveStack):
class Batsford(Klondike): class Batsford(Klondike):
def createGame(self, **layout): def createGame(self, **layout):
l = Klondike.createGame(self, rows=10, max_rounds=1, playcards=22) kwdefault(layout, rows=10, max_rounds=1, playcards=22)
l = apply(Klondike.createGame, (self,), layout)
s = self.s s = self.s
x, y = l.XM, self.height - l.YS x, y = l.XM, self.height - l.YS
s.reserves.append(Batsford_ReserveStack(x, y, self, max_cards=3)) s.reserves.append(Batsford_ReserveStack(x, y, self, max_cards=3))
@ -398,6 +415,11 @@ class Batsford(Klondike):
l.defaultStackGroups() l.defaultStackGroups()
class BatsfordAgain(Batsford):
def createGame(self):
Batsford.createGame(self, max_rounds=2)
# /*********************************************************************** # /***********************************************************************
# // Jumbo # // Jumbo
# ************************************************************************/ # ************************************************************************/
@ -1199,4 +1221,8 @@ registerGame(GameInfo(522, ArticGarden, "Artic Garden",
GI.GT_RAGLAN, 1, 0, GI.SL_MOSTLY_SKILL)) GI.GT_RAGLAN, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(532, GoldRush, "Gold Rush", registerGame(GameInfo(532, GoldRush, "Gold Rush",
GI.GT_KLONDIKE, 1, 2, GI.SL_BALANCED)) GI.GT_KLONDIKE, 1, 2, GI.SL_BALANCED))
registerGame(GameInfo(539, Usk, "Usk",
GI.GT_KLONDIKE, 1, 1, GI.SL_BALANCED))
registerGame(GameInfo(541, BatsfordAgain, "Batsford Again",
GI.GT_KLONDIKE, 2, 1, GI.SL_BALANCED))

View file

@ -135,7 +135,7 @@ class MonteCarlo(Game):
dir=0, base_rank=NO_RANK)) dir=0, base_rank=NO_RANK))
x, y = l.XM + 11*l.XS/2, l.YM x, y = l.XM + 11*l.XS/2, l.YM
s.foundations.append(self.Foundation_Class(x, y, self, suit=ANY_SUIT, s.foundations.append(self.Foundation_Class(x, y, self, suit=ANY_SUIT,
max_move=0, max_cards=52, base_rank=ANY_RANK)) max_move=0, max_cards=self.gameinfo.ncards, base_rank=ANY_RANK))
l.createText(s.foundations[0], "ss") l.createText(s.foundations[0], "ss")
y = y + 2*l.YS y = y + 2*l.YS
s.talon = self.Talon_Class(x, y, self, max_rounds=1) s.talon = self.Talon_Class(x, y, self, max_rounds=1)
@ -598,7 +598,7 @@ class TheWish(Game):
x, y = self.width - l.XS, self.height - l.YS x, y = self.width - l.XS, self.height - l.YS
s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT, s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT,
max_move=0, max_cards=52, max_accept=0, base_rank=ANY_RANK)) max_move=0, max_cards=32, max_accept=0, base_rank=ANY_RANK))
l.createText(s.foundations[0], "nn") l.createText(s.foundations[0], "nn")
# define stack-groups # define stack-groups

View file

@ -137,10 +137,18 @@ class PictureGallery_Foundation(RK_FoundationStack):
def getBottomImage(self): def getBottomImage(self):
return self.game.app.images.getLetter(ACE) return self.game.app.images.getLetter(ACE)
def closeStackMove(self):
if len(self.cards) == 8:
self.game.flipAllMove(self)
def canFlipCard(self):
return False
class PictureGallery_TableauStack(SS_RowStack): class PictureGallery_TableauStack(SS_RowStack):
def __init__(self, x, y, game, base_rank, yoffset, dir=3): def __init__(self, x, y, game, base_rank, yoffset, dir=3, max_cards=4):
SS_RowStack.__init__(self, x, y, game, base_rank=base_rank, dir=dir, max_accept=1) SS_RowStack.__init__(self, x, y, game,
base_rank=base_rank, dir=dir, max_cards=max_cards, max_accept=1)
self.CARD_YOFFSET = yoffset self.CARD_YOFFSET = yoffset
def acceptsCards(self, from_stack, cards): def acceptsCards(self, from_stack, cards):
@ -154,6 +162,13 @@ class PictureGallery_TableauStack(SS_RowStack):
def getBottomImage(self): def getBottomImage(self):
return self.game.app.images.getLetter(self.cap.base_rank) return self.game.app.images.getLetter(self.cap.base_rank)
def closeStackMove(self):
if len(self.cards) == self.cap.max_cards:
self.game.flipAllMove(self)
def canFlipCard(self):
return False
class PictureGallery_RowStack(BasicRowStack): class PictureGallery_RowStack(BasicRowStack):
def acceptsCards(self, from_stack, cards): def acceptsCards(self, from_stack, cards):
@ -176,7 +191,11 @@ class PictureGallery(Game):
Hint_Class = PictureGallery_Hint Hint_Class = PictureGallery_Hint
Foundation_Class = PictureGallery_Foundation Foundation_Class = PictureGallery_Foundation
TableauStack_Class = PictureGallery_TableauStack TableauStack_Classes = [
StackWrapper(PictureGallery_TableauStack, base_rank=3, max_cards=4, dir=3),
StackWrapper(PictureGallery_TableauStack, base_rank=2, max_cards=4, dir=3),
StackWrapper(PictureGallery_TableauStack, base_rank=1, max_cards=4, dir=3),
]
RowStack_Class = StackWrapper(PictureGallery_RowStack, max_accept=1) RowStack_Class = StackWrapper(PictureGallery_RowStack, max_accept=1)
Talon_Class = DealRowTalonStack Talon_Class = DealRowTalonStack
@ -184,7 +203,8 @@ class PictureGallery(Game):
# game layout # game layout
# #
def createGame(self, rows=3, waste=False, dir=3): def createGame(self, waste=False):
rows = len(self.TableauStack_Classes)
# create layout # create layout
l, s = Layout(self), self.s l, s = Layout(self), self.s
TABLEAU_YOFFSET = min(9, max(3, l.YOFFSET / 3)) TABLEAU_YOFFSET = min(9, max(3, l.YOFFSET / 3))
@ -201,10 +221,10 @@ class PictureGallery(Game):
y = l.YM + l.CH / 2 y = l.YM + l.CH / 2
s.foundations.append(self.Foundation_Class(x, y, self)) s.foundations.append(self.Foundation_Class(x, y, self))
y = l.YM y = l.YM
for i in range(rows,0,-1): #(3, 2, 1): for cl in self.TableauStack_Classes:
x = l.XM x = l.XM
for j in range(8): for j in range(8):
s.tableaux.append(self.TableauStack_Class(x, y, self, i, yoffset=TABLEAU_YOFFSET, dir=dir)) s.tableaux.append(cl(x, y, self, yoffset=TABLEAU_YOFFSET))
x = x + l.XS x = x + l.XS
y = y + th y = y + th
x, y = l.XM, y + l.YM x, y = l.XM, y + l.YM
@ -297,7 +317,10 @@ class GreatWheel_RowStack(BasicRowStack):
class GreatWheel(PictureGallery): class GreatWheel(PictureGallery):
Foundation_Class = GreatWheel_Foundation Foundation_Class = GreatWheel_Foundation
TableauStack_Class = PictureGallery_TableauStack TableauStack_Classes = [
StackWrapper(PictureGallery_TableauStack, base_rank=2, max_cards=5, dir=2),
StackWrapper(PictureGallery_TableauStack, base_rank=1, max_cards=6, dir=2),
]
RowStack_Class = StackWrapper(GreatWheel_RowStack, max_accept=1) RowStack_Class = StackWrapper(GreatWheel_RowStack, max_accept=1)
Talon_Class = StackWrapper(WasteTalonStack, max_rounds=1) Talon_Class = StackWrapper(WasteTalonStack, max_rounds=1)
@ -373,12 +396,12 @@ class MountOlympus(Game):
x, y = l.XM+l.XS, l.YM x, y = l.XM+l.XS, l.YM
for i in range(8): for i in range(8):
s.foundations.append(MountOlympus_Foundation(x, y, self, s.foundations.append(MountOlympus_Foundation(x, y, self,
suit=i/2, base_rank=ACE, dir=2, max_move=0)) suit=i/2, base_rank=ACE, dir=2, max_move=0, max_cards=7))
x += l.XS x += l.XS
x, y = l.XM+l.XS, l.YM+l.YS x, y = l.XM+l.XS, l.YM+l.YS
for i in range(8): for i in range(8):
s.foundations.append(MountOlympus_Foundation(x, y, self, s.foundations.append(MountOlympus_Foundation(x, y, self,
suit=i/2, base_rank=1, dir=2, max_move=0)) suit=i/2, base_rank=1, dir=2, max_move=0, max_cards=6))
x += l.XS x += l.XS
x, y = l.XM, l.YM+2*l.YS x, y = l.XM, l.YM+2*l.YS
for i in range(9): for i in range(9):

View file

@ -50,6 +50,13 @@ class PileOn_RowStack(RK_RowStack):
def getBottomImage(self): def getBottomImage(self):
return self.game.app.images.getReserveBottom() return self.game.app.images.getReserveBottom()
def closeStackMove(self):
if len(self.cards) == 4 and isRankSequence(self.cards, dir=0):
self.game.flipAllMove(self)
def canFlipCard(self):
return False
class PileOn(Game): class PileOn(Game):
Hint_Class = DefaultHint Hint_Class = DefaultHint
@ -106,19 +113,20 @@ class PileOn(Game):
def isGameWon(self): def isGameWon(self):
for r in self.s.rows: for r in self.s.rows:
if r.cards: if r.cards and not cardsFaceDown(r.cards):
if len(r.cards) != 4 or not r._isSequence(r.cards): return False
return 0 return True
return 1
def shallHighlightMatch(self, stack1, card1, stack2, card2): def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.rank == card2.rank return card1.rank == card2.rank
class SmallPileOn(PileOn): class SmallPileOn(PileOn):
TWIDTH = 3 TWIDTH = 3
NSTACKS = 11 NSTACKS = 11
PLAYCARDS = 4 PLAYCARDS = 4
class PileOn2Decks(PileOn): class PileOn2Decks(PileOn):
TWIDTH = 4 TWIDTH = 4
NSTACKS = 15 NSTACKS = 15

View file

@ -413,7 +413,7 @@ class BritishConstitution(Game):
# create stacks # create stacks
x, y = l.XM+l.XS, l.YM x, y = l.XM+l.XS, l.YM
for i in range(8): for i in range(8):
s.foundations.append(BritishConstitution_Foundation(x, y, self, suit=int(i/2))) s.foundations.append(BritishConstitution_Foundation(x, y, self, suit=int(i/2), max_cards=11))
x += l.XS x += l.XS
y = l.YM+l.YS y = l.YM+l.YS

View file

@ -136,7 +136,7 @@ class SiebenBisAs(Game):
s.reserves.append(ReserveStack(x, y, self, max_accept=0)) s.reserves.append(ReserveStack(x, y, self, max_accept=0))
for i in range(4): for i in range(4):
x, y, = l.XM + (i+3)*l.XS, l.YM + 4*l.YS x, y, = l.XM + (i+3)*l.XS, l.YM + 4*l.YS
s.foundations.append(SiebenBisAs_Foundation(x, y, self, i, base_rank=6, mod=13, max_move=0)) s.foundations.append(SiebenBisAs_Foundation(x, y, self, i, base_rank=6, mod=13, max_move=0, max_cards=8))
s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self) s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self)
# define stack-groups # define stack-groups

View file

@ -141,7 +141,7 @@ class Pegged(Game):
s.rows.append(stack) s.rows.append(stack)
self.map[stack.pos] = stack self.map[stack.pos] = stack
x, y = self.width - l.XS, l.YM x, y = self.width - l.XS, l.YM
s.foundations.append(AbstractFoundationStack(x, y, self, ANY_SUIT, max_move=0, max_accept=0)) s.foundations.append(AbstractFoundationStack(x, y, self, ANY_SUIT, max_move=0, max_accept=0, max_cards=self.gameinfo.ncards))
l.createText(s.foundations[0], "ss") l.createText(s.foundations[0], "ss")
y = self.height - l.YS y = self.height - l.YS
s.talon = InitialDealTalonStack(x, y, self) s.talon = InitialDealTalonStack(x, y, self)

View file

@ -53,20 +53,20 @@ class Sultan(Game):
self.setSize(w, h) self.setSize(w, h)
# create stacks # create stacks
lay = ((0,0,0,1), lay = ((0,0,0,1,13),
(2,0,0,1), (2,0,0,1,13),
(0,1,1,1), (0,1,1,1,13),
(2,1,1,1), (2,1,1,1,13),
(1,1,2,0), (1,1,2,0,1),
(1,2,2,1), (1,2,2,1,13),
(0,2,3,1), (0,2,3,1,13),
(2,2,3,1), (2,2,3,1,13),
(1,0,2,1), (1,0,2,1,12),
) )
for i, j, suit, max_accept in lay: for i, j, suit, max_accept, max_cards in lay:
x, y = 2*l.XM+l.XS+i*l.XS, l.YM+j*l.YS x, y = 2*l.XM+l.XS+i*l.XS, l.YM+j*l.YS
stack = SS_FoundationStack(x, y, self, suit=suit, stack = SS_FoundationStack(x, y, self, suit=suit,
max_move=0, max_accept=max_accept, mod=13) max_move=0, max_accept=max_accept, max_cards=max_cards, mod=13)
s.foundations.append(stack) s.foundations.append(stack)
x, y = l.XM, l.YM x, y = l.XM, l.YM
@ -309,7 +309,7 @@ class IdleAces(Game):
x, y = x0+i*l.XS, y0+j*l.YS x, y = x0+i*l.XS, y0+j*l.YS
s.foundations.append(RK_FoundationStack(x, y, self, s.foundations.append(RK_FoundationStack(x, y, self,
##suit=ANY_SUIT, ##suit=ANY_SUIT,
base_rank=1, max_move=0)) base_rank=1, max_move=0, max_cards=12))
k += 1 k += 1
k = 0 k = 0
for i, j in((1, 0.2), (3, 0.2), (1, 2.8), (3, 2.8)): for i, j in((1, 0.2), (3, 0.2), (1, 2.8), (3, 2.8)):
@ -635,14 +635,15 @@ class SixesAndSevens(Game):
for i in range(2): for i in range(2):
x = l.XM x = l.XM
for j in range(4): for j in range(4):
s.foundations.append(SS_FoundationStack(x, y, self, suit=j, base_rank=6)) s.foundations.append(SS_FoundationStack(x, y, self,
suit=j, base_rank=6, max_cards=7))
x += l.XS x += l.XS
y += l.YS y += l.YS
for i in range(2): for i in range(2):
x = l.XM x = l.XM
for j in range(4): for j in range(4):
s.foundations.append(SS_FoundationStack(x, y, self, suit=j, s.foundations.append(SS_FoundationStack(x, y, self, suit=j,
base_rank=5, dir=-1)) base_rank=5, dir=-1, max_cards=6))
x += l.XS x += l.XS
y += l.YS y += l.YS
y = l.YM y = l.YM

View file

@ -46,6 +46,10 @@ class TakeAway_Foundation(AbstractFoundationStack):
return (c1.rank == (c2.rank + 1) % mod or return (c1.rank == (c2.rank + 1) % mod or
c2.rank == (c1.rank + 1) % mod) c2.rank == (c1.rank + 1) % mod)
def closeStackMove(self):
pass
class TakeAway(Game): class TakeAway(Game):
RowStack_Class = BasicRowStack RowStack_Class = BasicRowStack

View file

@ -171,17 +171,22 @@ class Odessa(RussianSolitaire):
# // Grandfather # // Grandfather
# ************************************************************************/ # ************************************************************************/
class Grandfather_Talon(RedealTalonStack):
def redealCards(self, sound=0):
RedealTalonStack.redealCards(self, sound=sound, shuffle=True)
class Grandfather(RussianSolitaire): class Grandfather(RussianSolitaire):
Talon_Class = StackWrapper(Grandfather_Talon, max_rounds=3)
def startGame(self): def startGame(self):
n = 1 for i, j in ((1,7),(1,6),(2,6),(2,5),(3,5),(3,4)):
for i in (2,4,6,5,3,1): self.s.talon.dealRowAvail(rows=self.s.rows[i:j], flip=0, frames=0)
self.s.talon.dealRow(rows=[self.s.rows[n]]*i, flip=0, frames=0)
n += 1
n = 0
self.startDealSample() self.startDealSample()
for i in (1,5,5,5,5,5,5): self.s.talon.dealRowAvail()
self.s.talon.dealRow(rows=[self.s.rows[n]]*i) for i in range(4):
n += 1 self.s.talon.dealRowAvail(rows=self.s.rows[1:])
redealCards = startGame
# /*********************************************************************** # /***********************************************************************
@ -644,7 +649,7 @@ registerGame(GameInfo(20, RussianSolitaire, "Russian Solitaire",
registerGame(GameInfo(27, Odessa, "Odessa", registerGame(GameInfo(27, Odessa, "Odessa",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED)) GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(278, Grandfather, "Grandfather", registerGame(GameInfo(278, Grandfather, "Grandfather",
GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_YUKON, 1, 2, GI.SL_BALANCED))
registerGame(GameInfo(186, Alaska, "Alaska", registerGame(GameInfo(186, Alaska, "Alaska",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED)) GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(187, ChineseDiscipline, "Chinese Discipline", registerGame(GameInfo(187, ChineseDiscipline, "Chinese Discipline",

View file

@ -144,7 +144,6 @@ class AFlipAllMove(AtomicMove):
# do the actual move # do the actual move
def __doMove(self, game, stack): def __doMove(self, game, stack):
#card = stack.cards[-1]
for card in stack.cards: for card in stack.cards:
if card.face_up: if card.face_up:
card.showBack() card.showBack()
@ -434,3 +433,28 @@ class AShuffleStackMove(AtomicMove):
cmp(self.card_ids, other.card_ids) or cmp(self.card_ids, other.card_ids) or
cmp(self.state, other.state)) cmp(self.state, other.state))
# /***********************************************************************
# // ACloseStackMove
# ************************************************************************/
class ACloseStackMove(AtomicMove):
def __init__(self, stack):
self.stack_id = stack.id
def redo(self, game):
stack = game.allstacks[self.stack_id]
assert stack.cards
stack.is_closed = True
stack._shadeStack()
def undo(self, game):
stack = game.allstacks[self.stack_id]
assert stack.cards
stack.is_closed = False
stack._unshadeStack()
def cmpForRedo(self, other):
return cmp(self.stack_id, other.stack_id)

View file

@ -45,9 +45,11 @@ __all__ = ['cardsFaceUp',
'Stack', 'Stack',
'DealRow_StackMethods', 'DealRow_StackMethods',
'DealBaseCard_StackMethods', 'DealBaseCard_StackMethods',
'RedealCards_StackMethods',
'TalonStack', 'TalonStack',
'DealRowTalonStack', 'DealRowTalonStack',
'InitialDealTalonStack', 'InitialDealTalonStack',
'RedealTalonStack',
'OpenStack', 'OpenStack',
'AbstractFoundationStack', 'AbstractFoundationStack',
'SS_FoundationStack', 'SS_FoundationStack',
@ -276,10 +278,12 @@ class Stack:
bottom = None, # canvas item bottom = None, # canvas item
redeal = None, # canvas item redeal = None, # canvas item
redeal_img = None, # the corresponding PhotoImage redeal_img = None, # the corresponding PhotoImage
shade_img = None,
) )
# other canvas items # other canvas items
view.items = Struct( view.items = Struct(
bottom = None, # dummy canvas item bottom = None, # dummy canvas item
shade_item = None,
) )
# text items # text items
view.texts = Struct( view.texts = Struct(
@ -296,6 +300,8 @@ class Stack:
view.is_open = -1 view.is_open = -1
view.can_hide_cards = -1 view.can_hide_cards = -1
view.max_shadow_cards = -1 view.max_shadow_cards = -1
#
view.is_closed = False
def destruct(self): def destruct(self):
# help breaking circular references # help breaking circular references
@ -422,6 +428,7 @@ class Stack:
view._position(card) view._position(card)
if update: if update:
view.updateText() view.updateText()
self.closeStackMove()
return card return card
# Remove a card from the stack. Also update display. {model -> view} # Remove a card from the stack. Also update display. {model -> view}
@ -449,6 +456,9 @@ class Stack:
model.cards.remove(card) model.cards.remove(card)
if update: if update:
view.updateText() view.updateText()
if self.is_closed:
self._unshadeStack()
self.is_closed = False
return card return card
# Get the top card {model} # Get the top card {model}
@ -621,6 +631,8 @@ class Stack:
def fillStack(self): def fillStack(self):
self.game.fillStack(self) self.game.fillStack(self)
def closeStackMove(self):
pass
# #
# Playing move actions. Better not override. # Playing move actions. Better not override.
@ -974,6 +986,8 @@ class Stack:
i = self._findCard(event) i = self._findCard(event)
if i < 0 or not self.canMoveCards(self.cards[i:]): if i < 0 or not self.canMoveCards(self.cards[i:]):
return return
if self.is_closed:
self.items.shade_item.config(state='hidden')
x_offset, y_offset = self.cards[i].x, self.cards[i].y x_offset, y_offset = self.cards[i].x, self.cards[i].y
if sound: if sound:
self.game.playSample("startdrag") self.game.playSample("startdrag")
@ -1048,24 +1062,29 @@ class Stack:
return () return ()
cy = c.y cy = c.y
img0, img1 = images.getShadow(0), images.getShadow(l) img0, img1 = images.getShadow(0), images.getShadow(l)
if 0: ## if 0:
# Dynamically compute the shadow. Doesn't work because ## # Dynamically compute the shadow. Doesn't work because
# PhotoImage.copy() doesn't preserve transparency. ## # PhotoImage.copy() doesn't preserve transparency.
img1 = images.getShadow(13) ## img1 = images.getShadow(13)
if img1: ## if img1:
h = images.CARDH - img0.height() ## h = images.CARDH - img0.height()
h = h + (l - 1) * self.CARD_YOFFSET[0] ## h = h + (l - 1) * self.CARD_YOFFSET[0]
if h < img1.height(): ## if h < img1.height():
import Tkinter ## if hasattr(img1, '_pil_image'): # use PIL
dest = Tkinter.PhotoImage(width=img1.width(), height=h) ## import ImageTk
dest.blank() ## im = img1._pil_image.crop((0,0,img1.width(),h))
img1.tk.call(dest, "copy", img1.name, "-from", 0, 0, img1.width(), h) ## img1 = ImageTk.PhotoImage(im)
assert dest.height() == h and dest.width() == img1.width() ## else:
#print h, img1.height(), dest.height() ## import Tkinter
img1 = dest ## dest = Tkinter.PhotoImage(width=img1.width(), height=h)
self._foo = img1 # keep a reference ## dest.blank()
elif h > img1.height(): ## img1.tk.call(dest, "copy", img1.name, "-from", 0, 0, img1.width(), h)
img1 = None ## assert dest.height() == h and dest.width() == img1.width()
## #print h, img1.height(), dest.height()
## img1 = dest
## self._foo = img1 # keep a reference
## elif h > img1.height():
## img1 = None
if img0 and img1: if img0 and img1:
c = cards[-1] c = cards[-1]
if self.CARD_YOFFSET[0] < 0: c = cards[0] if self.CARD_YOFFSET[0] < 0: c = cards[0]
@ -1090,7 +1109,11 @@ class Stack:
# optimized for speed - we use lots of local variables # optimized for speed - we use lots of local variables
game = self.game game = self.game
images = game.app.images images = game.app.images
img = images.getShade() if not self.images.shade_img:
img = images.getShade()
self.images.shade_img = img
else:
img = self.images.shade_img
if img is None: if img is None:
return return
CW, CH = images.CARDW, images.CARDH CW, CH = images.CARDW, images.CARDH
@ -1139,6 +1162,31 @@ class Stack:
else: else:
img.lower(drag.cards[0].item) img.lower(drag.cards[0].item)
# for closeStackMove
def _shadeStack(self):
if not self.game.app.opt.shade_filled_stacks:
return
if not self.images.shade_img:
img = self.game.app.images.getShade()
self.images.shade_img = img
else:
img = self.images.shade_img
if img is None:
return
if not self.items.shade_item:
self.game.canvas.update_idletasks()
card = self.cards[-1]
item = MfxCanvasImage(self.game.canvas, card.x, card.y,
image=img, anchor=ANCHOR_NW)
##item.tkraise()
item.addtag(self.group)
self.items.shade_item = item
def _unshadeStack(self):
if self.items.shade_item:
self.items.shade_item.delete()
self.items.shade_item = None
def _stopDrag(self): def _stopDrag(self):
drag = self.game.drag drag = self.game.drag
after_cancel(drag.timer) after_cancel(drag.timer)
@ -1151,6 +1199,9 @@ class Stack:
drag.shadows = [] drag.shadows = []
drag.stack = None drag.stack = None
drag.cards = [] drag.cards = []
if self.is_closed:
self.items.shade_item.config(state='normal')
self.items.shade_item.tkraise()
# finish a drag operation # finish a drag operation
def finishDrag(self, event=None): def finishDrag(self, event=None):
@ -1173,8 +1224,7 @@ class Stack:
self.moveCardsBackHandler(event, drag) self.moveCardsBackHandler(event, drag)
def getHelp(self): def getHelp(self):
# devel return str(self) # debug
return str(self)
def getBaseCard(self): def getBaseCard(self):
return '' return ''
@ -1319,11 +1369,46 @@ class DealBaseCard_StackMethods:
ncards = ncards - 1 ncards = ncards - 1
class RedealCards_StackMethods:
def redealCards(self, sound=0, shuffle=False, reverse=False, frames=4):
if sound and self.game.app.opt.animations:
self.game.startDealSample()
lr = len(self.game.s.rows)
# move all cards to the Talon
num_cards = 0
assert len(self.cards) == 0
rows = list(self.game.s.rows)[:]
if reverse:
rows.reverse()
for r in rows:
for i in range(len(r.cards)):
num_cards += 1
self.game.moveMove(1, r, self, frames=0)
if self.cards[-1].face_up:
self.game.flipMove(self)
assert len(self.cards) == num_cards
if num_cards == 0: # game already finished
return 0
if shuffle:
# shuffle
self.game.shuffleStackMove(self)
# redeal
self.game.nextRoundMove(self)
self.game.redealCards()
if sound:
self.game.stopSamples()
return num_cards
# /*********************************************************************** # /***********************************************************************
# // The Talon is a stack with support for dealing. # // The Talon is a stack with support for dealing.
# ************************************************************************/ # ************************************************************************/
class TalonStack(Stack, DealRow_StackMethods, DealBaseCard_StackMethods): class TalonStack(Stack,
DealRow_StackMethods,
DealBaseCard_StackMethods,
):
def __init__(self, x, y, game, max_rounds=1, num_deal=1, **cap): def __init__(self, x, y, game, max_rounds=1, num_deal=1, **cap):
Stack.__init__(self, x, y, game, cap=cap) Stack.__init__(self, x, y, game, cap=cap)
self.max_rounds = max_rounds self.max_rounds = max_rounds
@ -1361,8 +1446,8 @@ class TalonStack(Stack, DealRow_StackMethods, DealBaseCard_StackMethods):
def removeAllCards(self): def removeAllCards(self):
for stack in self.game.allstacks: for stack in self.game.allstacks:
while stack.cards: while stack.cards:
##stack.removeCard(update=0) stack.removeCard(update=0)
stack.removeCard(unhide=0, update=0) ##stack.removeCard(unhide=0, update=0)
for stack in self.game.allstacks: for stack in self.game.allstacks:
stack.updateText() stack.updateText()
@ -1461,6 +1546,15 @@ class InitialDealTalonStack(TalonStack):
return None return None
class RedealTalonStack(TalonStack, RedealCards_StackMethods):
def canDealCards(self):
if self.round == self.max_rounds:
return False
return not self.game.isGameWon()
def dealCards(self, sound=0):
RedealCards_StackMethods.redealCards(self, sound=sound)
# /*********************************************************************** # /***********************************************************************
# // An OpenStack is a stack where cards can be placed and dragged # // An OpenStack is a stack where cards can be placed and dragged
# // (i.e. FoundationStack, RowStack, ReserveStack, ...) # // (i.e. FoundationStack, RowStack, ReserveStack, ...)
@ -1646,6 +1740,10 @@ class AbstractFoundationStack(OpenStack):
def getBaseCard(self): def getBaseCard(self):
return self._getBaseCard() return self._getBaseCard()
def closeStackMove(self):
if len(self.cards) == self.cap.max_cards:
self.game.closeStackMove(self)
# A SameSuit_FoundationStack is the typical Foundation stack. # A SameSuit_FoundationStack is the typical Foundation stack.
# It builds up in rank and suit. # It builds up in rank and suit.

View file

@ -115,8 +115,10 @@ class _OneImageCard(_HideableCard):
_HideableCard.__init__(self, id, deck, suit, rank, game, x=x, y=y) _HideableCard.__init__(self, id, deck, suit, rank, game, x=x, y=y)
self._face_image = game.getCardFaceImage(deck, suit, rank) self._face_image = game.getCardFaceImage(deck, suit, rank)
self._back_image = game.getCardBackImage(deck, suit, rank) self._back_image = game.getCardBackImage(deck, suit, rank)
self._shade_image = game.getCardShadeImage()
self._active_image = self._back_image self._active_image = self._back_image
self.item = MfxCanvasImage(game.canvas, self.x, self.y, image=self._active_image, anchor="nw") self.item = MfxCanvasImage(game.canvas, self.x, self.y, image=self._active_image, anchor="nw")
self.shade_item = None
##self._setImage = self.item.config ##self._setImage = self.item.config
def _setImage(self, image): def _setImage(self, image):
@ -153,6 +155,7 @@ class _OneImageCard(_HideableCard):
item.canvas.tk.call(item.canvas._w, "move", item.id, dx, dy) item.canvas.tk.call(item.canvas._w, "move", item.id, dx, dy)
# /*********************************************************************** # /***********************************************************************
# // New idea since 3.00 # // New idea since 3.00
# // # //

View file

@ -335,8 +335,8 @@ class PysolMenubar(PysolMenubarActions):
submenu.add_checkbutton(label=n_("Enable highlight same &rank"), variable=self.tkopt.highlight_samerank, command=self.mOptEnableHighlightSameRank) submenu.add_checkbutton(label=n_("Enable highlight same &rank"), variable=self.tkopt.highlight_samerank, command=self.mOptEnableHighlightSameRank)
submenu.add_checkbutton(label=n_("Highlight &no matching"), variable=self.tkopt.highlight_not_matching, command=self.mOptEnableHighlightNotMatching) submenu.add_checkbutton(label=n_("Highlight &no matching"), variable=self.tkopt.highlight_not_matching, command=self.mOptEnableHighlightNotMatching)
submenu.add_separator() submenu.add_separator()
submenu.add_checkbutton(label=n_("Show removed tiles (in Mahjongg games)"), variable=self.tkopt.mahjongg_show_removed, command=self.mOptMahjonggShowRemoved) submenu.add_checkbutton(label=n_("&Show removed tiles (in Mahjongg games)"), variable=self.tkopt.mahjongg_show_removed, command=self.mOptMahjonggShowRemoved)
submenu.add_checkbutton(label=n_("Show hint arrow (in Shisen-Sho games)"), variable=self.tkopt.shisen_show_hint, command=self.mOptShisenShowHint) submenu.add_checkbutton(label=n_("Show hint &arrow (in Shisen-Sho games)"), variable=self.tkopt.shisen_show_hint, command=self.mOptShisenShowHint)
menu.add_separator() menu.add_separator()
label = n_("&Sound...") label = n_("&Sound...")
if self.app.audio.audiodev is None: if self.app.audio.audiodev is None:
@ -354,6 +354,7 @@ class PysolMenubar(PysolMenubarActions):
submenu.add_checkbutton(label=n_("Card shado&w"), variable=self.tkopt.shadow, command=self.mOptShadow) submenu.add_checkbutton(label=n_("Card shado&w"), variable=self.tkopt.shadow, command=self.mOptShadow)
submenu.add_checkbutton(label=n_("Shade &legal moves"), variable=self.tkopt.shade, command=self.mOptShade) submenu.add_checkbutton(label=n_("Shade &legal moves"), variable=self.tkopt.shade, command=self.mOptShade)
submenu.add_checkbutton(label=n_("&Negative cards bottom"), variable=self.tkopt.negative_bottom, command=self.mOptNegativeBottom) submenu.add_checkbutton(label=n_("&Negative cards bottom"), variable=self.tkopt.negative_bottom, command=self.mOptNegativeBottom)
submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks)
submenu = MfxMenu(menu, label=n_("A&nimations")) submenu = MfxMenu(menu, label=n_("A&nimations"))
submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations) submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations)
submenu.add_radiobutton(label=n_("&Timer based"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations) submenu.add_radiobutton(label=n_("&Timer based"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations)

View file

@ -222,10 +222,17 @@ class MfxCanvas(Tkinter.Canvas):
if stack.cards[i].item.tag in current: if stack.cards[i].item.tag in current:
return i return i
else: else:
current = self.find("withtag", "current") # get item ids ## current = self.find("withtag", "current") # get item ids
for i in range(len(stack.cards)): ## for i in range(len(stack.cards)):
if stack.cards[i].item.id in current: ## if stack.cards[i].item.id in current:
return i ## return i
x, y = event.x, event.y
items = list(self.find_overlapping(x,y,x,y))
items.reverse()
for item in items:
for i in range(len(stack.cards)):
if stack.cards[i].item.id == item:
return i
return -1 return -1
def setTextColor(self, color): def setTextColor(self, color):