1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
PySolFC/pysollib/games/ultra/hexadeck.py
2017-04-19 12:03:44 +03:00

1405 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.mygettext import _, n_
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):
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 = 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