1#!/usr/bin/env python 2# -*- mode: python; coding: utf-8; -*- 3# ---------------------------------------------------------------------------## 4# 5# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer 6# Copyright (C) 2003 Mt. Hood Playing Card Co. 7# Copyright (C) 2005-2009 Skomoroh 8# 9# This program is free software: you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation, either version 3 of the License, or 12# (at your option) any later version. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program. If not, see <http://www.gnu.org/licenses/>. 21# 22# ---------------------------------------------------------------------------## 23 24import pysollib.game 25from pysollib.game import Game 26from pysollib.gamedb import GI, GameInfo, registerGame 27from pysollib.hint import CautiousDefaultHint 28from pysollib.layout import Layout 29from pysollib.mfxutil import kwdefault 30from pysollib.stack import \ 31 AbstractFoundationStack, \ 32 OpenStack, \ 33 Stack, \ 34 StackWrapper, \ 35 UD_SS_RowStack, \ 36 WasteStack, \ 37 WasteTalonStack 38from pysollib.util import ACE, ANY_RANK, NO_RANK 39 40 41# ************************************************************************ 42# * 43# ************************************************************************ 44 45 46class UnionSquare_Foundation(AbstractFoundationStack): 47 def acceptsCards(self, from_stack, cards): 48 if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): 49 return False 50 # check the rank 51 if len(self.cards) > 12: 52 return cards[0].rank == 25 - len(self.cards) 53 else: 54 return cards[0].rank == len(self.cards) 55 56 57class UnionSquare_RowStack(OpenStack): 58 def __init__(self, x, y, game, **cap): 59 kwdefault(cap, mod=8192, dir=0, base_rank=ANY_RANK, 60 max_accept=1, max_move=1) 61 OpenStack.__init__(self, x, y, game, **cap) 62 # self.CARD_YOFFSET = 1 63 64 def acceptsCards(self, from_stack, cards): 65 if not OpenStack.acceptsCards(self, from_stack, cards): 66 return False 67 if not self.cards: 68 return True 69 if cards[0].suit != self.cards[0].suit: 70 return False 71 if len(self.cards) == 1: 72 card_dir = cards[0].rank - self.cards[-1].rank 73 return card_dir == 1 or card_dir == -1 74 else: 75 stack_dir = (self.cards[1].rank - self.cards[0].rank) % \ 76 self.cap.mod 77 return (self.cards[-1].rank + stack_dir) % \ 78 self.cap.mod == cards[0].rank 79 80 getBottomImage = Stack._getReserveBottomImage 81 82 83# ************************************************************************ 84# * 85# ************************************************************************ 86 87class UnionSquare(pysollib.game.StartDealRowAndCards, Game): 88 Hint_Class = CautiousDefaultHint 89 Foundation_Class = StackWrapper(UnionSquare_Foundation, max_cards=26) 90 RowStack_Class = UnionSquare_RowStack 91 92 # 93 # game layout 94 # 95 96 def createGame(self, rows=16): 97 # create layout 98 l, s = Layout(self, card_y_space=20), self.s 99 100 # set window 101 self.setSize(l.XM + (5+rows//4)*l.XS, l.YM + 4*l.YS) 102 103 # create stacks 104 x, y, = l.XM, l.YM 105 s.talon = WasteTalonStack(x, y, self, max_rounds=1) 106 l.createText(s.talon, "s") 107 x = x + l.XS 108 s.waste = WasteStack(x, y, self) 109 l.createText(s.waste, "s") 110 for i in range(4): 111 x = 3*l.XS 112 for j in range(rows//4): 113 stack = self.RowStack_Class(x, y, self) 114 stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, 1 115 s.rows.append(stack) 116 x = x + l.XS 117 y = y + l.YS 118 x, y = self.width-l.XS, l.YM 119 for i in range(4): 120 stack = self.Foundation_Class(x, y, self, suit=i, 121 max_move=0, dir=0) 122 l.createText(stack, "sw") 123 s.foundations.append(stack) 124 y = y + l.YS 125 126 # define stack-groups 127 l.defaultStackGroups() 128 129 # 130 # game overrides 131 # 132 133 shallHighlightMatch = Game._shallHighlightMatch_SS 134 135 def getHighlightPilesStacks(self): 136 return () 137 138 139# ************************************************************************ 140# * Solid Square 141# ************************************************************************ 142 143class SolidSquare(UnionSquare): 144 RowStack_Class = StackWrapper(UD_SS_RowStack, base_rank=NO_RANK, 145 max_accept=1, max_move=1, mod=13) 146 147 def createGame(self): 148 UnionSquare.createGame(self, rows=20) 149 150 def _shuffleHook(self, cards): 151 return self._shuffleHookMoveToTop( 152 cards, 153 lambda c: (c.rank == ACE and c.deck == 0, c.suit)) 154 155 def startGame(self): 156 self.s.talon.dealRow(rows=self.s.foundations, frames=0) 157 UnionSquare.startGame(self) 158 159 def fillStack(self, stack): 160 if stack in self.s.rows and not stack.cards: 161 old_state = self.enterState(self.S_FILL) 162 if not self.s.waste.cards: 163 self.s.talon.dealCards() 164 if self.s.waste.cards: 165 self.s.waste.moveMove(1, stack) 166 self.leaveState(old_state) 167 168 shallHighlightMatch = Game._shallHighlightMatch_SSW 169 170 171# ************************************************************************ 172# * Boomerang 173# ************************************************************************ 174 175class Boomerang_Foundation(AbstractFoundationStack): 176 def acceptsCards(self, from_stack, cards): 177 if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): 178 return False 179 # check the rank 180 # 7, 8, 9, 10, J, Q, K, A, K, Q, J, 10, 9, 8, 7, A 181 if len(self.cards) < 7: 182 return cards[0].rank - 6 == len(self.cards) 183 elif len(self.cards) == 7: 184 return cards[0].rank == ACE 185 elif len(self.cards) < 15: 186 return cards[0].rank == 20 - len(self.cards) 187 else: # len(self.cards) == 15 188 return cards[0].rank == ACE 189 190 191class Boomerang(UnionSquare): 192 Foundation_Class = StackWrapper(Boomerang_Foundation, 193 base_rank=6, max_cards=16) 194 RowStack_Class = StackWrapper(UnionSquare_RowStack, base_rank=NO_RANK) 195 196 def createGame(self): 197 UnionSquare.createGame(self, rows=12) 198 199 def fillStack(self, stack): 200 if stack in self.s.rows and not stack.cards: 201 old_state = self.enterState(self.S_FILL) 202 if not self.s.waste.cards: 203 self.s.talon.dealCards() 204 if self.s.waste.cards: 205 self.s.waste.moveMove(1, stack) 206 self.leaveState(old_state) 207 208 209# register the game 210registerGame(GameInfo(35, UnionSquare, "Union Square", 211 GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_SKILL, 212 altnames=('British Square',), 213 )) 214registerGame(GameInfo(439, SolidSquare, "Solid Square", 215 GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED)) 216registerGame(GameInfo(738, Boomerang, "Boomerang", 217 GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED, 218 ranks=(0, 6, 7, 8, 9, 10, 11, 12), 219 )) 220