mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
This is artisanal manual craftwork :-) def mDone(self, button): if button == 0: # "OK" or double click - if isinstance(self.tree.selection_key, six.string_types): - self.key = str(self.tree.selection_key) - else: - self.key = self.tree.selection_key + self.key = self.tree.selection_key
328 lines
10 KiB
Python
328 lines
10 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/>.
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
|
|
from pysollib.game import Game
|
|
from pysollib.gamedb import GI, GameInfo, registerGame
|
|
from pysollib.hint import AbstractHint
|
|
from pysollib.layout import Layout
|
|
from pysollib.mfxutil import kwdefault
|
|
from pysollib.pysoltk import Card, MfxCanvasText
|
|
from pysollib.settings import TOOLKIT
|
|
from pysollib.stack import \
|
|
AbstractFoundationStack, \
|
|
InitialDealTalonStack, \
|
|
OpenStack
|
|
from pysollib.util import ANY_SUIT
|
|
|
|
|
|
# ************************************************************************
|
|
# * Samegame
|
|
# ************************************************************************
|
|
|
|
class Samegame_Hint(AbstractHint):
|
|
# FIXME: no intelligence whatsoever is implemented here
|
|
|
|
def computeHints(self):
|
|
game = self.game
|
|
for r in game.s.rows:
|
|
if r.cards:
|
|
removeStacks = r.getRemoveStacks()
|
|
score = 100 * len(removeStacks)
|
|
if score > 100:
|
|
self.addHint(score, 1, r, game.s.foundations[0])
|
|
|
|
|
|
class Samegame_Foundation(AbstractFoundationStack):
|
|
def __init__(self, x, y, game, suit=ANY_SUIT, **cap):
|
|
kwdefault(cap, max_move=0, max_accept=0, max_cards=game.NCARDS)
|
|
AbstractFoundationStack.__init__(self, x, y, game, suit, **cap)
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
return 1
|
|
|
|
|
|
class Samegame_RowStack(OpenStack):
|
|
def clickHandler(self, event):
|
|
if len(self.cards) == 0:
|
|
return False
|
|
self.playMoveMove(1, self.game.s.foundations[0], sound=False)
|
|
|
|
def rightclickHandler(self, event):
|
|
return self.clickHandler(event)
|
|
|
|
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
|
|
assert ncards == 1
|
|
if to_stack in self.game.s.foundations:
|
|
game = self.game
|
|
removeStacks = self.getRemoveStacks()
|
|
if len(removeStacks) < 2:
|
|
return False
|
|
|
|
old_state = game.enterState(game.S_FILL)
|
|
game.updateStackMove(self, 2 | 16)
|
|
for stack in removeStacks:
|
|
game.moveMove(1, stack, game.s.foundations[0], frames=0)
|
|
for stack in removeStacks:
|
|
stack.fillStack()
|
|
game.slideStacks()
|
|
|
|
if not game.demo:
|
|
game.playSample("drop", priority=200)
|
|
|
|
game.updateStackMove(self, 1 | 16) # for redo
|
|
game.leaveState(old_state)
|
|
return True
|
|
else:
|
|
return OpenStack.moveMove(self, ncards, to_stack, frames=frames,
|
|
shadow=shadow)
|
|
|
|
def fillStack(self):
|
|
self.game.fillStack(self)
|
|
|
|
def getRemoveStacks(self):
|
|
removeStacks = [self]
|
|
spotsChecked = 0
|
|
while spotsChecked < len(removeStacks):
|
|
adjacent = self.getAdjacent(removeStacks[spotsChecked].id)
|
|
for adjacentStack in adjacent:
|
|
if adjacentStack not in removeStacks and \
|
|
len(adjacentStack.cards) > 0 and \
|
|
adjacentStack.cards[0].suit == self.cards[0].suit:
|
|
removeStacks.append(adjacentStack)
|
|
spotsChecked += 1
|
|
return removeStacks
|
|
|
|
def getAdjacent(self, playSpace):
|
|
cols, rows = self.game.L
|
|
s = self.game.s
|
|
adjacentRows = []
|
|
if playSpace % rows != (rows - 1):
|
|
adjacentRows.append(s.rows[playSpace + 1])
|
|
|
|
if playSpace % rows != 0:
|
|
adjacentRows.append(s.rows[playSpace - 1])
|
|
|
|
if playSpace + rows < (cols * rows):
|
|
adjacentRows.append(s.rows[playSpace + rows])
|
|
|
|
if playSpace - rows > -1:
|
|
adjacentRows.append(s.rows[playSpace - rows])
|
|
|
|
return adjacentRows
|
|
|
|
|
|
class AbstractSamegameGame(Game):
|
|
Hint_Class = Samegame_Hint
|
|
RowStack_Class = Samegame_RowStack
|
|
|
|
COLORS = 3
|
|
NCARDS = 144
|
|
|
|
def createGame(self):
|
|
cols, rows = self.L
|
|
assert cols*rows == self.NCARDS
|
|
|
|
# start layout
|
|
l, s = Layout(self), self.s
|
|
# dx, dy = 3, -3
|
|
|
|
cs = self.app.images.cs
|
|
if cs.version == 6 or cs.mahjongg3d:
|
|
dx = l.XOFFSET
|
|
dy = -l.YOFFSET
|
|
d_x = cs.SHADOW_XOFFSET
|
|
d_y = cs.SHADOW_YOFFSET
|
|
self._delta_x, self._delta_y = dx, -dy
|
|
else:
|
|
dx = 3
|
|
dy = -3
|
|
d_x = 0
|
|
d_y = 0
|
|
self._delta_x, self._delta_y = 0, 0
|
|
# TODO - This should be moved to subsample logic in the future.
|
|
if self.preview > 1:
|
|
d_x /= 2
|
|
d_y /= 2
|
|
|
|
font = self.app.getFont("canvas_default")
|
|
|
|
# set window size
|
|
dxx, dyy = abs(dx), abs(dy)
|
|
cardw, cardh = l.CW - d_x, l.CH - d_y
|
|
w = l.XM + dxx + cols * cardw + d_x + l.XM + l.XM
|
|
h = l.YM + dyy + rows * cardh + d_y + l.YM
|
|
self.setSize(w, h)
|
|
|
|
#
|
|
self.cols = [[] for i in range(cols)]
|
|
cl = range(cols)
|
|
for col in cl:
|
|
for row in range(rows):
|
|
x = l.XM + dxx + col * cardw
|
|
y = l.YM + dyy + row * cardh
|
|
stack = self.RowStack_Class(x, y, self)
|
|
stack.CARD_XOFFSET = 0
|
|
stack.CARD_YOFFSET = 0
|
|
stack.coln, stack.rown = col, row
|
|
s.rows.append(stack)
|
|
self.cols[col].append(stack)
|
|
|
|
# create other stacks
|
|
y = l.YM + dyy
|
|
ivx = -l.XS-self.canvas.xmargin
|
|
if TOOLKIT == 'kivy':
|
|
ivx = -1000
|
|
s.foundations.append(Samegame_Foundation(ivx, y, self))
|
|
self.texts.info = MfxCanvasText(self.canvas,
|
|
self.width - l.XM, y,
|
|
anchor="nw", font=font)
|
|
# the Talon is invisble
|
|
s.talon = InitialDealTalonStack(-l.XS-self.canvas.xmargin,
|
|
self.height-dyy, self)
|
|
# Define stack groups
|
|
l.defaultStackGroups()
|
|
|
|
def startGame(self):
|
|
assert len(self.s.talon.cards) == self.NCARDS
|
|
# self.s.talon.dealRow(rows = self.s.rows, frames = 0)
|
|
n = 12
|
|
self.s.talon.dealRow(rows=self.s.rows[:self.NCARDS-n], frames=0)
|
|
self.startDealSample()
|
|
self.s.talon.dealRow(rows=self.s.rows[self.NCARDS-n:])
|
|
assert len(self.s.talon.cards) == 0
|
|
|
|
def _createCard(self, id, deck, suit, rank, x, y):
|
|
return Card(id, deck, id % self.COLORS, id % self.COLORS,
|
|
game=self, x=x, y=y)
|
|
|
|
def fillStack(self, stack):
|
|
to_stack = stack
|
|
for from_stack in self.cols[stack.coln][stack.rown+1::-1]:
|
|
if not from_stack.cards:
|
|
continue
|
|
self.moveMove(1, from_stack, to_stack, frames=0)
|
|
to_stack = from_stack
|
|
|
|
def slideStacks(self):
|
|
# Slide to the left to fill empty columns.
|
|
numrows = self.L[1]
|
|
card = 0
|
|
emptycols = 0
|
|
for c in range(len(self.cols)):
|
|
iscolempty = True
|
|
colstart = card
|
|
for r in range(numrows):
|
|
if len(self.s.rows[card].cards) > 0:
|
|
iscolempty = False
|
|
card += 1
|
|
if iscolempty:
|
|
emptycols += 1
|
|
elif emptycols > 0:
|
|
for r in range(colstart, card):
|
|
if len(self.s.rows[r].cards) > 0:
|
|
self.moveMove(1, self.s.rows[r],
|
|
self.s.rows[r - (numrows * emptycols)],
|
|
frames=0)
|
|
|
|
|
|
class Samegame3_20x10(AbstractSamegameGame):
|
|
L = (20, 10)
|
|
NCARDS = 200
|
|
|
|
|
|
class Samegame3_15x10(AbstractSamegameGame):
|
|
L = (15, 10)
|
|
NCARDS = 150
|
|
|
|
|
|
class Samegame3_25x15(AbstractSamegameGame):
|
|
L = (25, 15)
|
|
NCARDS = 375
|
|
|
|
|
|
class Samegame4_20x10(Samegame3_20x10):
|
|
COLORS = 4
|
|
|
|
|
|
class Samegame4_15x10(Samegame3_15x10):
|
|
COLORS = 4
|
|
|
|
|
|
class Samegame4_25x15(Samegame3_25x15):
|
|
COLORS = 4
|
|
|
|
|
|
class Samegame5_20x10(Samegame3_20x10):
|
|
COLORS = 5
|
|
|
|
|
|
class Samegame5_15x10(Samegame3_15x10):
|
|
COLORS = 5
|
|
|
|
|
|
class Samegame5_25x15(Samegame3_25x15):
|
|
COLORS = 5
|
|
|
|
|
|
class Samegame6_20x10(Samegame3_20x10):
|
|
COLORS = 6
|
|
|
|
|
|
class Samegame6_15x10(Samegame3_15x10):
|
|
COLORS = 6
|
|
|
|
|
|
class Samegame6_25x15(Samegame3_25x15):
|
|
COLORS = 6
|
|
|
|
|
|
# ************************************************************************
|
|
# * register a Samegame type game
|
|
# ************************************************************************
|
|
|
|
def r(id, gameclass, name, rules_filename="samegame.html"):
|
|
gi = GameInfo(id, gameclass, name,
|
|
GI.GT_SAMEGAME, 1, 0, GI.SL_MOSTLY_SKILL,
|
|
category=GI.GC_ISHIDO, short_name=name,
|
|
suits=list(range(1)), ranks=list(range(gameclass.NCARDS)),
|
|
si={"decks": 1, "ncards": gameclass.NCARDS})
|
|
gi.ncards = gameclass.NCARDS
|
|
gi.rules_filename = rules_filename
|
|
registerGame(gi)
|
|
return gi
|
|
|
|
|
|
r(19000, Samegame3_15x10, "Samegame 3 Colors 15x10")
|
|
r(19001, Samegame4_15x10, "Samegame 4 Colors 15x10")
|
|
r(19002, Samegame5_15x10, "Samegame 5 Colors 15x10")
|
|
r(19003, Samegame6_15x10, "Samegame 6 Colors 15x10")
|
|
r(19004, Samegame3_20x10, "Samegame 3 Colors 20x10")
|
|
r(19005, Samegame4_20x10, "Samegame 4 Colors 20x10")
|
|
r(19006, Samegame5_20x10, "Samegame 5 Colors 20x10")
|
|
r(19007, Samegame6_20x10, "Samegame 6 Colors 20x10")
|
|
r(19008, Samegame3_25x15, "Samegame 3 Colors 25x15")
|
|
r(19009, Samegame4_25x15, "Samegame 4 Colors 25x15")
|
|
r(19010, Samegame5_25x15, "Samegame 5 Colors 25x15")
|
|
r(19011, Samegame6_25x15, "Samegame 6 Colors 25x15")
|
|
|
|
del r
|