## ##---------------------------------------------------------------------------## ## ## PySol -- a Python Solitaire game ## ## Copyright (C) 2000 by T. Kirk ## Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer ## Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer ## Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer ## ## 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 2 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; see the file COPYING. ## If not, write to the Free Software Foundation, Inc., ## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## ##---------------------------------------------------------------------------## __all__ = [] # Imports import sys, math # PySol imports 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, MfxCanvasImage, bind, ANCHOR_NW from pysollib.games.special.pegged import Pegged_RowStack, WasteTalonStack, \ Pegged, PeggedCross1, PeggedCross2, Pegged6x6, Pegged7x7 ## Matrix_RowStack ## NewTower_RowStack ## RockHopper_RowStack ## ThreePeaks_TalonStack ## ThreePeaks_RowStack ## Matrix3 ## Matrix4 ## Matrix5 ## Matrix6 ## Matrix7 ## Matrix8 ## Matrix9 ## Matrix10 ## Matrix20 ## NewTowerofHanoi ## RockHopper ## RockHopperCross1 ## RockHopperCross2 ## RockHopper6x6 ## RockHopper7x7 ## ThreePeaks ## ThreePeaksNoScore ## LeGrandeTeton # /*********************************************************************** # // Matrix Row Stack # ************************************************************************/ class Matrix_RowStack(OpenStack): def __init__(self, x, y, game, **cap): kwdefault(cap, max_move=1, max_accept=1, max_cards=1, base_rank=ANY_RANK) apply(OpenStack.__init__, (self, x, y, game), cap) def canFlipCard(self): return 0 def canDropCards(self, stacks): return (None, 0) def cancelDrag(self, event=None): if event is None: self._stopDrag() def _findCard(self, event): # we need to override this because the shade may be hiding # the tile (from Tk's stacking view) return len(self.cards) - 1 def initBindings(self): bind(self.group, "<1>", self._Stack__clickEventHandler) bind(self.group, "", self._Stack__controlclickEventHandler) def getBottomImage(self): return self.game.app.images.getBlankBottom() def blockMap(self): ncards = self.game.gameinfo.ncards id, sqrt = self.id, int(math.sqrt(ncards)) line, row, column = int(id / sqrt), [], [] for r in self.game.s.rows[line * sqrt:sqrt + line * sqrt]: row.append(r.id) while id >= sqrt: id = id - sqrt while id < ncards: column.append(id) id = id + sqrt return [row, column] def basicIsBlocked(self): stack_map = self.blockMap() for j in range(2): for i in range(len(stack_map[j])): if not self.game.s.rows[stack_map[j][i]].cards: return 0 return 1 def clickHandler(self, event): game = self.game row = game.s.rows if not self.cards or game.drag.stack is self or self.basicIsBlocked(): return 1 stack_map = self.blockMap() for j in range(2): dir = 1 for i in range(len(stack_map[j])): to_stack = row[stack_map[j][i]] if to_stack is self: dir = -1 if not to_stack.cards: self._stopDrag() step = 1 from_stack = row[stack_map[j][i + dir]] while not from_stack is self: from_stack.playMoveMove(1, to_stack, frames = 0, sound = 1) to_stack = from_stack step = step + 1 from_stack = row[stack_map[j][i + dir * step]] self.playMoveMove(1, to_stack, frames = 0, sound = 1) return 1 return 1 # /*********************************************************************** # // New Tower Row Stack # ************************************************************************/ class NewTower_RowStack(Matrix_RowStack): def __init__(self, x, y, game, **cap): kwdefault(cap, max_move=1, max_accept=1, max_cards=99, base_rank=ANY_RANK) apply(OpenStack.__init__, (self, x, y, game), cap) self.CARD_YOFFSET = -max(self.game.app.images.CARD_YOFFSET, 20) def acceptsCards(self, from_stack, cards): if not OpenStack.acceptsCards(self, from_stack, cards): return 0 if self.cards: return self.cards[-1].rank > cards[0].rank return 1 def getBottomImage(self): # None doesn't recognize clicks. return self.game.app.images.getLetter(0) def basicIsBlocked(self): return 0 def clickHandler(self, event): game = self.game drag = game.drag from_stack = drag.stack if from_stack is self: # remove selection self._stopDrag() return 1 # possible move if from_stack: if self.acceptsCards(from_stack, from_stack.cards[-1:]): self._stopDrag() # this code actually moves the tiles from_stack.playMoveMove(1, self, frames=3, sound=0) return 1 drag.stack = self # move or create the shade image (see stack.py, _updateShade) if drag.shade_img: img = drag.shade_img img.dtag(drag.shade_stack.group) img.moveTo(self.x, self.y) elif self.cards: img = game.app.images.getShade() if img is None: return 1 img = MfxCanvasImage(game.canvas, self.x, self.y + self.CARD_YOFFSET[0] * (len(self.cards) - 1), image=img, anchor=ANCHOR_NW) drag.shade_img = img if self.cards: img.tkraise(self.cards[-1].item) img.addtag(self.group) drag.shade_stack = self return 1 # /*********************************************************************** # // Rock Hopper Row Stack # ************************************************************************/ class RockHopper_RowStack(Pegged_RowStack): def canFlipCard(self): return 0 def cancelDrag(self, event=None): if event is None: self._stopDrag() def _findCard(self, event): # we need to override this because the shade may be hiding # the tile (from Tk's stacking view) return len(self.cards) - 1 def initBindings(self): bind(self.group, "<1>", self._Stack__clickEventHandler) bind(self.group, "", self._Stack__controlclickEventHandler) def getBottomImage(self): # None doesn't recognize clicks. return self.game.app.images.getReserveBottom() def clickHandler(self, event): game = self.game drag = game.drag from_stack = drag.stack if from_stack is self: # remove selection self._stopDrag() return 1 # possible move if from_stack and not self.cards and self._getMiddleStack(from_stack) is not None: self._stopDrag() # this code actually moves the tiles from_stack.moveMove(1, self, frames=3) return 1 drag.stack = self # move or create the shade image (see stack.py, _updateShade) if drag.shade_img and self.cards: img = drag.shade_img img.dtag(drag.shade_stack.group) img.moveTo(self.x, self.y) elif self.cards: img = game.app.images.getShade() if img is None: return 1 img = MfxCanvasImage(game.canvas, self.x, self.y, image=img, anchor=ANCHOR_NW) drag.shade_img = img if self.cards: img.tkraise(self.cards[-1].item) img.addtag(self.group) drag.shade_stack = self return 1 # /*********************************************************************** # // Matrix Game # ************************************************************************/ class Matrix3(Game): # # Game layout # def createGame(self): l, s = Layout(self), self.s grid = math.sqrt(self.gameinfo.ncards) assert grid == int(grid) grid = int(grid) # Set window size w, h = l.XM * 2 + l.CW * grid, l.YM * 2 + l.CH * grid self.setSize(w, h) # Create rows for j in range(grid): x, y = l.XM, l.YM + l.CH * j for i in range(grid): s.rows.append(Matrix_RowStack(x, y, self)) x = x + l.CW # Create talon x, y = l.XM - l.XS, l.YM s.talon = InitialDealTalonStack(x, y, self) # Define stack groups l.defaultStackGroups() # # Game extras # def _shuffleHook(self, cards): # create solved game ncards = len(cards)-1 for c in cards: if c.rank == ncards: cards.remove(c) break n = 0 for i in range(ncards-1): for j in range(i+1, ncards): if cards[i].rank > cards[j].rank: n += 1 cards.reverse() if n%2: cards[0], cards[1] = cards[1], cards[0] return [c]+cards # # Game over rides # def startGame(self): assert len(self.s.talon.cards) == self.gameinfo.ncards self.startDealSample() self.s.talon.dealRow(rows=self.s.rows[:self.gameinfo.ncards - 1], frames=3) def isGameWon(self): if self.busy: return 0 s = self.s.rows l = len(s) - 1 for r in s[:l]: if not r.cards or not r.cards[0].rank == r.id: return 0 self.s.talon.dealRow(rows=s[l:], frames=3) return 1 def shallHighlightMatch(self, stack1, card1, stack2, card2): return ((card1.rank + 1 == card2.rank) or (card1.rank - 1 == card2.rank)) # /*********************************************************************** # // Size variations # ************************************************************************/ class Matrix4(Matrix3): pass class Matrix5(Matrix3): pass class Matrix6(Matrix3): pass class Matrix7(Matrix3): pass class Matrix8(Matrix3): pass class Matrix9(Matrix3): pass class Matrix10(Matrix3): pass class Matrix20(Matrix3): pass # /*********************************************************************** # // Rock Hopper # ************************************************************************/ class RockHopper(Pegged): STACK = RockHopper_RowStack class RockHopperCross1(PeggedCross1): STACK = RockHopper_RowStack class RockHopperCross2(PeggedCross2): STACK = RockHopper_RowStack class RockHopper6x6(Pegged6x6): STACK = RockHopper_RowStack class RockHopper7x7(Pegged7x7): STACK = RockHopper_RowStack # /*********************************************************************** # // Register a Matrix game # ************************************************************************/ def r(id, gameclass, short_name): name = short_name ncards = int(name[:2]) * int(name[:2]) gi = GameInfo(id, gameclass, name, GI.GT_MATRIX, 1, 0, GI.SL_SKILL, category=GI.GC_TRUMP_ONLY, short_name=short_name, suits=(), ranks=(), trumps=range(ncards), si = {"decks": 1, "ncards": ncards}) gi.ncards = ncards gi.rules_filename = "matrix.html" registerGame(gi) return gi r(22223, Matrix3, " 3x3 Matrix") r(22224, Matrix4, " 4x4 Matrix") r(22225, Matrix5, " 5x5 Matrix") r(22226, Matrix6, " 6x6 Matrix") r(22227, Matrix7, " 7x7 Matrix") r(22228, Matrix8, " 8x8 Matrix") r(22229, Matrix9, " 9x9 Matrix") r(22230, Matrix10, "10x10 Matrix") #r(22240, Matrix20, "20x20 Matrix") del r def r(id, gameclass, short_name): name = short_name ncards = 0 for n in gameclass.ROWS: ncards = ncards + n gi = GameInfo(id, gameclass, name, GI.GT_MATRIX, 1, 0, GI.SL_SKILL, category=GI.GC_TRUMP_ONLY, short_name=short_name, suits=(), ranks=(), trumps=range(ncards), si={"decks": 1, "ncards": ncards}) gi.ncards = ncards gi.rules_filename = "pegged.html" registerGame(gi) return gi r(22221, RockHopper, "Rock Hopper") r(22220, RockHopperCross1, "Rock Hopper Cross 1") r(22219, RockHopperCross2, "Rock Hopper Cross 2") r(22218, RockHopper6x6, "Rock Hopper 6x6") r(22217, RockHopper7x7, "Rock Hopper 7x7") del r