#!/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 . # # ---------------------------------------------------------------------------## from pysollib.game import Game from pysollib.gamedb import GI, GameInfo, registerGame from pysollib.hint import AbstractHint from pysollib.layout import Layout from pysollib.stack import \ AbstractFoundationStack, \ DealRowTalonStack, \ ReserveStack, \ Stack from pysollib.util import ANY_RANK, ANY_SUIT class PushPin_Hint(AbstractHint): def computeHints(self): game = self.game rows = game.s.rows for i in range(len(rows)-3): r = rows[i+1] if not rows[i+2].cards: break if r._checkPair(i, i+2): self.addHint(5000, 1, r, game.s.foundations[0]) if not rows[i+3].cards: break if r._checkPair(i, i+3): self.addHint(5000, 1, r, rows[i+2]) class PushPin_Foundation(AbstractFoundationStack): def acceptsCards(self, from_stack, cards): return True class PushPin_Talon(DealRowTalonStack): def dealCards(self, sound=False): for r in self.game.s.rows: if not r.cards: return self.dealRowAvail(rows=[r], sound=sound) return self.dealRowAvail(rows=[self.game.s.rows[0]], sound=sound) getBottomImage = Stack._getNoneBottomImage class PushPin_RowStack(ReserveStack): def _checkPair(self, ps, ns): if ps < 0 or ns > 51: return False rows = self.game.allstacks pc, nc = rows[ps].cards, rows[ns].cards if pc and nc: if pc[0].suit == nc[0].suit or pc[0].rank == nc[0].rank: return True return False def clickHandler(self, event): ps, ns = self.id - 1, self.id + 1 if self._checkPair(ps, ns): if not self.game.demo: self.game.playSample("autodrop", priority=20) self.playMoveMove(1, self.game.s.foundations[0], sound=False) return True return False def acceptsCards(self, from_stack, cards): if not self.cards: return False if abs(self.id - from_stack.id) != 1: return False ps = min(self.id, from_stack.id)-1 ns = ps + 3 return self._checkPair(ps, ns) def fillStack(self): self.game.fillEmptyStacks() def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): if to_stack is not self.game.s.foundations[0]: self._dropPairMove(ncards, to_stack, frames=-1, shadow=shadow) else: ReserveStack.moveMove( self, ncards, to_stack, frames=frames, shadow=shadow) def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1): game = self.game old_state = game.enterState(game.S_FILL) f = game.s.foundations[0] game.updateStackMove(game.s.talon, 2 | 16) # for undo if not game.demo: game.playSample("droppair", priority=200) game.moveMove(n, self, f, frames=frames, shadow=shadow) game.moveMove(n, other_stack, f, frames=frames, shadow=shadow) self.fillStack() game.updateStackMove(game.s.talon, 1 | 16) # for redo game.leaveState(old_state) getBottomImage = Stack._getBlankBottomImage class PushPin(Game): Hint_Class = PushPin_Hint RowStack_Class = PushPin_RowStack # # game layout # def createGame(self): # create layout l, s = Layout(self), self.s # set window xx, yy = 9, 6 w, h = l.XM+xx*l.XS, l.YM+yy*l.YS self.setSize(w, h) # create stacks for i in range(yy): for j in range(xx): n = j+xx*i if n < 1: continue if n > 52: break k = j if i % 2: k = xx-j-1 x, y = l.XM + k*l.XS, l.YM + i*l.YS s.rows.append(self.RowStack_Class(x, y, self)) s.talon = PushPin_Talon(l.XM, l.YM, self) s.foundations.append(PushPin_Foundation(l.XM, h-l.YS, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_accept=0, max_move=0, max_cards=52)) # define stack-groups l.defaultStackGroups() return l def startGame(self): self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:3]) def isGameWon(self): return len(self.s.foundations[0].cards) == 50 def _fillOne(self): rows = self.s.rows i = 0 for r in rows: if not r.cards: break i += 1 j = i for r in rows[i:]: if r.cards: break j += 1 else: return 0 self.moveMove(1, rows[j], rows[i], frames=2, shadow=0) return 1 def fillEmptyStacks(self): if not self.demo: self.startDealSample() old_state = self.enterState(self.S_FILL) while True: if not self._fillOne(): break self.leaveState(old_state) if not self.demo: self.stopSamples() def getAutoStacks(self, event=None): return ((), (), ()) class RoyalMarriage(PushPin): def _shuffleHook(self, cards): qi, ki = -1, -1 for i in range(len(cards)): c = cards[i] if c.suit == 2 and c.rank == 11: qi = i if c.suit == 2 and c.rank == 12: ki = i if qi >= 0 and ki >= 0: break q, k = cards[qi], cards[ki] del cards[max(qi, ki)] del cards[min(qi, ki)] cards.insert(0, k) cards.append(q) return cards class Queens(PushPin): def startGame(self): self._startAndDealRow() # ************************************************************************ # * Bayan (ex. Accordion) # ************************************************************************ class Accordion_Hint(AbstractHint): def computeHints(self): game = self.game rows = game.s.rows for i in range(len(rows)-3): r1, r2 = rows[i], rows[i+1] if r1.cards and r2.cards: c1, c2 = r1.cards[0], r2.cards[0] if c1.rank == c2.rank or c1.suit == c2.suit: if r2.acceptsCards(r1, [c1]): self.addHint(5000, 1, r1, r2) if r1.acceptsCards(r2, [c2]): self.addHint(5000, 1, r2, r1) r1, r2 = rows[i], rows[i+3] if r1.cards and r2.cards: c1, c2 = r1.cards[0], r2.cards[0] if c1.rank == c2.rank or c1.suit == c2.suit: if r2.acceptsCards(r1, [c1]): self.addHint(6000, 1, r1, r2) if r1.acceptsCards(r2, [c2]): self.addHint(6000, 1, r2, r1) class Accordion_RowStack(PushPin_RowStack): def acceptsCards(self, from_stack, cards): if not self.cards: return False if abs(self.id - from_stack.id) not in (1, 3): return False c1, c2 = self.cards[-1], cards[0] if c1.rank == c2.rank: return True return c1.suit == c2.suit clickHandler = ReserveStack.clickHandler class Accordion(PushPin): Hint_Class = Accordion_Hint RowStack_Class = Accordion_RowStack def startGame(self): self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:2]) def isGameWon(self): return len(self.s.foundations[0].cards) == 52 # ************************************************************************ # * Accordion (fixed) # ************************************************************************ class Accordion2_RowStack(Accordion_RowStack): def acceptsCards(self, from_stack, cards): if not Accordion_RowStack.acceptsCards(self, from_stack, cards): return False # accepts only from right stack return self.id < from_stack.id def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): game = self.game old_state = game.enterState(game.S_FILL) f = game.s.foundations[0] game.updateStackMove(game.s.talon, 2 | 16) # for undo game.moveMove(ncards, to_stack, f, frames=frames, shadow=shadow) game.moveMove(ncards, self, to_stack, frames=frames, shadow=shadow) self.fillStack() game.updateStackMove(game.s.talon, 1 | 16) # for redo game.leaveState(old_state) class Accordion2(Accordion): RowStack_Class = Accordion2_RowStack def isGameWon(self): return len(self.s.foundations[0].cards) == 51 # ************************************************************************ # * Relaxed Accordion # ************************************************************************ class RelaxedAccordion_RowStack(Accordion2_RowStack): acceptsCards = Accordion_RowStack.acceptsCards class RelaxedAccordion(Accordion2): RowStack_Class = RelaxedAccordion_RowStack registerGame(GameInfo(287, PushPin, "Push Pin", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(288, RoyalMarriage, "Royal Marriage", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) # registerGame(GameInfo(303, Queens, "Queens", # GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0)) registerGame(GameInfo(656, Accordion, "Bayan", GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(772, Accordion2, "Accordion", GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED, altnames=('Idle Year', 'Methuselah', 'Tower of Babel'))) registerGame(GameInfo(773, RelaxedAccordion, "Relaxed Accordion", GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED))