1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00

flake8 - mahjongg

This commit is contained in:
Shlomi Fish 2017-04-18 14:37:17 +03:00
parent 2ea7cf48ea
commit 2505afdb68
4 changed files with 165 additions and 144 deletions

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*- # -*- mode: python; coding: utf-8; -*-
# ---------------------------------------------------------------------------## # ---------------------------------------------------------------------------
# #
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer # Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
# Copyright (C) 2003 Mt. Hood Playing Card Co. # Copyright (C) 2003 Mt. Hood Playing Card Co.
@ -19,30 +19,40 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# ---------------------------------------------------------------------------## # ---------------------------------------------------------------------------
__all__ = [] __all__ = []
# Imports # Imports
import sys, re import sys
import re
import time import time
#from tkFont import Font # from tkFont import Font
from gettext import ungettext from gettext import ungettext
# PySol imports # PySol imports
from pysollib.mygettext import _, n_ from pysollib.mygettext import _
from pysollib.gamedb import registerGame, GameInfo, GI from pysollib.gamedb import registerGame, GameInfo, GI
from pysollib.util import *
from pysollib.mfxutil import kwdefault, Struct, Image from pysollib.mfxutil import kwdefault, Struct, Image
from pysollib.stack import *
from pysollib.game import Game from pysollib.game import Game
from pysollib.layout import Layout from pysollib.layout import Layout
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint from pysollib.hint import AbstractHint
from pysollib.settings import TOOLKIT, DEBUG from pysollib.settings import TOOLKIT, DEBUG
from pysollib.pysoltk import MfxCanvasText, MfxCanvasImage from pysollib.pysoltk import MfxCanvasText, MfxCanvasImage
from pysollib.pysoltk import bind, EVENT_HANDLED, ANCHOR_NW from pysollib.pysoltk import bind, EVENT_HANDLED, ANCHOR_NW
from pysollib.pysoltk import MfxMessageDialog from pysollib.pysoltk import MfxMessageDialog
from pysollib.util import ANY_SUIT, NO_RANK
from pysollib.stack import \
InitialDealTalonStack, \
OpenStack
from new import classobj
if sys.version_info > (3,):
xrange = range
def factorial(x): def factorial(x):
if x <= 1: if x <= 1:
@ -72,14 +82,14 @@ class Mahjongg_Hint(AbstractHint):
for t in stacks[i+1:]: for t in stacks[i+1:]:
if game.cardsMatch(r.cards[0], t.cards[0]): if game.cardsMatch(r.cards[0], t.cards[0]):
# simple scoring... # simple scoring...
##score = 10000 + r.id + t.id # score = 10000 + r.id + t.id
rb = r.blockmap rb = r.blockmap
tb = t.blockmap tb = t.blockmap
score = \ score = \
10000 + \ 10000 + \
1000 * (len(rb.below) + len(tb.below)) + \ 1000 * (len(rb.below) + len(tb.below)) + \
len(rb.all_left) + len(rb.all_right) + \ len(rb.all_left) + len(rb.all_right) + \
len(tb.all_left) + len(tb.all_right) len(tb.all_left) + len(tb.all_right)
self.addHint(score, 1, r, t) self.addHint(score, 1, r, t)
i += 1 i += 1
@ -88,7 +98,7 @@ class Mahjongg_Hint(AbstractHint):
# * # *
# ************************************************************************ # ************************************************************************
#class Mahjongg_Foundation(AbstractFoundationStack): # class Mahjongg_Foundation(AbstractFoundationStack):
class Mahjongg_Foundation(OpenStack): class Mahjongg_Foundation(OpenStack):
def __init__(self, x, y, game, suit=ANY_SUIT, **cap): def __init__(self, x, y, game, suit=ANY_SUIT, **cap):
@ -103,11 +113,11 @@ class Mahjongg_Foundation(OpenStack):
def basicIsBlocked(self): def basicIsBlocked(self):
return 1 return 1
#def initBindings(self): # def initBindings(self):
# pass # pass
def _position(self, card): def _position(self, card):
#AbstractFoundationStack._position(self, card) # AbstractFoundationStack._position(self, card)
OpenStack._position(self, card) OpenStack._position(self, card)
fnds = self.game.s.foundations fnds = self.game.s.foundations
@ -166,8 +176,9 @@ class Mahjongg_RowStack(OpenStack):
self._dropPairMove(ncards, to_stack, frames=-1, shadow=shadow) self._dropPairMove(ncards, to_stack, frames=-1, shadow=shadow)
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1): def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
##print 'drop:', self.id, other_stack.id # print 'drop:', self.id, other_stack.id
assert n == 1 and self.acceptsCards(other_stack, [other_stack.cards[-1]]) assert n == 1 and self.acceptsCards(
other_stack, [other_stack.cards[-1]])
if not self.game.demo: if not self.game.demo:
self.game.playSample("droppair", priority=200) self.game.playSample("droppair", priority=200)
old_state = self.game.enterState(self.game.S_FILL) old_state = self.game.enterState(self.game.S_FILL)
@ -213,24 +224,23 @@ class Mahjongg_RowStack(OpenStack):
for s in self.game.s.rows[self.id+1:]: for s in self.game.s.rows[self.id+1:]:
s.group.tkraise() s.group.tkraise()
# In Mahjongg games type there are a lot of stacks, so we optimize # In Mahjongg games type there are a lot of stacks, so we optimize
# and don't create bindings that are not used anyway. # and don't create bindings that are not used anyway.
def initBindings(self): def initBindings(self):
group = self.group group = self.group
# FIXME: dirty hack to access the Stack's private methods # FIXME: dirty hack to access the Stack's private methods
#bind(group, "<1>", self._Stack__clickEventHandler) # bind(group, "<1>", self._Stack__clickEventHandler)
#bind(group, "<3>", self._Stack__controlclickEventHandler) # bind(group, "<3>", self._Stack__controlclickEventHandler)
#bind(group, "<Control-1>", self._Stack__controlclickEventHandler) # bind(group, "<Control-1>", self._Stack__controlclickEventHandler)
# #
bind(group, "<1>", self.__clickEventHandler) bind(group, "<1>", self.__clickEventHandler)
bind(group, "<3>", self.__controlclickEventHandler) bind(group, "<3>", self.__controlclickEventHandler)
bind(group, "<Control-1>", self.__controlclickEventHandler) bind(group, "<Control-1>", self.__controlclickEventHandler)
##bind(group, "<Enter>", self._Stack__enterEventHandler) # bind(group, "<Enter>", self._Stack__enterEventHandler)
##bind(group, "<Leave>", self._Stack__leaveEventHandler) # bind(group, "<Leave>", self._Stack__leaveEventHandler)
def __defaultClickEventHandler(self, event, handler): def __defaultClickEventHandler(self, event, handler):
self.game.event_handled = True # for Game.undoHandler self.game.event_handled = True # for Game.undoHandler
if self.game.demo: if self.game.demo:
self.game.stopDemo(event) self.game.stopDemo(event)
if self.game.busy: if self.game.busy:
@ -239,7 +249,7 @@ class Mahjongg_RowStack(OpenStack):
return EVENT_HANDLED return EVENT_HANDLED
def __clickEventHandler(self, event): def __clickEventHandler(self, event):
##print 'click:', self.id # print 'click:', self.id
return self.__defaultClickEventHandler(event, self.clickHandler) return self.__defaultClickEventHandler(event, self.clickHandler)
def __controlclickEventHandler(self, event): def __controlclickEventHandler(self, event):
@ -259,8 +269,8 @@ class Mahjongg_RowStack(OpenStack):
self._stopDrag() self._stopDrag()
return 1 return 1
if self.basicIsBlocked(): if self.basicIsBlocked():
### remove selection # remove selection
##self.game.playSample("nomove") # self.game.playSample("nomove")
return 1 return 1
# possible move # possible move
if from_stack: if from_stack:
@ -273,11 +283,12 @@ class Mahjongg_RowStack(OpenStack):
self.game.playSample("startdrag") self.game.playSample("startdrag")
# create the shade image (see stack.py, _updateShade) # create the shade image (see stack.py, _updateShade)
if drag.shade_img: if drag.shade_img:
#drag.shade_img.dtag(drag.shade_stack.group) # drag.shade_img.dtag(drag.shade_stack.group)
drag.shade_img.delete() drag.shade_img.delete()
#game.canvas.delete(drag.shade_img) # game.canvas.delete(drag.shade_img)
drag.shade_img = None drag.shade_img = None
img = game.app.images.getHighlightedCard(card.deck, card.suit, card.rank) img = game.app.images.getHighlightedCard(
card.deck, card.suit, card.rank)
if img is None: if img is None:
return 1 return 1
img = MfxCanvasImage(game.canvas, self.x, self.y, image=img, img = MfxCanvasImage(game.canvas, self.x, self.y, image=img,
@ -335,11 +346,10 @@ class AbstractMahjonggGame(Game):
for tl in range(level, level + height): for tl in range(level, level + height):
tiles.append((tl, tx, ty)) tiles.append((tl, tx, ty))
assert len(tiles) == self.NCARDS assert len(tiles) == self.NCARDS
#tiles.sort() # tiles.sort()
#tiles = tuple(tiles) # tiles = tuple(tiles)
return tiles, max_tl, max_tx, max_ty return tiles, max_tl, max_tx, max_ty
# #
# game layout # game layout
# #
@ -351,8 +361,8 @@ class AbstractMahjonggGame(Game):
l, s = Layout(self), self.s l, s = Layout(self), self.s
show_removed = self.app.opt.mahjongg_show_removed show_removed = self.app.opt.mahjongg_show_removed
##dx, dy = 2, -2 # dx, dy = 2, -2
##dx, dy = 3, -3 # dx, dy = 3, -3
cs = self.app.cardset cs = self.app.cardset
if cs.version >= 6: if cs.version >= 6:
dx = l.XOFFSET dx = l.XOFFSET
@ -369,12 +379,12 @@ class AbstractMahjonggGame(Game):
d_x = 0 d_x = 0
d_y = 0 d_y = 0
self._delta_x, self._delta_y = 0, 0 self._delta_x, self._delta_y = 0, 0
#print dx, dy, d_x, d_y, cs.version # print dx, dy, d_x, d_y, cs.version
font = self.app.getFont("canvas_default") font = self.app.getFont("canvas_default")
# width of self.texts.info # width of self.texts.info
#ti_width = Font(self.canvas, font).measure(_('Remaining')) # ti_width = Font(self.canvas, font).measure(_('Remaining'))
ti_width = 80 ti_width = 80
# set window size # set window size
@ -403,21 +413,18 @@ class AbstractMahjonggGame(Game):
self.check_dist = l.CW*l.CW + l.CH*l.CH # see _getClosestStack() self.check_dist = l.CW*l.CW + l.CH*l.CH # see _getClosestStack()
# sort tiles (for 3D) # sort tiles (for 3D)
tiles.sort(lambda a, b: tiles.sort(key=lambda x: (x[0], x[2]-x[1]))
cmp(a[0], b[0]) or
cmp(-a[1]+a[2], -b[1]+b[2])
)
# create a row stack for each tile and compute the tilemap # create a row stack for each tile and compute the tilemap
tilemap = {} tilemap = {}
x0 = left_margin x0 = left_margin
y0 = l.YM + dyy y0 = l.YM + dyy
for level, tx, ty in tiles: for level, tx, ty in tiles:
#print level, tx, ty # print level, tx, ty
x = x0 + (tx * cardw) / 2 + level * dx x = x0 + (tx * cardw) / 2 + level * dx
y = y0 + (ty * cardh) / 2 + level * dy y = y0 + (ty * cardh) / 2 + level * dy
stack = self.RowStack_Class(x, y, self) stack = self.RowStack_Class(x, y, self)
##stack.G = (level, tx, ty) # stack.G = (level, tx, ty)
stack.CARD_XOFFSET = dx stack.CARD_XOFFSET = dx
stack.CARD_YOFFSET = dy stack.CARD_YOFFSET = dy
s.rows.append(stack) s.rows.append(stack)
@ -430,7 +437,7 @@ class AbstractMahjonggGame(Game):
# compute blockmap # compute blockmap
for stack in s.rows: for stack in s.rows:
level, tx, ty = tiles[stack.id] level, tx, ty = tiles[stack.id]
above, below, left, right, up, bottom = {}, {}, {}, {}, {}, {} above, below, left, right = {}, {}, {}, {}
# above blockers # above blockers
for tl in range(level+1, level+2): for tl in range(level+1, level+2):
above[tilemap.get((tl, tx, ty))] = 1 above[tilemap.get((tl, tx, ty))] = 1
@ -450,11 +457,11 @@ class AbstractMahjonggGame(Game):
right[tilemap.get((level, tx+2, ty))] = 1 right[tilemap.get((level, tx+2, ty))] = 1
right[tilemap.get((level, tx+2, ty+1))] = 1 right[tilemap.get((level, tx+2, ty+1))] = 1
# up blockers # up blockers
##up[tilemap.get((level, tx, ty-1))] = 1 # up[tilemap.get((level, tx, ty-1))] = 1
##up[tilemap.get((level, tx+1, ty-1))] = 1 # up[tilemap.get((level, tx+1, ty-1))] = 1
# bottom blockers # bottom blockers
##bottom[tilemap.get((level, tx, ty+2))] = 1 # bottom[tilemap.get((level, tx, ty+2))] = 1
##bottom[tilemap.get((level, tx+1, ty+2))] = 1 # bottom[tilemap.get((level, tx+1, ty+2))] = 1
# sanity check - assert that there are no overlapping tiles # sanity check - assert that there are no overlapping tiles
assert tilemap.get((level, tx, ty)) is stack assert tilemap.get((level, tx, ty)) is stack
assert tilemap.get((level, tx+1, ty)) is stack assert tilemap.get((level, tx+1, ty)) is stack
@ -465,19 +472,19 @@ class AbstractMahjonggGame(Game):
below = tuple(filter(None, below.keys())) below = tuple(filter(None, below.keys()))
left = tuple(filter(None, left.keys())) left = tuple(filter(None, left.keys()))
right = tuple(filter(None, right.keys())) right = tuple(filter(None, right.keys()))
##up = tuple(filter(None, up.keys())) # up = tuple(filter(None, up.keys()))
##bottom = tuple(filter(None, bottom.keys())) # bottom = tuple(filter(None, bottom.keys()))
# assemble # assemble
stack.blockmap = Struct( stack.blockmap = Struct(
above = above, above=above,
below = below, below=below,
left = left, left=left,
right = right, right=right,
##up = up, # up=up,
##bottom = bottom, # bottom=bottom,
all_left = None, all_left=None,
all_right = None, all_right=None,
) )
def get_all_left(s): def get_all_left(s):
@ -488,6 +495,7 @@ class AbstractMahjonggGame(Game):
get_all_left(t) get_all_left(t)
s.blockmap.all_left.update(t.blockmap.all_left) s.blockmap.all_left.update(t.blockmap.all_left)
s.blockmap.all_left[t] = 1 s.blockmap.all_left[t] = 1
def get_all_right(s): def get_all_right(s):
if s.blockmap.all_right is None: if s.blockmap.all_right is None:
s.blockmap.all_right = {} s.blockmap.all_right = {}
@ -504,7 +512,6 @@ class AbstractMahjonggGame(Game):
r.blockmap.all_left = tuple(r.blockmap.all_left.keys()) r.blockmap.all_left = tuple(r.blockmap.all_left.keys())
r.blockmap.all_right = tuple(r.blockmap.all_right.keys()) r.blockmap.all_right = tuple(r.blockmap.all_right.keys())
# create other stacks # create other stacks
for i in range(4): for i in range(4):
for j in range(9): for j in range(9):
@ -517,7 +524,7 @@ class AbstractMahjonggGame(Game):
y = l.YM+dyy y = l.YM+dyy
elif TOOLKIT == 'gtk': elif TOOLKIT == 'gtk':
# FIXME # FIXME
x = self.width -l.XS x = self.width - l.XS
y = self.height - l.YS y = self.height - l.YS
stack = Mahjongg_Foundation(x, y, self) stack = Mahjongg_Foundation(x, y, self)
if show_removed: if show_removed:
@ -536,7 +543,6 @@ class AbstractMahjonggGame(Game):
# Define stack groups # Define stack groups
l.defaultStackGroups() l.defaultStackGroups()
# #
# game overrides # game overrides
# #
@ -554,7 +560,6 @@ class AbstractMahjonggGame(Game):
return cards return cards
return new_cards return new_cards
def _shuffleHook1(self, cards): def _shuffleHook1(self, cards):
# old version; it generate a very easy layouts # old version; it generate a very easy layouts
old_cards = cards[:] old_cards = cards[:]
@ -625,10 +630,9 @@ class AbstractMahjonggGame(Game):
if new_cards: if new_cards:
new_cards.reverse() new_cards.reverse()
return new_cards return new_cards
print 'oops! can\'t create a solvable game' print('oops! can\'t create a solvable game')
return old_cards return old_cards
def _shuffleHook2(self, rows, cards): def _shuffleHook2(self, rows, cards):
start_time = time.time() start_time = time.time()
@ -690,15 +694,16 @@ class AbstractMahjonggGame(Game):
break break
# find suitable stacks # find suitable stacks
## suitable_stacks = [] # suitable_stacks = []
## for r in rows: # for r in rows:
## if nc[r.id] is None and is_suitable(r, nc): # if nc[r.id] is None and is_suitable(r, nc):
## suitable_stacks.append(r) # suitable_stacks.append(r)
suitable_stacks = [r for r in rows suitable_stacks = [r for r in rows
if nc[r.id] is None and is_suitable(r, nc)] if nc[r.id] is None and is_suitable(r, nc)]
old_pairs = [] old_pairs = []
i = factorial(len(suitable_stacks))/2/factorial(len(suitable_stacks)-2) i = factorial(len(suitable_stacks))/2 \
/ factorial(len(suitable_stacks)-2)
for j in xrange(i): for j in xrange(i):
if iters[0] > max_iters: if iters[0] > max_iters:
return None return None
@ -728,11 +733,11 @@ class AbstractMahjonggGame(Game):
if ret: if ret:
ret = [x for x in ret if x != 1] ret = [x for x in ret if x != 1]
return ret return ret
nc[s1.id] = nc[s2.id] = None # try another way nc[s1.id] = nc[s2.id] = None # try another way
return None return None
new_cards = [None]*len(self.s.rows) # None - empty stack, 1 - non-used new_cards = [None]*len(self.s.rows) # None - empty stack, 1 - non-used
drows = dict.fromkeys(rows) # optimization drows = dict.fromkeys(rows) # optimization
for r in self.s.rows: for r in self.s.rows:
if r not in drows: if r not in drows:
@ -742,16 +747,16 @@ class AbstractMahjonggGame(Game):
while True: while True:
ret = create_solvable(cards[:], new_cards) ret = create_solvable(cards[:], new_cards)
if DEBUG: if DEBUG:
print 'create_solvable time:', time.time() - start_time print('create_solvable time:', time.time() - start_time)
if ret: if ret:
ret.reverse() ret.reverse()
return ret return ret
if time.time() - start_time > max_time or \ if time.time() - start_time > max_time or \
iters[0] <= max_iters: iters[0] <= max_iters:
print 'oops! can\'t create a solvable game' print('oops! can\'t create a solvable game')
return None return None
iters = [0] iters = [0]
print 'oops! can\'t create a solvable game' print('oops! can\'t create a solvable game')
return None return None
def _mahjonggShuffle(self): def _mahjonggShuffle(self):
@ -785,13 +790,13 @@ class AbstractMahjonggGame(Game):
new_cards = self._shuffleHook2(rows, cards) new_cards = self._shuffleHook2(rows, cards)
if new_cards is None: if new_cards is None:
d = MfxMessageDialog(self.top, title=_('Warning'), MfxMessageDialog(self.top, title=_('Warning'),
text=_('''\ text=_('''\
Sorry, I can\'t find Sorry, I can\'t find
a solvable configuration.'''), a solvable configuration.'''),
bitmap='warning') bitmap='warning')
self.leaveState(old_state) self.leaveState(old_state)
##self.finishMove() # self.finishMove()
# hack # hack
am = self.moves.current[0] am = self.moves.current[0]
am.undo(self) # restore random am.undo(self) # restore random
@ -817,7 +822,7 @@ a solvable configuration.'''),
def startGame(self): def startGame(self):
assert len(self.s.talon.cards) == self.NCARDS assert len(self.s.talon.cards) == self.NCARDS
#self.s.talon.dealRow(rows = self.s.rows, frames = 0) # self.s.talon.dealRow(rows = self.s.rows, frames = 0)
n = 12 n = 12
self.s.talon.dealRow(rows=self.s.rows[:self.NCARDS-n], frames=0) self.s.talon.dealRow(rows=self.s.rows[:self.NCARDS-n], frames=0)
self.startDealSample() self.startDealSample()
@ -850,8 +855,8 @@ a solvable configuration.'''),
for t in stacks[i+1:]: for t in stacks[i+1:]:
if self.cardsMatch(r.cards[0], t.cards[0]): if self.cardsMatch(r.cards[0], t.cards[0]):
n += 1 n += 1
#if n == 3: n = 1 # if n == 3: n = 1
#elif n == 2: n = 0 # elif n == 2: n = 0
n = n % 2 n = n % 2
f += n f += n
i += 1 i += 1
@ -881,7 +886,7 @@ a solvable configuration.'''),
# Mahjongg special: highlight all moveable tiles # Mahjongg special: highlight all moveable tiles
return ((self.s.rows, 1),) return ((self.s.rows, 1),)
def _highlightCards(self, info, sleep=1.5, delta=(1,1,1,1)): def _highlightCards(self, info, sleep=1.5, delta=(1, 1, 1, 1)):
if not Image: if not Image:
delta = (-self._delta_x, 0, 0, -self._delta_y) delta = (-self._delta_x, 0, 0, -self._delta_y)
return Game._highlightCards(self, info, sleep=sleep, delta=delta) return Game._highlightCards(self, info, sleep=sleep, delta=delta)
@ -895,9 +900,9 @@ a solvable configuration.'''),
for s, c1, c2, color in info: for s, c1, c2, color in info:
assert c1 is c2 assert c1 is c2
assert c1 in s.cards assert c1 in s.cards
tkraise = False
x, y = s.x, s.y x, y = s.x, s.y
img = self.app.images.getHighlightedCard(c1.deck, c1.suit, c1.rank, 'black') img = self.app.images.getHighlightedCard(
c1.deck, c1.suit, c1.rank, 'black')
if img is None: if img is None:
continue continue
img = MfxCanvasImage(self.canvas, x, y, image=img, img = MfxCanvasImage(self.canvas, x, y, image=img,
@ -944,8 +949,8 @@ a solvable configuration.'''),
return self.getCardFaceImage(deck, suit, rank) return self.getCardFaceImage(deck, suit, rank)
def _createCard(self, id, deck, suit, rank, x, y): def _createCard(self, id, deck, suit, rank, x, y):
##if deck >= 1 and suit == 3 and rank >= 4: # if deck >= 1 and suit == 3 and rank >= 4:
if deck%4 and suit == 3 and rank >= 4: if deck % 4 and suit == 3 and rank >= 4:
return None return None
return Game._createCard(self, id, deck, suit, rank, x, y) return Game._createCard(self, id, deck, suit, rank, x, y)
@ -977,11 +982,11 @@ a solvable configuration.'''),
return card1.rank == card2.rank return card1.rank == card2.rank
## mahjongg util # mahjongg util
def comp_cardset(ncards): def comp_cardset(ncards):
# calc decks, ranks & trumps # calc decks, ranks & trumps
assert ncards % 4 == 0 assert ncards % 4 == 0
assert 0 < ncards <= 288 # ??? assert 0 < ncards <= 288 # ???
decks = 1 decks = 1
cards = ncards/4 cards = ncards/4
if ncards > 144: if ncards > 144:
@ -1001,7 +1006,6 @@ def comp_cardset(ncards):
# * register a Mahjongg type game # * register a Mahjongg type game
# ************************************************************************ # ************************************************************************
from new import classobj
def r(id, short_name, name=None, ncards=144, layout=None): def r(id, short_name, name=None, ncards=144, layout=None):
assert layout assert layout
@ -1014,7 +1018,7 @@ def r(id, short_name, name=None, ncards=144, layout=None):
gameclass.NCARDS = ncards gameclass.NCARDS = ncards
decks, ranks, trumps = comp_cardset(ncards) decks, ranks, trumps = comp_cardset(ncards)
gi = GameInfo(id, gameclass, name, gi = GameInfo(id, gameclass, name,
GI.GT_MAHJONGG, 4*decks, 0, ##GI.SL_MOSTLY_SKILL, GI.GT_MAHJONGG, 4*decks, 0, # GI.SL_MOSTLY_SKILL,
category=GI.GC_MAHJONGG, short_name=short_name, category=GI.GC_MAHJONGG, short_name=short_name,
suits=range(3), ranks=range(ranks), trumps=range(trumps), suits=range(3), ranks=range(ranks), trumps=range(trumps),
si={"decks": decks, "ncards": ncards}) si={"decks": decks, "ncards": ncards})
@ -1022,4 +1026,3 @@ def r(id, short_name, name=None, ncards=144, layout=None):
gi.rules_filename = "mahjongg.html" gi.rules_filename = "mahjongg.html"
registerGame(gi) registerGame(gi)
return gi return gi

View file

@ -24,10 +24,10 @@
from mahjongg import r from mahjongg import r
# test # test
#r(5991, "AAA 1", ncards=4, layout="0daa") # r(5991, "AAA 1", ncards=4, layout="0daa")
#r(5992, "AAA 2", ncards=8, layout="0daadca") # r(5992, "AAA 2", ncards=8, layout="0daadca")
#r(5993, "AAA 3", ncards=20, layout="0daaCabdacKbbdcaCcbdcc") # r(5993, "AAA 3", ncards=20, layout="0daaCabdacKbbdcaCcbdcc")
#r(5994, "AAA 4", ncards=20, layout="0daaDabdacdcaDcbdcc") # r(5994, "AAA 4", ncards=20, layout="0daaDabdacdcaDcbdcc")
# ************************************************************************ # ************************************************************************
# * game definitions # * game definitions

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*- # -*- mode: python; coding: utf-8; -*-
# ---------------------------------------------------------------------------## # ---------------------------------------------------------------------------
# #
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer # Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
# Copyright (C) 2003 Mt. Hood Playing Card Co. # Copyright (C) 2003 Mt. Hood Playing Card Co.
@ -19,36 +19,43 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# ---------------------------------------------------------------------------## # ---------------------------------------------------------------------------
__all__ = [] __all__ = []
# Imports # Imports
import sys import sys
#from tkFont import Font # from tkFont import Font
from gettext import ungettext from gettext import ungettext
# PySol imports # PySol imports
from pysollib.mygettext import _, n_ from pysollib.mygettext import _
from pysollib.gamedb import registerGame, GameInfo, GI from pysollib.gamedb import registerGame, GameInfo, GI
from pysollib.util import *
from pysollib.mfxutil import kwdefault from pysollib.mfxutil import kwdefault
from pysollib.stack import *
from pysollib.game import Game
from pysollib.layout import Layout from pysollib.layout import Layout
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint from pysollib.hint import AbstractHint
from pysollib.pysoltk import MfxCanvasText, MfxCanvasLine from pysollib.pysoltk import MfxCanvasText, MfxCanvasLine
from mahjongg import Mahjongg_RowStack, AbstractMahjonggGame, comp_cardset from mahjongg import Mahjongg_RowStack, AbstractMahjonggGame, comp_cardset
from pysollib.util import ANY_SUIT
from pysollib.stack import \
AbstractFoundationStack, \
InitialDealTalonStack
if sys.version_info > (3,):
xrange = range
# ************************************************************************ # ************************************************************************
# * # *
# ************************************************************************ # ************************************************************************
class Shisen_Hint(AbstractHint): class Shisen_Hint(AbstractHint):
TOP_MATCHING = False TOP_MATCHING = False
# FIXME: no intelligence whatsoever is implemented here # FIXME: no intelligence whatsoever is implemented here
def computeHints(self): def computeHints(self):
game = self.game game = self.game
# get free stacks # get free stacks
@ -60,7 +67,7 @@ class Shisen_Hint(AbstractHint):
i = 0 i = 0
for r in stacks: for r in stacks:
for t in stacks[i+1:]: for t in stacks[i+1:]:
#if game.cardsMatch(r.cards[0], t.cards[0]): # if game.cardsMatch(r.cards[0], t.cards[0]):
if r.acceptsCards(t, t.cards): if r.acceptsCards(t, t.cards):
# simple scoring... # simple scoring...
if self.TOP_MATCHING: if self.TOP_MATCHING:
@ -122,7 +129,7 @@ class Shisen_RowStack(Mahjongg_RowStack):
if nx < 0 or ny < 0 or nx > cols+1 or ny > rows+1: if nx < 0 or ny < 0 or nx > cols+1 or ny > rows+1:
return 0 return 0
if nx in (0, cols+1) or ny in (0, rows+1) \ if nx in (0, cols+1) or ny in (0, rows+1) \
or not game_cols[nx-1][ny-1].cards: or not game_cols[nx-1][ny-1].cards:
if direct_chng_cnt == 0: if direct_chng_cnt == 0:
return 1 return 1
elif direct_chng_cnt == 1: elif direct_chng_cnt == 1:
@ -159,20 +166,21 @@ class Shisen_RowStack(Mahjongg_RowStack):
return 0 return 0
res_path = [None] res_path = [None]
def do_accepts(x, y, direct, direct_chng_cnt, path): def do_accepts(x, y, direct, direct_chng_cnt, path):
#if direct_chng_cnt > 3: # if direct_chng_cnt > 3:
# return # return
if a[x][y] < direct_chng_cnt: if a[x][y] < direct_chng_cnt:
return return
#if res_path[0]: # if res_path[0]:
# return # return
a[x][y] = direct_chng_cnt a[x][y] = direct_chng_cnt
if x == x2 and y == y2: if x == x2 and y == y2:
res_path[0] = path res_path[0] = path
return return
if can_move(x, y, x, y+1, direct, 1, direct_chng_cnt): #### 1 if can_move(x, y, x, y+1, direct, 1, direct_chng_cnt): # 1
#dcc = direct == 1 and direct_chng_cnt or direct_chng_cnt+1 # dcc = direct == 1 and direct_chng_cnt or direct_chng_cnt+1
p = path[:] p = path[:]
if direct == 1: if direct == 1:
dcc = direct_chng_cnt dcc = direct_chng_cnt
@ -180,8 +188,8 @@ class Shisen_RowStack(Mahjongg_RowStack):
dcc = direct_chng_cnt+1 dcc = direct_chng_cnt+1
p.append((x, y)) p.append((x, y))
do_accepts(x, y+1, 1, dcc, p) do_accepts(x, y+1, 1, dcc, p)
if can_move(x, y, x, y-1, direct, 2, direct_chng_cnt): #### 2 if can_move(x, y, x, y-1, direct, 2, direct_chng_cnt): # 2
#dcc = direct == 2 and direct_chng_cnt or direct_chng_cnt+1 # dcc = direct == 2 and direct_chng_cnt or direct_chng_cnt+1
p = path[:] p = path[:]
if direct == 2: if direct == 2:
dcc = direct_chng_cnt dcc = direct_chng_cnt
@ -189,8 +197,8 @@ class Shisen_RowStack(Mahjongg_RowStack):
dcc = direct_chng_cnt+1 dcc = direct_chng_cnt+1
p.append((x, y)) p.append((x, y))
do_accepts(x, y-1, 2, dcc, p) do_accepts(x, y-1, 2, dcc, p)
if can_move(x, y, x+1, y, direct, 3, direct_chng_cnt): #### 3 if can_move(x, y, x+1, y, direct, 3, direct_chng_cnt): # 3
#dcc = direct == 3 and direct_chng_cnt or direct_chng_cnt+1 # dcc = direct == 3 and direct_chng_cnt or direct_chng_cnt+1
p = path[:] p = path[:]
if direct == 3: if direct == 3:
dcc = direct_chng_cnt dcc = direct_chng_cnt
@ -198,8 +206,8 @@ class Shisen_RowStack(Mahjongg_RowStack):
dcc = direct_chng_cnt+1 dcc = direct_chng_cnt+1
p.append((x, y)) p.append((x, y))
do_accepts(x+1, y, 3, dcc, p) do_accepts(x+1, y, 3, dcc, p)
if can_move(x, y, x-1, y, direct, 4, direct_chng_cnt): #### 4 if can_move(x, y, x-1, y, direct, 4, direct_chng_cnt): # 4
#dcc = direct == 4 and direct_chng_cnt or direct_chng_cnt+1 # dcc = direct == 4 and direct_chng_cnt or direct_chng_cnt+1
p = path[:] p = path[:]
if direct == 4: if direct == 4:
dcc = direct_chng_cnt dcc = direct_chng_cnt
@ -209,18 +217,17 @@ class Shisen_RowStack(Mahjongg_RowStack):
do_accepts(x-1, y, 4, dcc, p) do_accepts(x-1, y, 4, dcc, p)
do_accepts(x1, y1, 0, 0, []) do_accepts(x1, y1, 0, 0, [])
#from pprint import pprint # from pprint import pprint
#pprint(a) # pprint(a)
if a[x2][y2] > 3: if a[x2][y2] > 3:
return None return None
res_path = res_path[0] res_path = res_path[0]
res_path.append((x2, y2)) res_path.append((x2, y2))
#print res_path # print res_path
return res_path return res_path
def fillStack(self): def fillStack(self):
self.game.fillStack(self) self.game.fillStack(self)
@ -229,13 +236,14 @@ class Shisen_RowStack(Mahjongg_RowStack):
if to_stack.cards: if to_stack.cards:
self._dropPairMove(ncards, to_stack, frames=-1, shadow=shadow) self._dropPairMove(ncards, to_stack, frames=-1, shadow=shadow)
else: else:
Mahjongg_RowStack.moveMove(self, ncards, to_stack, frames=frames, shadow=shadow) Mahjongg_RowStack.moveMove(self, ncards, to_stack, frames=frames,
shadow=shadow)
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1): def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
game = self.game game = self.game
old_state = game.enterState(game.S_FILL) old_state = game.enterState(game.S_FILL)
f = game.s.foundations[0] f = game.s.foundations[0]
game.updateStackMove(game.s.talon, 2|16) # for undo game.updateStackMove(game.s.talon, 2 | 16) # for undo
if not game.demo: if not game.demo:
if game.app.opt.shisen_show_hint: if game.app.opt.shisen_show_hint:
self.drawArrow(other_stack, game.app.opt.timeouts['hint']) self.drawArrow(other_stack, game.app.opt.timeouts['hint'])
@ -245,23 +253,22 @@ class Shisen_RowStack(Mahjongg_RowStack):
game.moveMove(n, other_stack, f, frames=frames, shadow=shadow) game.moveMove(n, other_stack, f, frames=frames, shadow=shadow)
self.fillStack() self.fillStack()
other_stack.fillStack() other_stack.fillStack()
game.updateStackMove(game.s.talon, 1|16) # for redo game.updateStackMove(game.s.talon, 1 | 16) # for redo
game.leaveState(old_state) game.leaveState(old_state)
def drawArrow(self, other_stack, sleep): def drawArrow(self, other_stack, sleep):
game = self.game game = self.game
images = game.app.images images = game.app.images
cs = game.app.cardset cs = game.app.cardset
path = self.acceptsCards(other_stack, [other_stack.cards[-1]]) path = self.acceptsCards(other_stack, [other_stack.cards[-1]])
#print path # print path
x0, y0 = game.XMARGIN, game.YMARGIN x0, y0 = game.XMARGIN, game.YMARGIN
cardw, cardh = images.CARDW, images.CARDH cardw, cardh = images.CARDW, images.CARDH
if cs.version >= 6: if cs.version >= 6:
cardw -= cs.SHADOW_XOFFSET cardw -= cs.SHADOW_XOFFSET
cardh -= cs.SHADOW_YOFFSET cardh -= cs.SHADOW_YOFFSET
coords = [] coords = []
dx, dy = game._delta_x, game._delta_y dx = game._delta_x
xf, yf = images._xfactor, images._yfactor xf, yf = images._xfactor, images._yfactor
for x, y in path: for x, y in path:
if x == 0: if x == 0:
@ -276,17 +283,17 @@ class Shisen_RowStack(Mahjongg_RowStack):
coords.append(int(round(yf * (y0+cardh*(y-1)+6)))) coords.append(int(round(yf * (y0+cardh*(y-1)+6))))
else: else:
coords.append(int(round(yf * (y0+cardh/2+cardh*(y-1))))) coords.append(int(round(yf * (y0+cardh/2+cardh*(y-1)))))
#print coords # print coords
##s1 = min(cardw/2, cardh/2, 30) # s1 = min(cardw/2, cardh/2, 30)
##w = min(s1/3, 7) # w = min(s1/3, 7)
##s2 = min(w, 10) # s2 = min(w, 10)
w = 7 w = 7
arrow = MfxCanvasLine(game.canvas, arrow = MfxCanvasLine(game.canvas,
coords, coords,
{'width': w, {'width': w,
'fill': game.app.opt.colors['hintarrow'], 'fill': game.app.opt.colors['hintarrow'],
##'arrow': 'last', # 'arrow': 'last',
##'arrowshape': (s1, s1, s2) # 'arrowshape': (s1, s1, s2)
} }
) )
game.canvas.update_idletasks() game.canvas.update_idletasks()
@ -297,10 +304,10 @@ class Shisen_RowStack(Mahjongg_RowStack):
class AbstractShisenGame(AbstractMahjonggGame): class AbstractShisenGame(AbstractMahjonggGame):
Hint_Class = NotShisen_Hint #Shisen_Hint Hint_Class = NotShisen_Hint # Shisen_Hint
RowStack_Class = Shisen_RowStack RowStack_Class = Shisen_RowStack
#NCARDS = 144 # NCARDS = 144
GRAVITY = True GRAVITY = True
def createGame(self): def createGame(self):
@ -309,7 +316,7 @@ class AbstractShisenGame(AbstractMahjonggGame):
# start layout # start layout
l, s = Layout(self), self.s l, s = Layout(self), self.s
##dx, dy = 3, -3 # dx, dy = 3, -3
cs = self.app.cardset cs = self.app.cardset
if cs.version >= 6: if cs.version >= 6:
@ -328,7 +335,7 @@ class AbstractShisenGame(AbstractMahjonggGame):
font = self.app.getFont("canvas_default") font = self.app.getFont("canvas_default")
# width of self.texts.info # width of self.texts.info
#ti_width = Font(self.canvas, font).measure(_('Remaining')) # ti_width = Font(self.canvas, font).measure(_('Remaining'))
ti_width = 80 ti_width = 80
# set window size # set window size
@ -358,8 +365,8 @@ class AbstractShisenGame(AbstractMahjonggGame):
stack.coln, stack.rown = col, row stack.coln, stack.rown = col, row
s.rows.append(stack) s.rows.append(stack)
self.cols[col].append(stack) self.cols[col].append(stack)
#from pprint import pprint # from pprint import pprint
#pprint(self.cols) # pprint(self.cols)
# create other stacks # create other stacks
y = l.YM + dyy y = l.YM + dyy
@ -376,7 +383,8 @@ class AbstractShisenGame(AbstractMahjonggGame):
l.defaultStackGroups() l.defaultStackGroups()
def fillStack(self, stack): def fillStack(self, stack):
if not self.GRAVITY: return if not self.GRAVITY:
return
to_stack = stack to_stack = stack
for from_stack in self.cols[stack.coln][stack.rown+1::-1]: for from_stack in self.cols[stack.coln][stack.rown+1::-1]:
if not from_stack.cards: if not from_stack.cards:
@ -419,13 +427,11 @@ class AbstractShisenGame(AbstractMahjonggGame):
self.NCARDS - t) % (self.NCARDS - t) self.NCARDS - t) % (self.NCARDS - t)
t = r1 + r2 + f t = r1 + r2 + f
self.texts.info.config(text = t) self.texts.info.config(text=t)
def drawHintArrow(self, from_stack, to_stack, ncards, sleep): def drawHintArrow(self, from_stack, to_stack, ncards, sleep):
from_stack.drawArrow(to_stack, sleep) from_stack.drawArrow(to_stack, sleep)
def _shuffleHook(self, cards): def _shuffleHook(self, cards):
return cards return cards
@ -436,23 +442,28 @@ class AbstractShisenGame(AbstractMahjonggGame):
class Shisen_18x8(AbstractShisenGame): class Shisen_18x8(AbstractShisenGame):
L = (18, 8) L = (18, 8)
class Shisen_14x6(AbstractShisenGame): class Shisen_14x6(AbstractShisenGame):
L = (14, 6) L = (14, 6)
NCARDS = 84 NCARDS = 84
class Shisen_24x12(AbstractShisenGame): class Shisen_24x12(AbstractShisenGame):
L = (24, 12) L = (24, 12)
NCARDS = 288 NCARDS = 288
class Shisen_18x8_NoGravity(AbstractShisenGame): class Shisen_18x8_NoGravity(AbstractShisenGame):
L = (18, 8) L = (18, 8)
GRAVITY = False GRAVITY = False
class Shisen_14x6_NoGravity(AbstractShisenGame): class Shisen_14x6_NoGravity(AbstractShisenGame):
L = (14, 6) L = (14, 6)
NCARDS = 84 NCARDS = 84
GRAVITY = False GRAVITY = False
class Shisen_24x12_NoGravity(AbstractShisenGame): class Shisen_24x12_NoGravity(AbstractShisenGame):
L = (24, 12) L = (24, 12)
NCARDS = 288 NCARDS = 288
@ -479,11 +490,13 @@ class NotShisen_14x6(AbstractShisenGame):
L = (14, 6) L = (14, 6)
NCARDS = 84 NCARDS = 84
class NotShisen_18x8(AbstractShisenGame): class NotShisen_18x8(AbstractShisenGame):
Hint_Class = NotShisen_Hint Hint_Class = NotShisen_Hint
RowStack_Class = NotShisen_RowStack RowStack_Class = NotShisen_RowStack
L = (18, 8) L = (18, 8)
class NotShisen_24x12(AbstractShisenGame): class NotShisen_24x12(AbstractShisenGame):
Hint_Class = NotShisen_Hint Hint_Class = NotShisen_Hint
RowStack_Class = NotShisen_RowStack RowStack_Class = NotShisen_RowStack
@ -507,6 +520,7 @@ def r(id, gameclass, name, rules_filename="shisensho.html"):
registerGame(gi) registerGame(gi)
return gi return gi
r(11001, Shisen_14x6, "Shisen-Sho 14x6") r(11001, Shisen_14x6, "Shisen-Sho 14x6")
r(11002, Shisen_18x8, "Shisen-Sho 18x8") r(11002, Shisen_18x8, "Shisen-Sho 18x8")
r(11003, Shisen_24x12, "Shisen-Sho 24x12") r(11003, Shisen_24x12, "Shisen-Sho 24x12")

