1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
PySolFC/pysollib/games/special/hexadeck.py
2025-03-03 21:28:35 -05:00

1738 lines
57 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/>.
#
# ---------------------------------------------------------------------------##
# Imports
import math
from pysollib.game import Game
from pysollib.gamedb import GI, GameInfo, registerGame
from pysollib.games.montana import Montana, Montana_RowStack
from pysollib.hint import CautiousDefaultHint, DefaultHint
from pysollib.layout import Layout
from pysollib.mfxutil import kwdefault
from pysollib.mygettext import _
from pysollib.pysoltk import MfxCanvasText
from pysollib.stack import \
AC_RowStack, \
AbstractFoundationStack, \
BasicRowStack, \
InitialDealTalonStack, \
OpenStack, \
ReserveStack, \
SS_FoundationStack, \
StackWrapper, \
WasteStack, \
WasteTalonStack, \
Yukon_AC_RowStack
from pysollib.util import ANY_RANK, ANY_SUIT, NO_RANK, UNLIMITED_ACCEPTS, \
UNLIMITED_MOVES
# ************************************************************************
# * 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[:((self.game.gameinfo.decks
* 4) - 1)]:
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=None, **cap):
kwdefault(cap, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS,
dir=-1)
OpenStack.__init__(self, x, y, game, **cap)
if yoffset is not None:
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)
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):
stack = Bits_RowStack(x, y, self, max_cards=1, max_accept=1,
base_suit=j, max_move=0)
s.rows.append(stack)
stack.texts.misc = 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):
stack = self.s.rows[i + j * 4]
stack.texts.misc.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 = staticmethod(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 = staticmethod(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 = staticmethod(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] is 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 = staticmethod(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 = staticmethod(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 = staticmethod(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 = staticmethod(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 = staticmethod(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 = staticmethod(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 = staticmethod(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 = staticmethod(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 -= 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 = staticmethod(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
self._startDealNumRows(4)
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]))
# ************************************************************************
# *
# ************************************************************************
class HexYukon_RowStack(Yukon_AC_RowStack):
def canMoveCards(self, cards):
if len(cards) > 1:
for card in cards:
if card.suit == 4:
return False
return Yukon_AC_RowStack.canMoveCards(self, cards)
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 Yukon_AC_RowStack.acceptsCards(self, from_stack, cards)
class HexYukon(Game):
Layout_Method = staticmethod(Layout.yukonLayout)
Talon_Class = InitialDealTalonStack
Foundation_Class = HexADeck_FoundationStack
RowStack_Class = StackWrapper(HexYukon_RowStack, base_rank=15)
def createGame(self, **layout):
# create layout
l, s = Layout(self), self.s
kwdefault(layout, rows=8, texts=0, playcards=25)
self.Layout_Method(l, **layout)
self.setSize(l.size[0], l.size[1])
# create stacks
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
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))
for r in l.s.rows:
s.rows.append(self.RowStack_Class(r.x, r.y, self))
# default
l.defaultAll()
return l
def startGame(self):
for i in range(1, len(self.s.rows)):
self.s.talon.dealRow(rows=self.s.rows[i:], flip=0, frames=0)
for i in range(4):
self.s.talon.dealRow(rows=self.s.rows[0:], flip=1, frames=0)
self._startAndDealRow()
def getHighlightPilesStacks(self):
return ()
shallHighlightMatch = Game._shallHighlightMatch_AC
# ************************************************************************
# *
# ************************************************************************
class MagicMontana_RowStack(Montana_RowStack):
def acceptsCards(self, from_stack, cards):
if not BasicRowStack.acceptsCards(self, from_stack, cards):
return False
if self.id % self.game.RSTEP == 0:
return cards[0].rank == self.game.RBASE
left = self.game.s.rows[self.id - 1]
if left.cards:
if left.cards[-1].suit == 4:
return False
if cards[0].suit == 4:
return True
return left.cards and left.cards[-1].suit == cards[0].suit \
and left.cards[-1].rank + 1 == cards[0].rank
class MagicMontana_Hint(DefaultHint):
def computeHints(self):
game = self.game
RSTEP, RBASE = game.RSTEP, game.RBASE
freerows = [s for s in game.s.rows if not s.cards]
# for each stack
for r in game.s.rows:
if not r.cards:
continue
assert len(r.cards) == 1 and r.cards[-1].face_up
c, pile, rpile = r.cards[0], r.cards, []
if r.id % RSTEP > 0:
left = game.s.rows[r.id - 1]
else:
left = None
if c.rank == RBASE:
# do not move the leftmost card of a row if the
# rank is correct
continue
for t in freerows:
if self.shallMovePile(r, t, pile, rpile):
# FIXME: this scoring is completely simple
if left and left.cards:
# prefer low-rank left neighbours
score = 40000 + (self.K - left.cards[-1].rank)
else:
score = 50000
# Deprioritize moving wizards, unless the next card
# is a 10. This will prevent an endless loop in the
# demo, but more advanced logic can probably use the
# wizards more strategically.
if r.cards[-1].suit == 4:
if t.id % RSTEP > 0:
leftt = game.s.rows[t.id - 1]
if leftt.cards[-1].rank < 15:
score -= 30000
else:
continue
self.addHint(score, 1, r, t)
class MagicMontana(Montana):
RowStack_Class = MagicMontana_RowStack
Hint_Class = MagicMontana_Hint
RLEN, RSTEP, RBASE = 72, 18, 0
def startGame(self):
frames = 0
for i in range(self.RLEN):
if i == self.RLEN-self.RSTEP: # last row
self.startDealSample()
frames = -1
if i % self.RSTEP == 0: # left column
continue
self.s.talon.dealRow(rows=(self.s.rows[i],), frames=frames)
def isGameWon(self):
rows = self.s.rows
for i in range(0, self.RLEN, self.RSTEP):
if not rows[i].cards:
return False
suit = rows[i].cards[-1].suit
for j in range(self.RSTEP - 2):
r = rows[i + j]
if not r.cards or r.cards[-1].rank != self.RBASE + j \
or r.cards[-1].suit != suit:
return False
w = rows[i + self.RSTEP - 2]
if not w.cards or w.cards[-1].suit != 4:
return False
return True
# ************************************************************************
# * Wizard's Storeroom
# ************************************************************************
class WizardsStoreroom(AbstractHexADeckGame):
MAX_ROUNDS = 2
#
# Game layout
#
def createGame(self):
l, s = Layout(self), self.s
# Set window size
decks = self.gameinfo.decks
self.setSize(2*l.XM + (2 + 5*decks)*l.XS, 3*l.YM + 5*l.YS)
yoffset = min(l.YOFFSET, max(10, l.YOFFSET // 2))
# Create talon
x = l.XM
y = l.YM
s.talon = WasteTalonStack(
x, y, self, num_deal=1, max_rounds=self.MAX_ROUNDS)
l.createText(s.talon, "s")
x = x + l.XS
s.waste = WasteStack(x, y, self)
l.createText(s.waste, "s")
# Create foundations
x = x + l.XM + l.XS
for j in range(4):
for i in range(decks):
s.foundations.append(
SS_FoundationStack(x, y, self, j, max_cards=16))
x = x + l.XS
for i in range(decks):
s.foundations.append(
HexATrump_Foundation(x, y, self, 4, max_cards=4))
x = x + l.XS
# Create reserve
x = l.XM
y = l.YM + l.YS + l.TEXT_HEIGHT
s.reserves.append(OpenStack(x, y, self))
s.reserves[0].CARD_YOFFSET = (l.YOFFSET, yoffset)[decks == 2]
# Create rows
x = x + l.XM + l.XS
for i in range(4*decks+1):
s.rows.append(HexAKlon_RowStack(x, y, self))
x = x + l.XS
self.setRegion(s.rows, (-999, y - l.YS, 999999, 999999))
# Define stack groups
l.defaultStackGroups()
#
# Game over rides
#
def startGame(self):
decks = self.gameinfo.decks
self.startDealSample()
for i in range(14 * decks):
self.s.talon.dealRow(rows=self.s.reserves, flip=0, frames=4)
self.s.reserves[0].flipMove()
self.s.talon.dealRow(rows=self.s.rows)
self.s.talon.dealCards() # deal first card to WasteStack
def fillStack(self, stack):
r = self.s.reserves[0]
if not stack.cards and stack in self.s.rows:
if r.cards and stack.acceptsCards(r, r.cards[-1:]):
r.moveMove(1, stack)
if r.canFlipCard():
r.flipMove()
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.rank + 1 == card2.rank or
card1.rank - 1 == card2.rank) and
card1.color != card2.color)
# ************************************************************************
# *
# ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level,
altnames=()):
game_type = game_type | GI.GT_HEXADECK
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(4)), ranks=list(range(16)),
trumps=list(range(4)), altnames=altnames)
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 (Draw 3)', 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, altnames=('Merlin\'s Coil'))
r(16677, MagesGame, 'Mage\'s Game', GI.GT_HEXADECK | GI.GT_OPEN, 1, 0,
GI.SL_BALANCED)
r(16678, Convolution, 'Convolution', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,
GI.SL_MOSTLY_SKILL)
r(16679, Labyrinth, 'Hex Labyrinth', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,
GI.SL_MOSTLY_SKILL)
r(16680, Snakestone, 'Snakestone', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,
GI.SL_MOSTLY_SKILL)
r(16681, HexYukon, 'Hex Yukon', GI.GT_HEXADECK, 1, 0, GI.SL_BALANCED)
r(16682, MagicMontana, 'Magic Montana', GI.GT_HEXADECK | GI.GT_OPEN, 1, 2,
GI.SL_MOSTLY_SKILL)
r(16683, WizardsStoreroom, "Wizard's Storeroom", GI.GT_HEXADECK, 1, 1,
GI.SL_MOSTLY_SKILL)
r(16684, WizardsStoreroom, "Big Storeroom", GI.GT_HEXADECK, 2, 1,
GI.SL_MOSTLY_SKILL)
del r