#!/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 . # # ---------------------------------------------------------------------------## import math from pysollib.game import Game from pysollib.hint import DefaultHint from pysollib.mfxutil import kwdefault from pysollib.mygettext import _ from pysollib.stack import \ AbstractFoundationStack, \ OpenStack, \ ReserveStack, \ cardsFaceUp, \ isRankSequence from pysollib.util import ANY_RANK, ANY_SUIT class AbstractFlowerGame(Game): SUITS = (_("Pine"), _("Plum"), _("Cherry"), _("Wisteria"), _("Iris"), _("Peony"), _("Bush Clover"), _("Eularia"), _("Chrysanthemum"), _("Maple"), _("Willow"), _("Paulownia")) def shallHighlightMatch(self, stack1, card1, stack2, card2): return ((card1.suit == card2.suit) and ((card1.rank + 1 == card2.rank) or (card1.rank - 1 == card2.rank))) class Queue_Hint(DefaultHint): pass # ************************************************************************ # * Flower Foundation Stacks # ***********************************************************************/ class Flower_FoundationStack(AbstractFoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, max_cards=12, max_move=0, base_rank=ANY_RANK, base_suit=ANY_SUIT) AbstractFoundationStack.__init__(self, x, y, game, suit, **cap) def updateText(self): AbstractFoundationStack.updateText(self) self.game.updateText() def isHanafudaSequence(self, s, strictness=1): for i in range(len(s) - 1): if s[i].suit != s[i + 1].suit: return 0 if s[i].suit == 10 or strictness: a, b = s[i].rank, s[i + 1].rank else: a, b = self.swapTrashCards(s[i], s[i + 1]) if a + 1 != b: return 0 return cardsFaceUp(s) def swapTrashCards(self, carda, cardb): a, b = carda.rank, cardb.rank if a == 3 and b == 2: a, b = 2, 3 elif a == 1 and b == 3: b = 2 return a, b def getBaseCard(self): return '' # FIXME def getHelp(self): return '' # FIXME class Hanafuda_SS_FoundationStack(Flower_FoundationStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not stackcards: return cards[0].rank == 3 return self.isHanafudaSequence([cards[0], stackcards[-1]]) def getBottomImage(self): return self.game.app.images.getSuitBottom(self.cap.suit) class FlowerClock_Foundation(Flower_FoundationStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not stackcards: return cards[0].rank == 3 if not stackcards[-1].suit == cards[0].suit: return 0 return stackcards[-1].rank == cards[0].rank + 1 class Gaji_Foundation(Flower_FoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, max_move=1, min_cards=1, max_accept=1, base_suit=ANY_SUIT) Flower_FoundationStack.__init__(self, x, y, game, suit, **cap) self.CARD_YOFFSET = self.game.app.images.CARD_YOFFSET def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards return ((((stackcards[-1].suit + 1) % 12) == cards[0].suit) and (stackcards[-1].rank == cards[0].rank)) def getBottomImage(self): return self.game.app.images.getLetter(self.cap.base_rank) class Pagoda_Foundation(Flower_FoundationStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not stackcards: return cards[0].rank == 3 a, b = stackcards[-1].rank, cards[0].rank if len(stackcards) < 4: return a - 1 == b elif len(stackcards) > 4: return a + 1 == b else: return a == b def getBottomImage(self): return self.game.app.images.getSuitBottom(self.cap.suit) class MatsuKiri_Foundation(Flower_FoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, max_move=0, max_cards=48, max_accept=4, min_accept=4) AbstractFoundationStack.__init__(self, x, y, game, suit, **cap) self.CARD_YOFFSET = self.game.app.images.CARDH // 10 def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 if not self.isHanafudaSequence(cards, 0): return 0 stackcards = self.cards if not stackcards: return cards[0].suit == 0 return stackcards[-1].suit + 1 == cards[0].suit # def getBottomImage(self): # return self.game.app.images.getBraidBottom() class GreatWall_FoundationStack(Flower_FoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, max_cards=48, max_move=1, min_accept=1, max_accept=1) Flower_FoundationStack.__init__(self, x, y, game, suit, **cap) self.CARD_YOFFSET = self.game.app.images.CARDH // 20 def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if stackcards: return ((stackcards[-1].suit + 1) % 12 == cards[0].suit and cards[0].rank == self.cap.base_rank) else: return cards[0].suit == 0 def getBottomImage(self): return self.game.app.images.getLetter(self.cap.base_rank) class FourWinds_Foundation(Flower_FoundationStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not (cards[0].rank == self.cap.base_rank): return 0 if not stackcards: return (cards[0].suit == 0) else: return (cards[0].suit == stackcards[-1].suit + 1) # def getBottomImage(self): # return self.game.app.images.getLetter(self.cap.base_rank) class Queue_Foundation(AbstractFoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, mod=12, dir=0, base_suit=ANY_SUIT, 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 cards[0].suit == self.game.base_card.suit stack_dir = self.game.getFoundationDir() if stack_dir == 0: card_dir = (cards[0].suit - self.cards[-1].suit) % 12 return card_dir in (1, 11) else: return (self.cards[-1].suit + stack_dir) % 12 == cards[0].suit def getBottomImage(self): return self.game.app.images.getLetter(self.cap.base_rank) # ************************************************************************ # * Flower Row Stacks # ***********************************************************************/ class Flower_OpenStack(OpenStack): def __init__(self, x, y, game, yoffset, **cap): kwdefault(cap, max_move=99, max_cards=99, max_accept=99, base_rank=0, dir=1) OpenStack.__init__(self, x, y, game, **cap) self.CARD_YOFFSET = yoffset def isHanafudaSequence(self, cards, strictness=1): c1 = cards[0] for c2 in cards[1:]: if c1.suit != c2.suit: return 0 if c1.suit == 10 or strictness: a, b = c1.rank, c2.rank else: a, b = self.swapTrashCards(c1, c2) if a + self.cap.dir != b: return 0 c1 = c2 return 1 def swapTrashCards(self, carda, cardb): a, b = carda.rank, cardb.rank if a == 3 and b == 2: a, b = 2, 3 elif a == 1 and b == 3: b = 2 return a, b class Hanafuda_SequenceStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards) \ or not self.isHanafudaSequence(cards): return 0 stackcards = self.cards if not len(stackcards): return cards[0].rank == 0 or self.cap.base_rank == ANY_RANK return self.isHanafudaSequence([stackcards[-1], cards[0]]) class Oonsoo_SequenceStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards) \ or not self.isHanafudaSequence(cards, 0): return 0 stackcards = self.cards if not len(stackcards): return cards[0].rank == 0 or self.cap.base_rank == ANY_RANK return self.isHanafudaSequence([stackcards[-1], cards[0]], 0) class FlowerClock_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not len(stackcards): return 1 return stackcards[-1].rank + 1 == cards[0].rank class Gaji_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if ((not len(stackcards)) or ((stackcards[-1].suit == 10) and (stackcards[-1].rank == 3)) or ((cards[0].suit == 10) and (cards[0].rank == 3))): return 1 elif stackcards[-1].suit != cards[0].suit: return 0 a, b = self.swapTrashCards(stackcards[-1], cards[0]) return a + 1 == b class Matsukiri_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not stackcards: return cards[0].rank == 0 if cards[0].suit != stackcards[-1].suit: return 0 if stackcards[-1].suit == 10 or self.game.Strictness: a, b = stackcards[-1].rank, cards[0].rank else: a, b = self.swapTrashCards(stackcards[-1], cards[0]) return a + 1 == b def canDropCards(self, stacks): pile = self.getPile() if not pile or len(pile) <= 3: return (None, 0) f = self.game.s.foundations[0] if not f.cards: suit = 0 else: suit = f.cards[-1].suit + 1 if not pile[-1].suit == suit or \ not self.isHanafudaSequence(pile[-4:], 0): return (None, 0) return (f, 4) class Samuri_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not stackcards: return cards[0].rank == 0 return stackcards[-1].suit == cards[0].suit and \ stackcards[-1].rank + 1 == cards[0].rank class GreatWall_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if not stackcards: return cards[0].rank == 0 if cards[0].rank == stackcards[-1].rank: return stackcards[-1].suit == (cards[0].suit + 1) % 12 a, b = self.swapTrashCards(stackcards[-1], cards[0]) return a + 1 == b class FourWinds_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): return 0 stackcards = self.cards if len(cards) - 1 or len(stackcards) >= 3: return 0 if not stackcards: return 1 return ((cards[0].rank == stackcards[-1].rank) and (cards[0].suit == stackcards[-1].suit - 1)) def getBottomImage(self): return self.game.app.images.getReserveBottom() class Queue_BraidStack(OpenStack): def __init__(self, x, y, game, 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 # compensate for card width offset = self.game.app.images.CARDW / 1.7 self.CARD_XOFFSET = [] j = 1 for i in range(20): self.CARD_XOFFSET.append(int(math.sin(j) * offset)) j = j + .9 class Queue_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 Queue_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 JapaneseGarden_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if (not self.basicAcceptsCards(from_stack, cards) or from_stack not in self.game.s.rows): return 0 stackcards = self.cards if not len(stackcards): return 1 return stackcards[-1].rank + 1 == cards[0].rank class HanafudaRK_RowStack(Flower_OpenStack): def acceptsCards(self, from_stack, cards): if (not self.basicAcceptsCards(from_stack, cards) or not isRankSequence(cards, dir=1)): return 0 stackcards = self.cards if not len(stackcards): return 1 return stackcards[-1].rank + 1 == cards[0].rank