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/mughal.py

1192 lines
38 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/>.
#
# ---------------------------------------------------------------------------##
import math
from pysollib.game import Game
from pysollib.gamedb import GI, GameInfo, registerGame
from pysollib.hint import AbstractHint, 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, \
DealRowTalonStack, \
InitialDealTalonStack, \
OpenStack, \
RK_RowStack, \
ReserveStack, \
SS_FoundationStack, \
SS_RowStack, \
StackWrapper, \
WasteStack, \
WasteTalonStack, \
isSameSuitSequence
from pysollib.util import ANY_RANK, ANY_SUIT, NO_RANK, UNLIMITED_ACCEPTS, \
UNLIMITED_CARDS, UNLIMITED_MOVES
# ************************************************************************
# * Mughal Foundation Stacks
# ***********************************************************************/
class Mughal_FoundationStack(AbstractFoundationStack):
def __init__(self, x, y, game, suit, **cap):
kwdefault(cap, max_move=0)
SS_FoundationStack.__init__(self, x, y, game, suit, **cap)
def updateText(self):
AbstractFoundationStack.updateText(self)
self.game.updateText()
class Triumph_Foundation(AbstractFoundationStack):
def __init__(self, x, y, game, suit, **cap):
kwdefault(cap, mod=12, 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, 11)
else:
return (self.cards[-1].rank + stack_dir) % self.cap.mod \
== cards[0].rank
# ************************************************************************
# * Mughal Row Stacks
# ***********************************************************************/
class Mughal_OpenStack(OpenStack):
def __init__(self, x, y, game, yoffset, **cap):
kwdefault(cap, max_move=UNLIMITED_MOVES, max_cards=UNLIMITED_CARDS,
max_accept=UNLIMITED_ACCEPTS, base_rank=0, 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 not ((c1.suit + c2.suit) % 2 and c1.rank + dir == c2.rank):
return 0
c1 = c2
return 1
def isAlternateForceSequence(self, cards, dir=None):
if not dir:
dir = self.cap.dir
c1 = cards[0]
for c2 in cards[1:]:
if not ((c1.suit < 4 and c2.suit > 3 or
c1.suit > 3 and c2.suit < 4) and
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.suit == c2.suit and c1.rank + dir == c2.rank):
return 0
c1 = c2
return 1
class Mughal_AC_RowStack(Mughal_OpenStack):
def acceptsCards(self, from_stack, cards):
if (not self.basicAcceptsCards(from_stack, cards) or
not self.isAlternateColorSequence(cards)):
return 0
stackcards = self.cards
if not len(stackcards):
return cards[0].rank == 11 or self.cap.base_rank == ANY_RANK
return self.isAlternateColorSequence([stackcards[-1], cards[0]])
class Mughal_AF_RowStack(Mughal_OpenStack):
def acceptsCards(self, from_stack, cards):
if (not self.basicAcceptsCards(from_stack, cards) or
not self.isAlternateForceSequence(cards)):
return 0
stackcards = self.cards
if not len(stackcards):
return cards[0].rank == 11 or self.cap.base_rank == ANY_RANK
return self.isAlternateForceSequence([stackcards[-1], cards[0]])
class Mughal_RK_RowStack(Mughal_OpenStack):
def acceptsCards(self, from_stack, cards):
if (not self.basicAcceptsCards(from_stack, cards) or
not self.isRankSequence(cards)):
return 0
stackcards = self.cards
if not len(stackcards):
return cards[0].rank == 11 or self.cap.base_rank == ANY_RANK
return self.isRankSequence([stackcards[-1], cards[0]])
class Mughal_SS_RowStack(Mughal_OpenStack):
def acceptsCards(self, from_stack, cards):
if (not self.basicAcceptsCards(from_stack, cards) or
not self.isSuitSequence(cards)):
return 0
stackcards = self.cards
if not len(stackcards):
return cards[0].rank == 11 or self.cap.base_rank == ANY_RANK
return self.isSuitSequence([stackcards[-1], cards[0]])
class Circles_RowStack(SS_RowStack):
def __init__(self, x, y, game, base_rank, yoffset):
SS_RowStack.__init__(
self, x, y, game, base_rank=base_rank,
max_accept=1, max_move=1)
self.CARD_YOFFSET = 1
class Triumph_BraidStack(OpenStack):
def __init__(self, x, y, game, xoffset, yoffset):
OpenStack.__init__(self, x, y, game)
self.CARD_YOFFSET = int(self.game.app.images.CARD_YOFFSET * yoffset)
# use a sine wave for the x offsets
self.CARD_XOFFSET = []
j = 1
for i in range(30):
self.CARD_XOFFSET.append(int(math.cos(j) * xoffset))
j = j + .9
class Triumph_StrongStack(ReserveStack):
def fillStack(self):
if not self.cards:
if self.game.s.braidstrong.cards:
self.game.moveMove(1, self.game.s.braidstrong, self)
elif self.game.s.braidweak.cards:
self.game.moveMove(1, self.game.s.braidweak, self)
def getBottomImage(self):
return self.game.app.images.getBraidBottom()
class Triumph_WeakStack(ReserveStack):
def fillStack(self):
if not self.cards:
if self.game.s.braidweak.cards:
self.game.moveMove(1, self.game.s.braidweak, self)
elif self.game.s.braidstrong.cards:
self.game.moveMove(1, self.game.s.braidstrong, self)
def getBottomImage(self):
return self.game.app.images.getBraidBottom()
class Triumph_ReserveStack(ReserveStack):
def acceptsCards(self, from_stack, cards):
if (from_stack is self.game.s.braidstrong or
from_stack is self.game.s.braidweak 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 AbstractMughalGame(Game):
SUITS = (_("Crown"), _("Silver"), _("Saber"), _("Servant"),
_("Harp"), _("Gold"), _("Document"), _("Stores"))
RANKS = (_("Ace"), "2", "3", "4", "5", "6", "7", "8", "9", "10",
_("Pradhan"), _("Raja"))
COLORS = (_("Brown"), _("Black"), _("Red"), _("Yellow"),
_("Green"), _("Grey"), _("Orange"), _("Tan"))
FORCE = (_("Strong"), _("Weak"))
def updateText(self):
pass
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank)
class Triumph_Hint(DefaultHint):
# FIXME: demo is not too clever in this game
pass
# ************************************************************************
# * Mughal Circles
# ***********************************************************************/
class MughalCircles(AbstractMughalGame):
#
# Game layout
#
def createGame(self):
l, s = Layout(self), self.s
# Set window size
w, h = l.XM + l.XS * 9, l.YM + l.YS * 7
self.setSize(w, h)
# Create row stacks
x = w // 2 - l.CW // 2
y = h // 2 - l.YS // 2
x0 = (-1, -.8, 0, .8, 1, .8, 0, -.8,
-2, -1.9, -1.5, -.8, 0, .8, 1.5, 1.9, 2, 1.9, 1.5, .8,
0, -.8, -1.5, -1.9)
y0 = (0, -.8, -1, -.8, 0, .8, 1, .8,
0, -.8, -1.5, -1.9, -2, -1.9, -1.5, -.8,
0, .8, 1.5, 1.9, 2, 1.9, 1.5, .8)
for i in range(24):
# FIXME:
_x, _y = x+l.XS*x0[i]+l.XM*x0[i]*2, y+l.YS*y0[i]+l.YM*y0[i]*2
if _x < 0:
_x = 0
if _y < 0:
_y = 0
s.rows.append(
Circles_RowStack(_x, _y, self, base_rank=ANY_RANK, yoffset=0))
# Create reserve stacks
s.reserves.append(ReserveStack(l.XM, h - l.YS, self))
s.reserves.append(ReserveStack(w - l.XS, h - l.YS, self))
# Create foundations
x = l.XM
y = l.YM
for i in range(4):
s.foundations.append(
SS_FoundationStack(
x, y, self, i, mod=12,
max_move=0, max_cards=12))
y = y + l.YS
x = self.width - l.XS
y = l.YM
for i in range(4):
s.foundations.append(
SS_FoundationStack(
x, y, self, i + 4, mod=12,
max_move=0, max_cards=12))
y = y + l.YS
# FIXME:
_x1, _x2 = l.XM + l.XS, w - l.XS - l.XM
for i in s.rows:
if i.x < _x1:
i.x = _x1
elif i.x > _x2:
i.x = _x2
self.setRegion(s.rows, (_x1, 0, _x2, 999999))
# Create talon
s.talon = InitialDealTalonStack(l.XM + l.XS, l.YM, self)
# Define stack groups
l.defaultStackGroups()
#
# Game over rides
#
def startGame(self):
assert len(self.s.talon.cards) == 96
self._startDealNumRowsAndDealRowAndCards(3)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.suit == card2.suit) and
((card1.rank + 1 == card2.rank) or
(card1.rank - 1 == card2.rank)))
# ************************************************************************
# * Eight Legions
# ***********************************************************************/
class EightLegions(AbstractMughalGame):
#
# Game layout
#
def createGame(self):
l, s = Layout(self), self.s
# Set window size
self.setSize(l.XM * 3 + l.XS * 9, l.YM + l.YS * 6)
# Create row stacks
x = l.XM
y = l.YM
for i in range(8):
s.rows.append(RK_RowStack(x, y, self, base_rank=11,
max_move=12, max_cards=99))
x = x + l.XS
# Create reserve stacks
x = self.width - l.XS
y = l.YM
for i in range(6):
s.reserves.append(ReserveStack(x, y, self))
y = y + l.YS
y = y - l.YS
for i in range(4):
x = x - l.XS
s.reserves.append(ReserveStack(x, y, self))
self.setRegion(s.rows, (0, 0, l.XM + l.XS * 8, l.YS * 5))
# Create talon
s.talon = DealRowTalonStack(l.XM, self.height - l.YS, self)
l.createText(s.talon, "n")
# Define stack groups
l.defaultStackGroups()
#
# Game over rides
#
def startGame(self):
assert len(self.s.talon.cards) == 96
self._startDealNumRows(4)
self.s.talon.dealCards()
def isGameWon(self):
if len(self.s.talon.cards):
return 0
for s in self.s.rows:
if len(s.cards) != 12 or not isSameSuitSequence(s.cards):
return 0
return 1
# ************************************************************************
# * Shamsher
# ***********************************************************************/
class Shamsher(AbstractMughalGame):
Layout_Method = staticmethod(Layout.ghulamLayout)
Talon_Class = InitialDealTalonStack
Foundation_Class = SS_FoundationStack
RowStack_Class = RK_RowStack
BASE_RANK = ANY_RANK
#
# Game layout
#
def createGame(self, **layout):
l, s = Layout(self), self.s
kwdefault(layout, rows=14, reserves=4, texts=0)
self.Layout_Method(l, **layout)
self.setSize(l.size[0], l.size[1])
# Create foundations
for r in l.s.foundations:
s.foundations.append(
self.Foundation_Class(
r.x, r.y, self,
r.suit, mod=12, max_cards=12))
# Create reserve stacks
for r in l.s.reserves:
s.reserves.append(ReserveStack(r.x, r.y, self, ))
# Create row stacks
for r in l.s.rows:
s.rows.append(
self.RowStack_Class(
r.x, r.y, self, max_cards=12,
suit=ANY_SUIT, base_rank=self.BASE_RANK))
# Create talon
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
# Define stack groups
l.defaultAll()
#
# Game over rides
#
def startGame(self):
assert len(self.s.talon.cards) == 96
self._startDealNumRows(6)
self.s.talon.dealRow(rows=self.s.rows[:12])
self.s.talon.dealCards()
# ************************************************************************
# * Ashrafi
# ***********************************************************************/
class Ashrafi(Shamsher):
Layout_Method = staticmethod(Layout.ghulamLayout)
Talon_Class = InitialDealTalonStack
Foundation_Class = SS_FoundationStack
RowStack_Class = RK_RowStack
BASE_RANK = 11
#
# Game layout
#
def createGame(self, **layout):
Shamsher.createGame(self)
# ************************************************************************
# * Ghulam
# ***********************************************************************/
class Ghulam(Shamsher):
Layout_Method = staticmethod(Layout.ghulamLayout)
Talon_Class = InitialDealTalonStack
Foundation_Class = SS_FoundationStack
RowStack_Class = SS_RowStack
BASE_RANK = ANY_RANK
#
# Game layout
#
def createGame(self, **layout):
Shamsher.createGame(self)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.suit == card2.suit) and
((card1.rank + 1 == card2.rank) or
(card1.rank - 1 == card2.rank)))
# ************************************************************************
# * Tipati
# ***********************************************************************/
class Tipati(AbstractMughalGame):
Layout_Method = staticmethod(Layout.klondikeLayout)
Talon_Class = WasteTalonStack
Foundation_Class = SS_FoundationStack
RowStack_Class = RK_RowStack
BASE_RANK = 11
MAX_MOVE = 0
#
# Game layout
#
def createGame(self, max_rounds=1, num_deal=1, **layout):
l, s = Layout(self), self.s
kwdefault(layout, rows=8, waste=1)
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=12, max_cards=12, max_move=self.MAX_MOVE))
# Create row stacks
for r in l.s.rows:
s.rows.append(
self.RowStack_Class(
r.x, r.y, self,
suit=ANY_SUIT, base_rank=self.BASE_RANK))
# Define stack groups
l.defaultAll()
#
# Game over rides
#
def startGame(self):
assert len(self.s.talon.cards) == 96
for i in range(8):
self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
self.startDealSample()
self.s.talon.dealRow()
self.s.talon.dealCards()
# ************************************************************************
# * Ashwapati
# ***********************************************************************/
class Ashwapati(Tipati):
RowStack_Class = SS_RowStack
BASE_RANK = ANY_RANK
MAX_MOVE = 1
#
# Game layout
#
def createGame(self, **layout):
Tipati.createGame(self, max_rounds=-1, num_deal=1)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.suit == card2.suit) and
((card1.rank + 1 == card2.rank) or
(card1.rank - 1 == card2.rank)))
# ************************************************************************
# * Gajapati
# ***********************************************************************/
class Gajapati(Tipati):
RowStack_Class = SS_RowStack
BASE_RANK = ANY_RANK
MAX_MOVE = 1
#
# Game layout
#
def createGame(self, **layout):
Tipati.createGame(self, max_rounds=-1, num_deal=3)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.suit == card2.suit) and
((card1.rank + 1 == card2.rank) or
(card1.rank - 1 == card2.rank)))
# ************************************************************************
# * Narpati
# ***********************************************************************/
class Narpati(Tipati):
RowStack_Class = AC_RowStack
MAX_MOVE = 1
#
# Game layout
#
def createGame(self, **layout):
Tipati.createGame(self, max_rounds=1, num_deal=1)
# ************************************************************************
# * Garhpati
# ***********************************************************************/
class Garhpati(Tipati):
RowStack_Class = AC_RowStack
#
# Game layout
#
def createGame(self, **layout):
Tipati.createGame(self, max_rounds=-1, num_deal=3)
# ************************************************************************
# * Dhanpati
# ***********************************************************************/
class Dhanpati(Tipati):
#
# Game layout
#
def createGame(self, **layout):
Tipati.createGame(self, max_rounds=2, num_deal=3)
# ************************************************************************
# * Akbar's Triumph
# ************************************************************************
class AkbarsTriumph(AbstractMughalGame):
Hint_Class = Triumph_Hint
BRAID_CARDS = 12
BRAID_OFFSET = 1.1
#
# 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)
decks = self.gameinfo.decks
h = max(5 * l.YS + 35, l.YS + (self.BRAID_CARDS - 1) * l.YOFFSET)
self.setSize(l.XM + l.XS * (7 + decks * 2), l.YM + h)
# extra settings
self.base_card = None
# Create foundations, rows, reserves
s.addattr(braidstrong=None) # register extra stack variable
s.addattr(braidweak=None) # register extra stack variable
x, y = l.XM, l.YM
for j in range(4):
for i in range(decks):
s.foundations.append(
Triumph_Foundation(
x + l.XS * i, y, self,
j, mod=12, max_cards=12))
s.rows.append(Triumph_StrongStack(x + l.XS * decks, y, self))
s.rows.append(Triumph_ReserveStack(
x + l.XS * (1 + decks), y, self))
y = y + l.YS
x, y = x + l.XS * (5 + decks), l.YM
for j in range(4):
s.rows.append(Triumph_ReserveStack(x, y, self))
s.rows.append(Triumph_WeakStack(x + l.XS, y, self))
for i in range(decks, 0, -1):
s.foundations.append(Triumph_Foundation(
x + l.XS * (1 + i), y, self,
j + 4, mod=12, max_cards=12))
y = y + l.YS
self.texts.info = MfxCanvasText(
self.canvas,
self.width // 2, h - l.YM // 2,
anchor="center",
font=self.app.getFont("canvas_default"))
# Create braids
x, y = l.XM + l.XS * 2.3 + l.XS * decks, l.YM
s.braidstrong = Triumph_BraidStack(
x, y, self, xoffset=12, yoffset=self.BRAID_OFFSET)
x += l.XS * 1.4
s.braidweak = Triumph_BraidStack(
x, y, self, xoffset=-12, yoffset=self.BRAID_OFFSET)
# Create talon
x, y = l.XM + l.XS * 2 + l.XS * decks, h - l.YS - l.YM
s.talon = WasteTalonStack(x, y, self, max_rounds=3)
l.createText(s.talon, "s")
s.talon.texts.rounds = MfxCanvasText(
self.canvas,
self.width // 2, h - l.YM * 2.5,
anchor="center",
font=self.app.getFont("canvas_default"))
x += l.XS * 2
s.waste = WasteStack(x, y, self)
l.createText(s.waste, "s")
# define stack-groups
self.sg.talonstacks = [s.talon] + [s.waste]
self.sg.openstacks = s.foundations + s.rows
self.sg.dropstacks = [s.braidstrong] + [s.braidweak] + s.rows \
+ [s.waste]
#
# game overrides
#
def startGame(self):
self.startDealSample()
self.base_card = None
self.updateText()
for i in range(self.BRAID_CARDS):
self.s.talon.dealRow(rows=[self.s.braidstrong])
for i in range(self.BRAID_CARDS):
self.s.talon.dealRow(rows=[self.s.braidweak])
self.s.talon.dealRow()
# deal base_card to foundations, update cap.base_rank
self.base_card = self.s.talon.getCard()
to_stack = self.s.foundations[
self.base_card.suit * self.gameinfo.decks]
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) % 12 == card2.rank or
(card2.rank + 1) % 12 == 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() % 12
if dir == 1:
t = t + _(" Ascending")
elif dir == 11:
t = t + _(" Descending")
self.texts.info.config(text=t)
# ************************************************************************
# * Akbar's Conquest
# ************************************************************************
class AkbarsConquest(AkbarsTriumph):
BRAID_CARDS = 16
BRAID_OFFSET = .9
# ************************************************************************
# *
# ************************************************************************
class Vajra(AbstractMughalGame):
RowStack_Class = StackWrapper(Mughal_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(96 * 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=l.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(4):
s.foundations.append(
SS_FoundationStack(x, y, self, suit=suit+(4 * i)))
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 == 11:
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 Danda(Vajra):
RowStack_Class = StackWrapper(Mughal_AF_RowStack, base_rank=NO_RANK)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
row = self.s.rows[0]
sequence = row.isAlternateForceSequence
return (sequence([card1, card2]) or sequence([card2, card1]))
# ************************************************************************
# *
# ************************************************************************
class Khadga(Vajra):
RowStack_Class = StackWrapper(Mughal_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 Makara(Vajra):
RowStack_Class = StackWrapper(Mughal_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]))
# ************************************************************************
# * Ashta Dikapala Game Stacks
# ************************************************************************
class Dikapala_TableauStack(Mughal_OpenStack):
def __init__(self, x, y, game, base_rank, yoffset, **cap):
kwdefault(cap, dir=3, max_move=99, max_cards=4, max_accept=1,
base_rank=base_rank)
OpenStack.__init__(self, x, y, game, **cap)
self.CARD_YOFFSET = yoffset
def acceptsCards(self, from_stack, cards):
if not self.basicAcceptsCards(from_stack, cards):
return 0
# check that the base card is correct
if self.cards and self.cards[0].rank != self.cap.base_rank:
return 0
if not self.cards:
return cards[0].rank == self.cap.base_rank
return (self.cards[-1].suit == cards[0].suit and
self.cards[-1].rank + self.cap.dir == cards[0].rank)
def getBottomImage(self):
return self.game.app.images.getLetter(self.cap.base_rank)
class Dikapala_ReserveStack(ReserveStack):
def __init__(self, x, y, game, **cap):
kwdefault(cap, max_cards=1, max_accept=1, base_rank=ANY_RANK)
OpenStack.__init__(self, x, y, game, **cap)
def acceptsCards(self, from_stack, cards):
return (ReserveStack.acceptsCards(self, from_stack, cards) and
self.game.s.talon.cards)
class Dikapala_RowStack(BasicRowStack):
def acceptsCards(self, from_stack, cards):
if not BasicRowStack.acceptsCards(self, from_stack, cards):
return 0
# check
return not (self.cards or self.game.s.talon.cards)
def canMoveCards(self, cards):
return 1
def getBottomImage(self):
return self.game.app.images.getTalonBottom()
# ************************************************************************
# * Dikapala Hint
# ************************************************************************
class Dikapala_Hint(AbstractHint):
def computeHints(self):
game = self.game
# 2)See if we can move a card to the tableaux
if not self.hints:
for r in game.sg.dropstacks:
pile = r.getPile()
if not pile or len(pile) != 1:
continue
if r in game.s.tableaux:
rr = self.ClonedStack(r, stackcards=r.cards[:-1])
if rr.acceptsCards(None, pile):
# do not move a card that is already in correct place
continue
base_score = 80000 + (4 - r.cap.base_suit)
else:
base_score = 80000
# find a stack that would accept this card
for t in game.s.tableaux:
if t is not r and t.acceptsCards(r, pile):
score = base_score + 100 * (self.K - pile[0].rank)
self.addHint(score, 1, r, t)
break
# 3)See if we can move a card from the tableaux
# to a row stack. This can only happen if there are
# no more cards to deal.
if not self.hints:
for r in game.s.tableaux:
pile = r.getPile()
if not pile or len(pile) != 1:
continue
rr = self.ClonedStack(r, stackcards=r.cards[:-1])
if rr.acceptsCards(None, pile):
# do not move a card that is already in correct place
continue
# find a stack that would accept this card
for t in game.s.rows:
if t is not r and t.acceptsCards(r, pile):
score = 70000 + 100 * (self.K - pile[0].rank)
self.addHint(score, 1, r, t)
break
# 4)See if we can move a card within the row stacks
if not self.hints:
for r in game.s.rows:
pile = r.getPile()
if not pile or len(pile) != 1 or len(pile) == len(r.cards):
continue
base_score = 60000
# find a stack that would accept this card
for t in game.s.rows:
if t is not r and t.acceptsCards(r, pile):
score = base_score + 100 * (self.K - pile[0].rank)
self.addHint(score, 1, r, t)
break
# 5)See if we can deal cards
if self.level >= 2:
if game.canDealCards():
self.addHint(self.SCORE_DEAL, 0, game.s.talon, None)
# ************************************************************************
# * Ashta Dikapala
# ************************************************************************
class AshtaDikapala(Game):
Hint_Class = Dikapala_Hint
#
# game layout
#
def createGame(self):
# create layout
l, s = Layout(self), self.s
TABLEAU_YOFFSET = min(9, max(3, l.YOFFSET // 3))
# set window
th = l.YS + 3 * TABLEAU_YOFFSET
# (set piles so that at least 2/3 of a card is visible with 10 cards)
h = 8 * l.YOFFSET + l.CH * 2//3
self.setSize(9 * l.XS + l.XM * 2, l.YM + 3 * th + l.YM + h)
# create stacks
s.addattr(tableaux=[]) # register extra stack variable
x = l.XM + 8 * l.XS + l.XS // 2
y = l.YM
for i in range(3, 0, -1):
x = l.XM
for j in range(8):
s.tableaux.append(
Dikapala_TableauStack(
x, y, self, i - 1, TABLEAU_YOFFSET))
x = x + l.XS
x = x + l.XM
s.reserves.append(Dikapala_ReserveStack(x, y, self))
y = y + th
x, y = l.XM, y + l.YM
for i in range(8):
s.rows.append(Dikapala_RowStack(x, y, self, max_accept=1))
x = x + l.XS
x = self.width - l.XS
y = self.height - l.YS
s.talon = DealRowTalonStack(x, y, self)
l.createText(s.talon, "sw")
# define stack-groups
self.sg.openstacks = s.tableaux + s.rows + s.reserves
self.sg.talonstacks = [s.talon]
self.sg.dropstacks = s.tableaux + s.rows
#
# game overrides
#
def startGame(self):
self.s.talon.dealRow(rows=self.s.tableaux, frames=0)
self._startAndDealRow()
def isGameWon(self):
for stack in self.s.tableaux:
if len(stack.cards) != 4:
return 0
return 1
def fillStack(self, stack):
if self.s.talon.cards:
if stack in self.s.rows and len(stack.cards) == 0:
self.s.talon.dealRow(rows=[stack])
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.suit == card2.suit and
(card1.rank + 3 == card2.rank or card2.rank + 3 == card1.rank))
def getHighlightPilesStacks(self):
return ()
# ************************************************************************
# *
# ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level, altnames=()):
game_type = game_type | GI.GT_MUGHAL_GANJIFA
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(8)), ranks=list(range(12)), altnames=altnames)
registerGame(gi)
return gi
r(14401, MughalCircles, 'Mughal Circles', GI.GT_MUGHAL_GANJIFA, 1, 0,
GI.SL_MOSTLY_SKILL)
r(14402, Ghulam, 'Ghulam', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(14403, Shamsher, 'Shamsher', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(14404, EightLegions, 'Eight Legions', GI.GT_MUGHAL_GANJIFA, 1, 0,
GI.SL_MOSTLY_SKILL)
r(14405, Ashrafi, 'Ashrafi', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(14406, Tipati, 'Tipati', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_BALANCED)
r(14407, Ashwapati, 'Ashwapati', GI.GT_MUGHAL_GANJIFA, 1, -1, GI.SL_BALANCED)
r(14408, Gajapati, 'Gajapati', GI.GT_MUGHAL_GANJIFA, 1, -1, GI.SL_BALANCED)
r(14409, Narpati, 'Narpati', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_BALANCED)
r(14410, Garhpati, 'Garhpati', GI.GT_MUGHAL_GANJIFA, 1, -1, GI.SL_BALANCED)
r(14411, Dhanpati, 'Dhanpati', GI.GT_MUGHAL_GANJIFA, 1, 1, GI.SL_BALANCED)
r(14412, AkbarsTriumph, 'Akbar\'s Triumph', GI.GT_MUGHAL_GANJIFA, 1, 2,
GI.SL_BALANCED)
r(14413, AkbarsConquest, 'Akbar\'s Conquest', GI.GT_MUGHAL_GANJIFA, 2, 2,
GI.SL_BALANCED)
r(16000, Vajra, 'Vajra', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16001, Danda, 'Danda', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16002, Khadga, 'Khadga', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16003, Makara, 'Makara', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16004, AshtaDikapala, 'Ashta Dikapala', GI.GT_MUGHAL_GANJIFA, 1, 0,
GI.SL_BALANCED, altnames=('Eight Guardians'))
del r