View file

@ -13,6 +13,10 @@ my %skip =
map { $_ => 1 } map { $_ => 1 }
qw( qw(
./pysollib/games/__init__.py ./pysollib/games/__init__.py
./pysollib/games/mahjongg/__init__.py
./pysollib/games/mahjongg/mahjongg1.py
./pysollib/games/mahjongg/mahjongg2.py
./pysollib/games/mahjongg/mahjongg3.py
./pysollib/games/ultra/__init__.py ./pysollib/games/ultra/__init__.py
./pysollib/pysoltk.py ./pysollib/pysoltk.py
./pysollib/tile/ttk.py ./pysollib/tile/ttk.py
@ -21,7 +25,7 @@ my %skip =
# my $cmd = shell_quote( 'flake8', '.' ); # my $cmd = shell_quote( 'flake8', '.' );
my $cmd = shell_quote( 'flake8', my $cmd = shell_quote( 'flake8',
grep { not exists $skip{$_} } glob('./pysollib/*.py ./pysollib/[cmpuw]*/*.py ./pysollib/tile/*.py ./pysollib/ui/tktile/*.py ./pysollib/games/*.py ./pysollib/games/ultra/*.py') ); grep { not exists $skip{$_} } glob('./pysollib/*.py ./pysollib/[cmpuw]*/*.py ./pysollib/tile/*.py ./pysollib/ui/tktile/*.py ./pysollib/games/*.py ./pysollib/games/[mu]*/*.py') );
# TEST # TEST
eq_or_diff( scalar(`$cmd`), '', "flake8 is happy with the code." ); eq_or_diff( scalar(`$cmd`), '', "flake8 is happy with the code." );