mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
* added config-file option sound_sample_buffer_size * bugfixes git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@234 efabe8c0-fbe8-4139-b769-b5e6d273206e
1401 lines
47 KiB
Python
1401 lines
47 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
|
|
import sys, math
|
|
|
|
# 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
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Hex A Deck Foundation Stacks
|
|
# ************************************************************************/
|
|
|
|
class HexADeck_FoundationStack(SS_FoundationStack):
|
|
def __init__(self, x, y, game, suit, **cap):
|
|
kwdefault(cap, max_move=0, max_cards=12)
|
|
SS_FoundationStack.__init__(self, x, y, game, suit, **cap)
|
|
|
|
|
|
class HexATrump_Foundation(HexADeck_FoundationStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.basicAcceptsCards(from_stack, cards):
|
|
return 0
|
|
for s in self.game.s.foundations[:3]:
|
|
if len(s.cards) != 16:
|
|
return 0
|
|
return 1
|
|
|
|
|
|
class Merlins_Foundation(AbstractFoundationStack):
|
|
def __init__(self, x, y, game, suit, **cap):
|
|
kwdefault(cap, mod=16, dir=0, base_rank=NO_RANK, max_move=0)
|
|
AbstractFoundationStack.__init__(self, x, y, game, suit, **cap)
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not AbstractFoundationStack.acceptsCards(self, from_stack, cards):
|
|
return 0
|
|
if not self.cards:
|
|
return 1
|
|
stack_dir = self.game.getFoundationDir()
|
|
if stack_dir == 0:
|
|
card_dir = (cards[0].rank - self.cards[-1].rank) % self.cap.mod
|
|
return card_dir in (1, 15)
|
|
else:
|
|
return (self.cards[-1].rank + stack_dir) % self.cap.mod == cards[0].rank
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Hex A Deck Row Stacks
|
|
# ************************************************************************/
|
|
|
|
class HexADeck_OpenStack(OpenStack):
|
|
|
|
def __init__(self, x, y, game, yoffset, **cap):
|
|
kwdefault(cap, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS, dir=-1)
|
|
OpenStack.__init__(self, x, y, game, **cap)
|
|
self.CARD_YOFFSET = yoffset
|
|
|
|
def isRankSequence(self, cards, dir=None):
|
|
if not dir:
|
|
dir = self.cap.dir
|
|
c1 = cards[0]
|
|
for c2 in cards[1:]:
|
|
if not c1.rank + dir == c2.rank:
|
|
return 0
|
|
c1 = c2
|
|
return 1
|
|
|
|
def isAlternateColorSequence(self, cards, dir=None):
|
|
if not dir:
|
|
dir = self.cap.dir
|
|
c1 = cards[0]
|
|
for c2 in cards[1:]:
|
|
if (c1.color < 2 and c1.color == c2.color
|
|
or not c1.rank + dir == c2.rank):
|
|
return 0
|
|
c1 = c2
|
|
return 1
|
|
|
|
def isSuitSequence(self, cards, dir=None):
|
|
if not dir:
|
|
dir = self.cap.dir
|
|
c1 = cards[0]
|
|
for c2 in cards[1:]:
|
|
if not ((c1.color == 2 or c2.color == 2
|
|
or c1.suit == c2.suit)
|
|
and c1.rank + dir == c2.rank):
|
|
return 0
|
|
c1 = c2
|
|
return 1
|
|
|
|
|
|
class HexADeck_RK_RowStack(HexADeck_OpenStack):
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if (not self.basicAcceptsCards(from_stack, cards)
|
|
or not self.isRankSequence(cards)):
|
|
return 0
|
|
if not self.cards:
|
|
return cards[0].rank == 15 or self.cap.base_rank == ANY_RANK
|
|
return self.isRankSequence([self.cards[-1], cards[0]])
|
|
|
|
def canMoveCards(self, cards):
|
|
return (self.basicCanMoveCards(cards)
|
|
and self.isRankSequence(cards))
|
|
|
|
|
|
class HexADeck_AC_RowStack(HexADeck_OpenStack):
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if (not self.basicAcceptsCards(from_stack, cards)
|
|
or not self.isAlternateColorSequence(cards)):
|
|
return 0
|
|
if not self.cards:
|
|
return cards[0].rank == 15 or self.cap.base_rank == ANY_RANK
|
|
return self.isAlternateColorSequence([self.cards[-1], cards[0]])
|
|
|
|
def canMoveCards(self, cards):
|
|
return (self.basicCanMoveCards(cards)
|
|
and self.isAlternateColorSequence(cards))
|
|
|
|
|
|
class HexADeck_SS_RowStack(HexADeck_OpenStack):
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if (not self.basicAcceptsCards(from_stack, cards)
|
|
or not self.isSuitSequence(cards)):
|
|
return 0
|
|
if not self.cards:
|
|
return cards[0].rank == 15 or self.cap.base_rank == ANY_RANK
|
|
return self.isSuitSequence([self.cards[-1], cards[0]])
|
|
|
|
def canMoveCards(self, cards):
|
|
return (self.basicCanMoveCards(cards)
|
|
and self.isSuitSequence(cards))
|
|
|
|
|
|
class Bits_RowStack(ReserveStack):
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.basicAcceptsCards(from_stack, cards):
|
|
return 0
|
|
stackcards = self.cards
|
|
if stackcards or cards[0].suit == 4:
|
|
return 0
|
|
i = int(self.id / 4)
|
|
for r in self.game.s.rows[i * 4:self.id]:
|
|
if not r.cards:
|
|
return 0
|
|
return ((self.game.s.foundations[i].cards[-1].rank + 1
|
|
>> (self.id % 4)) % 2 == (cards[0].rank + 1) % 2)
|
|
|
|
|
|
class Bytes_RowStack(ReserveStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.basicAcceptsCards(from_stack, cards):
|
|
return 0
|
|
stackcards = self.cards
|
|
if stackcards or cards[0].suit == 4:
|
|
return 0
|
|
id = self.id - 16
|
|
i = int(id / 2)
|
|
for r in self.game.s.rows[16 + i * 2:self.id]:
|
|
if not r.cards:
|
|
return 0
|
|
return self.game.s.foundations[i].cards[-1].rank == cards[0].rank
|
|
|
|
|
|
class HexAKlon_RowStack(AC_RowStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.basicAcceptsCards(from_stack, cards):
|
|
return 0
|
|
stackcards = self.cards
|
|
if stackcards:
|
|
if (stackcards[-1].suit == 4 or cards[0].suit == 4):
|
|
return 1
|
|
return AC_RowStack.acceptsCards(self, from_stack, cards)
|
|
|
|
|
|
class HexADeck_ACRowStack(AC_RowStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.basicAcceptsCards(from_stack, cards):
|
|
return 0
|
|
stackcards = self.cards
|
|
if stackcards:
|
|
if (stackcards[-1].suit == 4 or cards[0].suit == 4):
|
|
return stackcards[-1].rank == cards[0].rank + 1
|
|
return AC_RowStack.acceptsCards(self, from_stack, cards)
|
|
|
|
|
|
class Familiar_ReserveStack(ReserveStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not ReserveStack.acceptsCards(self, from_stack, cards):
|
|
return 0
|
|
# Only take Wizards
|
|
return cards[0].suit == 4
|
|
|
|
def getBottomImage(self):
|
|
return self.game.app.images.getSuitBottom(4)
|
|
|
|
|
|
class Merlins_BraidStack(OpenStack):
|
|
def __init__(self, x, y, game):
|
|
OpenStack.__init__(self, x, y, game)
|
|
CW = self.game.app.images.CARDW
|
|
self.CARD_YOFFSET = self.game.app.images.CARD_YOFFSET
|
|
# use a sine wave for the x offsets
|
|
self.CARD_XOFFSET = []
|
|
j = 1
|
|
for i in range(20):
|
|
self.CARD_XOFFSET.append(int(math.sin(j) * 20))
|
|
j = j + .9
|
|
|
|
|
|
class Merlins_RowStack(ReserveStack):
|
|
def fillStack(self):
|
|
if not self.cards and self.game.s.braid.cards:
|
|
self.game.moveMove(1, self.game.s.braid, self)
|
|
|
|
def getBottomImage(self):
|
|
return self.game.app.images.getBraidBottom()
|
|
|
|
|
|
class Merlins_ReserveStack(ReserveStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if from_stack is self.game.s.braid or from_stack in self.game.s.rows:
|
|
return 0
|
|
return ReserveStack.acceptsCards(self, from_stack, cards)
|
|
|
|
def getBottomImage(self):
|
|
return self.game.app.images.getTalonBottom()
|
|
|
|
|
|
# /***********************************************************************
|
|
# //
|
|
# ************************************************************************/
|
|
|
|
class AbstractHexADeckGame(Game):
|
|
RANKS = (_("Ace"), "2", "3", "4", "5", "6", "7", "8", "9",
|
|
"A", "B", "C", "D", "E", "F", "10")
|
|
|
|
|
|
class Merlins_Hint(DefaultHint):
|
|
pass
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Bits n Bytes
|
|
# ************************************************************************/
|
|
|
|
class BitsNBytes(Game):
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self):
|
|
l, s = Layout(self), self.s
|
|
font = self.app.getFont("canvas_default")
|
|
|
|
# Set window size
|
|
self.setSize(l.XM * 4 + l.XS * 8, l.YM + l.YS * 4)
|
|
|
|
# Create bit stacks
|
|
self.bit_texts = []
|
|
y = l.YM
|
|
for j in range(4):
|
|
x = l.XM * 4 + l.XS * 7
|
|
for i in range(4):
|
|
s.rows.append(Bits_RowStack(x, y, self, max_cards=1,
|
|
max_accept=1, base_suit=j, max_move=0))
|
|
self.bit_texts.append(MfxCanvasText(self.canvas, x + l.CW / 2 , y + l.CH / 2,
|
|
anchor="center", font=font))
|
|
x = x - l.XS
|
|
y = y + l.YS
|
|
|
|
# Create byte stacks
|
|
y = l.YM
|
|
for j in range(4):
|
|
x = l.XM * 3 + l.XS * 3
|
|
for i in range(2):
|
|
s.rows.append(Bytes_RowStack(x, y, self, max_cards=1,
|
|
max_accept=1, base_suit=ANY_SUIT, max_move=0))
|
|
x = x - l.XS
|
|
y = y + l.YS
|
|
|
|
# Create foundations
|
|
x = l.XM * 2 + l.XS
|
|
y = l.YM
|
|
for i in range(4):
|
|
s.foundations.append(SS_FoundationStack(x, y, self, i, mod=1,
|
|
max_move=0, max_cards=1))
|
|
y = y + l.YS
|
|
self.setRegion(s.rows, (0, 0, 999999, 999999))
|
|
|
|
# Create talon
|
|
x = l.XM
|
|
y = l.YM
|
|
s.talon = WasteTalonStack(x, y, self, num_deal=2, max_rounds=2)
|
|
l.createText(s.talon, "s")
|
|
y += l.YS + l.TEXT_HEIGHT
|
|
s.waste = WasteStack(x, y, self)
|
|
l.createText(s.waste, "s")
|
|
|
|
# Define stack groups
|
|
l.defaultStackGroups()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def updateText(self):
|
|
if self.preview > 1:
|
|
return
|
|
for j in range(4):
|
|
if not len(self.s.foundations[j].cards):
|
|
break
|
|
s = self.s.foundations[j].cards[-1].rank + 1
|
|
for i in range(4):
|
|
self.bit_texts[i + j * 4].config(text = str(s % 2))
|
|
s = int(s / 2)
|
|
|
|
def _shuffleHook(self, cards):
|
|
topcards, ranks = [None] * 4, [None] * 4
|
|
for c in cards[:]:
|
|
if not c.suit == 4:
|
|
if not topcards[c.suit]:
|
|
haverank = 0
|
|
for i in range(4):
|
|
if c.rank == ranks[i]:
|
|
haverank = 1
|
|
if not haverank:
|
|
topcards[c.suit] = c
|
|
ranks[c.suit] = c.rank
|
|
cards.remove(c)
|
|
cards = topcards + cards
|
|
cards.reverse()
|
|
return cards
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
self.startDealSample()
|
|
self.s.talon.dealRow(rows=self.s.foundations)
|
|
self.s.talon.dealCards()
|
|
|
|
def isGameWon(self):
|
|
for s in self.s.rows:
|
|
if not s.cards:
|
|
return 0
|
|
return 1
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return 0
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Hex A Klon
|
|
# ************************************************************************/
|
|
|
|
class HexAKlon(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = HexAKlon_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=-1, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=8, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations[:4]:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
r = l.s.foundations[4]
|
|
s.foundations.append(HexATrump_Foundation(r.x, r.y, self, 4, mod=4,
|
|
max_move=0, max_cards=4, base_rank=ANY_RANK))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(len(self.s.rows)):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Hex A Klon by Threes
|
|
# ************************************************************************/
|
|
|
|
class HexAKlonByThrees(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = HexAKlon_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=-1, num_deal=3, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=8, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations[:4]:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
r = l.s.foundations[4]
|
|
s.foundations.append(HexATrump_Foundation(r.x, r.y, self, 4, mod=4,
|
|
max_move=0, max_cards=4, base_rank=ANY_RANK))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(len(self.s.rows)):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // King Only Hex A Klon
|
|
# ************************************************************************/
|
|
|
|
class KingOnlyHexAKlon(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = HexAKlon_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=-1, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=8, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations[:4]:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
r = l.s.foundations[4]
|
|
s.foundations.append(HexATrump_Foundation(r.x, r.y, self, 4, mod=4,
|
|
max_move=0, max_cards=4, base_rank=ANY_RANK))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=15))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(len(self.s.rows)):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def _shuffleHook(self, cards):
|
|
basecard = [None]
|
|
for c in cards[:]:
|
|
if c.suit == 4:
|
|
if basecard[0] == None:
|
|
basecard[0] = c
|
|
cards.remove(c)
|
|
cards = basecard + cards
|
|
cards.reverse()
|
|
return cards
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Klondike Plus 16
|
|
# ************************************************************************/
|
|
|
|
class KlondikePlus16(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = HexAKlon_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=2, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=8, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=15))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(len(self.s.rows)):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // The Familiar
|
|
# ************************************************************************/
|
|
|
|
class TheFamiliar(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=2, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=8, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=15))
|
|
|
|
# Create reserve
|
|
x, y = l.XM, self.height - l.YS
|
|
s.reserves.append(Familiar_ReserveStack(x, y, self, max_cards=3))
|
|
self.setRegion(s.reserves, (-999, y - l.YM, x + l.XS, 999999), priority=1)
|
|
l.createText(s.reserves[0], "se")
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(len(self.s.rows)):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Two Familiars
|
|
# ************************************************************************/
|
|
|
|
class TwoFamiliars(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=2, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=12, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=15))
|
|
|
|
# Create reserve
|
|
x, y = l.XM, self.height - l.YS
|
|
s.reserves.append(Familiar_ReserveStack(x, y, self, max_cards=3))
|
|
self.setRegion(s.reserves, (-999, y - l.YM, x + l.XS, 999999), priority=1)
|
|
l.createText(s.reserves[0], "se")
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68 * 2
|
|
for i in range(len(self.s.rows)):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Ten by Eight
|
|
# ************************************************************************/
|
|
|
|
class TenByEight(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.gypsyLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=-1, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=10, waste=1, playcards=30)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68 * 2
|
|
frames = 0
|
|
for i in range(8):
|
|
if i == 5:
|
|
frames = -1
|
|
self.startDealSample()
|
|
self.s.talon.dealRow(frames=frames)
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Drawbridge
|
|
# ************************************************************************/
|
|
|
|
class Drawbridge(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.harpLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=2, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=7, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(len(self.s.rows) - 1):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Double Drawbridge
|
|
# ************************************************************************/
|
|
|
|
class DoubleDrawbridge(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.harpLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=2, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=10, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68 * 2
|
|
for i in range(len(self.s.rows) - 1):
|
|
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Hidden Passages
|
|
# ************************************************************************/
|
|
|
|
class HiddenPassages(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=2, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=7, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations[:4]:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
r = l.s.foundations[4]
|
|
s.foundations.append(HexATrump_Foundation(r.x, r.y, self, 4, mod=4,
|
|
max_move=0, max_cards=4, base_rank=ANY_RANK))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
def _shuffleHook(self, cards):
|
|
topcards = [None] * 4
|
|
for c in cards[:]:
|
|
if c.rank == 0 and not c.suit == 4:
|
|
topcards[c.suit] = c
|
|
cards.remove(c)
|
|
cards = topcards + cards
|
|
cards.reverse()
|
|
return cards
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
self.s.talon.dealRow(rows=self.s.foundations[:4], frames=0)
|
|
for i in range(2):
|
|
self.s.talon.dealRow(flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Cluitjar's Lair
|
|
# ************************************************************************/
|
|
|
|
class CluitjarsLair(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.klondikeLayout
|
|
Talon_Class = WasteTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = HexADeck_ACRowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=1, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=7, waste=1, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations[:4]:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
r = l.s.foundations[4]
|
|
s.foundations.append(HexATrump_Foundation(r.x, r.y, self, 4, mod=4,
|
|
max_move=0, max_cards=4, base_rank=ANY_RANK))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(2):
|
|
self.s.talon.dealRow(flip=0, frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Merlin's Meander
|
|
# ************************************************************************/
|
|
|
|
class MerlinsMeander(AbstractHexADeckGame):
|
|
Hint_Class = Merlins_Hint
|
|
MERLINS_CARDS = 20
|
|
|
|
#
|
|
# game layout
|
|
#
|
|
|
|
def createGame(self):
|
|
# create layout
|
|
l, s = Layout(self), self.s
|
|
|
|
# set window
|
|
# (piles up to 20 cards are playable - needed for Braid_BraidStack)
|
|
h = max(4*l.YS + 30, l.YS+(self.MERLINS_CARDS-1)*l.YOFFSET)
|
|
self.setSize(10*l.XS+l.XM, l.YM + h)
|
|
|
|
# extra settings
|
|
self.base_card = None
|
|
|
|
# Create rows, reserves
|
|
s.addattr(braid=None) # register extra stack variable
|
|
x, y = l.XM, l.YM
|
|
for i in range(2):
|
|
s.rows.append(Merlins_RowStack(x + l.XS * 0.5, y, self))
|
|
s.rows.append(Merlins_RowStack(x + l.XS * 4.5, y, self))
|
|
s.reserves.append(Familiar_ReserveStack(x + l.XS * 6.5, y, self, max_cards=3))
|
|
y = y + l.YS * 3
|
|
y = l.YM + l.YS
|
|
for i in range(2):
|
|
s.rows.append(Merlins_ReserveStack(x, y, self))
|
|
s.rows.append(Merlins_ReserveStack(x + l.XS, y, self))
|
|
s.rows.append(Merlins_ReserveStack(x, y + l.YS, self))
|
|
s.rows.append(Merlins_ReserveStack(x + l.XS, y + l.YS, self))
|
|
x = x + l.XS * 4
|
|
|
|
# Create braid
|
|
x, y = l.XM + l.XS * 2.2, l.YM
|
|
s.braid = Merlins_BraidStack(x, y, self)
|
|
|
|
# Create talon, waste
|
|
x, y = l.XM + l.XS * 7, l.YM + l.YS * 1.5
|
|
s.talon = WasteTalonStack(x, y, self, max_rounds=3)
|
|
l.createText(s.talon, "s")
|
|
s.talon.texts.rounds = MfxCanvasText(self.canvas,
|
|
x + l.CW / 2, y - l.YM,
|
|
anchor="s",
|
|
font=self.app.getFont("canvas_default"))
|
|
x = x - l.XS
|
|
s.waste = WasteStack(x, y, self)
|
|
l.createText(s.waste, "s")
|
|
|
|
# Create foundations
|
|
x, y = l.XM + l.XS * 8, l.YM
|
|
for i in range(4):
|
|
s.foundations.append(Merlins_Foundation(x, y, self, i, mod=16,
|
|
max_cards=16, base_rank=ANY_RANK))
|
|
s.foundations.append(Merlins_Foundation(x + l.XS, y, self, i, mod=16,
|
|
max_cards=16, base_rank=ANY_RANK))
|
|
y = y + l.YS
|
|
self.texts.info = MfxCanvasText(self.canvas,
|
|
x + l.CW + l.XM / 2, y,
|
|
anchor="n",
|
|
font=self.app.getFont("canvas_default"))
|
|
|
|
# define stack-groups
|
|
self.sg.talonstacks = [s.talon] + [s.waste]
|
|
self.sg.openstacks = s.foundations + s.rows + s.reserves
|
|
self.sg.dropstacks = [s.braid] + s.rows + [s.waste] + s.reserves
|
|
|
|
|
|
#
|
|
# game overrides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68 * 2
|
|
self.startDealSample()
|
|
self.base_card = None
|
|
self.updateText()
|
|
for i in range(self.MERLINS_CARDS):
|
|
self.s.talon.dealRow(rows=[self.s.braid])
|
|
self.s.talon.dealRow()
|
|
# deal base_card to foundations, update cap.base_rank
|
|
self.base_card = self.s.talon.getCard()
|
|
while self.base_card.suit == 4:
|
|
self.s.talon.cards.remove(self.base_card)
|
|
self.s.talon.cards.insert(0, self.base_card)
|
|
self.base_card = self.s.talon.getCard()
|
|
to_stack = self.s.foundations[2 * self.base_card.suit]
|
|
self.flipMove(self.s.talon)
|
|
self.moveMove(1, self.s.talon, to_stack)
|
|
self.updateText()
|
|
for s in self.s.foundations:
|
|
s.cap.base_rank = self.base_card.rank
|
|
# deal first card to WasteStack
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.suit == card2.suit and
|
|
((card1.rank + 1) % 16 == card2.rank or (card2.rank + 1) % 16 == card1.rank))
|
|
|
|
def getHighlightPilesStacks(self):
|
|
return ()
|
|
|
|
def _restoreGameHook(self, game):
|
|
self.base_card = self.cards[game.loadinfo.base_card_id]
|
|
for s in self.s.foundations:
|
|
s.cap.base_rank = self.base_card.rank
|
|
|
|
def _loadGameHook(self, p):
|
|
self.loadinfo.addattr(base_card_id=None) # register extra load var.
|
|
self.loadinfo.base_card_id = p.load()
|
|
|
|
def _saveGameHook(self, p):
|
|
p.dump(self.base_card.id)
|
|
|
|
|
|
#
|
|
# game extras
|
|
#
|
|
|
|
def updateText(self):
|
|
if self.preview > 1 or not self.texts.info:
|
|
return
|
|
if not self.base_card:
|
|
t = ""
|
|
else:
|
|
t = self.RANKS[self.base_card.rank]
|
|
dir = self.getFoundationDir() % 16
|
|
if dir == 1:
|
|
t = t + _(" Ascending")
|
|
elif dir == 15:
|
|
t = t + _(" Descending")
|
|
self.texts.info.config(text=t)
|
|
|
|
def isGameWon(self):
|
|
for s in self.s.rows:
|
|
if s.cards and s.cards[0].suit != 4:
|
|
return 0
|
|
if not len(self.s.talon.cards) and len(self.s.waste.cards) == 1:
|
|
return self.s.waste.cards[0].suit == 4
|
|
return len(self.s.talon.cards) + len(self.s.waste.cards) == 0
|
|
|
|
|
|
# /***********************************************************************
|
|
# // Mage's Game
|
|
# ************************************************************************/
|
|
|
|
class MagesGame(Game):
|
|
Hint_Class = CautiousDefaultHint
|
|
Layout_Method = Layout.gypsyLayout
|
|
Talon_Class = InitialDealTalonStack
|
|
Foundation_Class = SS_FoundationStack
|
|
RowStack_Class = AC_RowStack
|
|
|
|
#
|
|
# Game layout
|
|
#
|
|
|
|
def createGame(self, max_rounds=1, num_deal=1, **layout):
|
|
l, s = Layout(self), self.s
|
|
kwdefault(layout, rows=12, texts=0, playcards=20)
|
|
self.Layout_Method(l, **layout)
|
|
self.setSize(l.size[0], l.size[1])
|
|
|
|
# Create talon
|
|
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
|
|
max_rounds=max_rounds, num_deal=num_deal)
|
|
|
|
# Create foundations
|
|
for r in l.s.foundations:
|
|
s.foundations.append(self.Foundation_Class(r.x, r.y, self,
|
|
r.suit, mod=16, max_cards=16, max_move=1))
|
|
|
|
# Create rows
|
|
for r in l.s.rows:
|
|
s.rows.append(self.RowStack_Class(r.x, r.y, self,
|
|
suit=ANY_SUIT, base_rank=ANY_RANK))
|
|
|
|
# Define stack groups
|
|
l.defaultAll()
|
|
|
|
#
|
|
# Game over rides
|
|
#
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == 68
|
|
for i in range(4):
|
|
self.s.talon.dealRow(frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
self.s.talon.dealRow(rows=self.s.rows[2:10])
|
|
self.s.talon.dealCards()
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
return (card1.color != card2.color and
|
|
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
|
|
|
|
|
|
|
|
# /***********************************************************************
|
|
# //
|
|
# ************************************************************************/
|
|
|
|
class Convolution(AbstractHexADeckGame):
|
|
RowStack_Class = StackWrapper(HexADeck_RK_RowStack, base_rank=NO_RANK)
|
|
|
|
#
|
|
# game layout
|
|
#
|
|
|
|
def createGame(self, rows=9, reserves=8):
|
|
# create layout
|
|
l, s = Layout(self), self.s
|
|
|
|
# set size
|
|
maxrows = max(rows, reserves)
|
|
self.setSize(l.XM + (maxrows + 2) * l.XS, l.YM + 6 * l.YS)
|
|
|
|
#
|
|
playcards = 4 * l.YS / l.YOFFSET
|
|
xoffset, yoffset = [], []
|
|
for i in range(playcards):
|
|
xoffset.append(0)
|
|
yoffset.append(l.YOFFSET)
|
|
for i in range(68 * self.gameinfo.decks - playcards):
|
|
xoffset.append(l.XOFFSET)
|
|
yoffset.append(0)
|
|
|
|
# create stacks
|
|
x, y = l.XM + (maxrows - reserves) * l.XS / 2, l.YM
|
|
for i in range(reserves):
|
|
s.reserves.append(ReserveStack(x, y, self))
|
|
x = x + l.XS
|
|
x, y = l.XM + (maxrows - rows) * l.XS / 2, l.YM + l.YS
|
|
self.setRegion(s.reserves, (-999, -999, 999999, y - l.YM / 2))
|
|
for i in range(rows):
|
|
stack = self.RowStack_Class(x, y, self, yoffset=yoffset)
|
|
stack.CARD_XOFFSET = xoffset
|
|
stack.CARD_YOFFSET = yoffset
|
|
s.rows.append(stack)
|
|
x = x + l.XS
|
|
x, y = l.XM + maxrows * l.XS, l.YM
|
|
for i in range(2):
|
|
for suit in range(5):
|
|
s.foundations.append(SS_FoundationStack(x, y, self, suit=suit, max_cards=16))
|
|
y = y + l.YS
|
|
x, y = x + l.XS, l.YM
|
|
self.setRegion(self.s.foundations, (x - l.XS * 2, -999, 999999,
|
|
self.height - (l.YS + l.YM)), priority=1)
|
|
s.talon = InitialDealTalonStack(self.width - 3 * l.XS / 2, self.height - l.YS, self)
|
|
|
|
# define stack-groups
|
|
l.defaultStackGroups()
|
|
|
|
#
|
|
# game overrides
|
|
#
|
|
|
|
def startGame(self):
|
|
self.startDealSample()
|
|
i = 0
|
|
while self.s.talon.cards:
|
|
if self.s.talon.cards[-1].rank == 15:
|
|
if self.s.rows[i].cards:
|
|
i = i + 1
|
|
self.s.talon.dealRow(rows=[self.s.rows[i]], frames=4)
|
|
|
|
# must look at cards
|
|
def _getClosestStack(self, cx, cy, stacks, dragstack):
|
|
closest, cdist = None, 999999999
|
|
for stack in stacks:
|
|
if stack.cards and stack is not dragstack:
|
|
dist = (stack.cards[-1].x - cx)**2 + (stack.cards[-1].y - cy)**2
|
|
else:
|
|
dist = (stack.x - cx)**2 + (stack.y - cy)**2
|
|
if dist < cdist:
|
|
closest, cdist = stack, dist
|
|
return closest
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
row = self.s.rows[0]
|
|
sequence = row.isRankSequence
|
|
return (sequence([card1, card2]) or sequence([card2, card1]))
|
|
|
|
|
|
# /***********************************************************************
|
|
# //
|
|
# ************************************************************************/
|
|
|
|
class Labyrinth(Convolution):
|
|
RowStack_Class = StackWrapper(HexADeck_AC_RowStack, base_rank=NO_RANK)
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
row = self.s.rows[0]
|
|
sequence = row.isAlternateColorSequence
|
|
return (sequence([card1, card2]) or sequence([card2, card1]))
|
|
|
|
|
|
|
|
# /***********************************************************************
|
|
# //
|
|
# ************************************************************************/
|
|
|
|
class Snakestone(Convolution):
|
|
RowStack_Class = StackWrapper(HexADeck_SS_RowStack, base_rank=NO_RANK)
|
|
|
|
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
|
row = self.s.rows[0]
|
|
sequence = row.isSuitSequence
|
|
return (sequence([card1, card2]) or sequence([card2, card1]))
|
|
|
|
|
|
|
|
# /***********************************************************************
|
|
# //
|
|
# ************************************************************************/
|
|
|
|
def r(id, gameclass, name, game_type, decks, redeals, skill_level):
|
|
game_type = game_type | GI.GT_HEXADECK
|
|
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
|
|
suits=range(4), ranks=range(16), trumps=range(4))
|
|
registerGame(gi)
|
|
return gi
|
|
|
|
|
|
r(165, BitsNBytes, 'Bits n Bytes', GI.GT_HEXADECK, 1, 1, GI.SL_BALANCED)
|
|
r(166, HexAKlon, 'Hex A Klon', GI.GT_HEXADECK, 1, -1, GI.SL_BALANCED)
|
|
r(16666, KlondikePlus16, 'Klondike Plus 16', GI.GT_HEXADECK, 1, 1, GI.SL_BALANCED)
|
|
r(16667, HexAKlonByThrees, 'Hex A Klon by Threes', GI.GT_HEXADECK, 1, -1, GI.SL_BALANCED)
|
|
r(16668, KingOnlyHexAKlon, 'King Only Hex A Klon', GI.GT_HEXADECK, 1, -1, GI.SL_BALANCED)
|
|
r(16669, TheFamiliar, 'The Familiar', GI.GT_HEXADECK, 1, 1, GI.SL_BALANCED)
|
|
r(16670, TwoFamiliars, 'Two Familiars', GI.GT_HEXADECK, 2, 1, GI.SL_BALANCED)
|
|
r(16671, TenByEight, '10 x 8', GI.GT_HEXADECK, 2, -1, GI.SL_BALANCED)
|
|
r(16672, Drawbridge, 'Drawbridge', GI.GT_HEXADECK, 1, 1, GI.SL_BALANCED)
|
|
r(16673, DoubleDrawbridge, 'Double Drawbridge', GI.GT_HEXADECK, 2, 1, GI.SL_BALANCED)
|
|
r(16674, HiddenPassages, 'Hidden Passages', GI.GT_HEXADECK, 1, 1, GI.SL_MOSTLY_LUCK)
|
|
r(16675, CluitjarsLair, 'Cluitjar\'s Lair', GI.GT_HEXADECK, 1, 0, GI.SL_BALANCED)
|
|
r(16676, MerlinsMeander, 'Merlin\'s Meander', GI.GT_HEXADECK, 2, 2, GI.SL_BALANCED)
|
|
r(16677, MagesGame, 'Mage\'s Game', GI.GT_HEXADECK, 1, 0, GI.SL_BALANCED)
|
|
r(16678, Convolution, 'Convolution', GI.GT_HEXADECK, 2, 0, GI.SL_MOSTLY_SKILL)
|
|
r(16679, Labyrinth, 'Hex Labyrinth', GI.GT_HEXADECK, 2, 0, GI.SL_MOSTLY_SKILL)
|
|
r(16680, Snakestone, 'Snakestone', GI.GT_HEXADECK, 2, 0, GI.SL_MOSTLY_SKILL)
|
|
|
|
del r
|