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

+ added shuffle to mahjongg games

git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@166 efabe8c0-fbe8-4139-b769-b5e6d273206e
This commit is contained in:
skomoroh 2007-05-17 21:39:29 +00:00
parent 933dc7b4cc
commit 500d8635f9
8 changed files with 142 additions and 42 deletions

View file

@ -88,6 +88,7 @@ class PysolMenubarActions:
hint = 0, hint = 0,
autofaceup = 0, autofaceup = 0,
autodrop = 0, autodrop = 0,
shuffle = 0,
autodeal = 0, autodeal = 0,
quickplay = 0, quickplay = 0,
demo = 0, demo = 0,
@ -195,6 +196,8 @@ class PysolMenubarActions:
ms.pause = 1 ms.pause = 1
if game.gameinfo.si.game_type == GI.GT_CUSTOM: if game.gameinfo.si.game_type == GI.GT_CUSTOM:
ms.custom_game = 1 ms.custom_game = 1
if game.canShuffle():
ms.shuffle = 1
# update menu items and toolbar # update menu items and toolbar
def _updateMenus(self): def _updateMenus(self):
@ -235,6 +238,7 @@ class PysolMenubarActions:
self.setToolbarState(ms.undo, "undo") self.setToolbarState(ms.undo, "undo")
self.setToolbarState(ms.redo, "redo") self.setToolbarState(ms.redo, "redo")
self.setToolbarState(ms.autodrop, "autodrop") self.setToolbarState(ms.autodrop, "autodrop")
self.setToolbarState(ms.shuffle, "shuffle")
self.setToolbarState(ms.pause, "pause") self.setToolbarState(ms.pause, "pause")
self.setToolbarState(ms.rules, "rules") self.setToolbarState(ms.rules, "rules")
@ -487,6 +491,11 @@ class PysolMenubarActions:
##self.game.autoPlay(autofaceup=1, autodrop=1) ##self.game.autoPlay(autofaceup=1, autodrop=1)
self.game.autoDrop(autofaceup=1) self.game.autoDrop(autofaceup=1)
def mShuffle(self, *args):
if self._cancelDrag(): return
if self.game.canShuffle():
self.game._mahjonggShuffle()
def mStatus(self, *args): def mStatus(self, *args):
if self._cancelDrag(break_pause=False): return if self._cancelDrag(break_pause=False): return
self.mPlayerStats(mode=100) self.mPlayerStats(mode=100)
@ -889,6 +898,11 @@ class PysolToolbarActions:
self.menubar.mDrop() self.menubar.mDrop()
return 1 return 1
def mShuffle(self, *args):
if not self._busy():
self.menubar.mShuffle()
return 1
def mPause(self, *args): def mPause(self, *args):
if not self._busy(): if not self._busy():
self.menubar.mPause() self.menubar.mPause()

View file

@ -1588,6 +1588,10 @@ class Game:
def canRedo(self): def canRedo(self):
return self.canUndo() return self.canUndo()
# Mahjongg
def canShuffle(self):
return False
# #
# Game - stats handlers # Game - stats handlers

View file

@ -29,6 +29,7 @@ __all__ = []
# Imports # Imports
import sys, re import sys, re
import time import time
from gettext import ungettext
#from tkFont import Font #from tkFont import Font
# PySol imports # PySol imports
@ -39,8 +40,9 @@ 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, DefaultHint, CautiousDefaultHint
from pysollib.pysoltk import MfxCanvasText, MfxCanvasImage, bind, \ from pysollib.pysoltk import MfxCanvasText, MfxCanvasImage
EVENT_HANDLED, ANCHOR_NW from pysollib.pysoltk import bind, EVENT_HANDLED, ANCHOR_NW
from pysollib.pysoltk import MfxMessageDialog
from pysollib.settings import TOOLKIT from pysollib.settings import TOOLKIT
@ -72,7 +74,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
tb = t.blockmap
score = \
10000 + \
1000 * (len(rb.below) + len(tb.below)) + \
len(rb.all_left) + len(rb.all_right) + \
len(tb.all_left) + len(tb.all_right)
self.addHint(score, 1, r, t) self.addHint(score, 1, r, t)
i = i + 1 i = i + 1
@ -302,18 +311,10 @@ class AbstractMahjonggGame(Game):
Hint_Class = Mahjongg_Hint Hint_Class = Mahjongg_Hint
RowStack_Class = Mahjongg_RowStack RowStack_Class = Mahjongg_RowStack
GAME_VERSION = 2 GAME_VERSION = 3
NCARDS = 144 NCARDS = 144
# For i18n
text_free_matching_pairs_0 = _("No Free\nMatching\nPairs")
text_free_matching_pairs_1 = _("1 Free\nMatching\nPair")
text_free_matching_pairs_2 = _(" Free\nMatching\nPairs")
text_tiles_removed = _("\nTiles\nRemoved\n\n")
text_tiles_remaining = _("\nTiles\nRemaining\n\n")
def getTiles(self): def getTiles(self):
# decode tile positions # decode tile positions
L = self.L L = self.L
@ -549,7 +550,10 @@ class AbstractMahjonggGame(Game):
# easy # easy
return self._shuffleHook1(cards[:]) return self._shuffleHook1(cards[:])
# hard # hard
return self._shuffleHook2(cards) new_cards = self._shuffleHook2(self.s.rows, cards)
if new_cards is None:
return cards
return new_cards
def _shuffleHook1(self, cards): def _shuffleHook1(self, cards):
@ -625,7 +629,7 @@ class AbstractMahjonggGame(Game):
return old_cards return old_cards
def _shuffleHook2(self, cards): def _shuffleHook2(self, rows, cards):
start_time = time.time() start_time = time.time()
iters = [0] iters = [0]
@ -633,37 +637,35 @@ class AbstractMahjonggGame(Game):
max_time = 2.0 # seconds max_time = 2.0 # seconds
max_iters = len(cards) max_iters = len(cards)
rows = self.s.rows
def is_suitable(stack, cards): def is_suitable(stack, cards):
for s in stack.blockmap.below: for s in stack.blockmap.below:
if cards[s.id] == 1:
continue
# check if below stacks are non-empty # check if below stacks are non-empty
if cards[s.id] is None: if cards[s.id] is None:
return False return False
nleft = 0
for s in stack.blockmap.left: for s in stack.blockmap.left:
if cards[s.id] == 1:
continue
if cards[s.id] is None: if cards[s.id] is None:
for t in s.blockmap.all_left: for t in s.blockmap.all_left:
if cards[t.id] == 1:
continue
if cards[t.id] is not None: if cards[t.id] is not None:
# we have empty stack between two non-empty # we have empty stack between two non-empty
return False return False
else:
nleft += 1
nright = 0
for s in stack.blockmap.right: for s in stack.blockmap.right:
if cards[s.id] == 1:
continue
if cards[s.id] is None: if cards[s.id] is None:
for t in s.blockmap.all_right: for t in s.blockmap.all_right:
if cards[t.id] == 1:
continue
if cards[t.id] is not None: if cards[t.id] is not None:
# we have empty stack between two non-empty # we have empty stack between two non-empty
return False return False
else:
nright += 1
if nleft > 0 and nright > 0:
# we have left and right non-empty stacks
return False
return True return True
def create_solvable(cards, new_cards): def create_solvable(cards, new_cards):
@ -713,7 +715,7 @@ class AbstractMahjonggGame(Game):
# select two suitable stacks # select two suitable stacks
s1 = suitable_stacks[r1] s1 = suitable_stacks[r1]
s2 = suitable_stacks[r2] s2 = suitable_stacks[r2]
# # check if s1 don't block s2
nc[s1.id] = c1 nc[s1.id] = c1
if not is_suitable(s2, nc): if not is_suitable(s2, nc):
nc[s1.id] = None nc[s1.id] = None
@ -722,31 +724,96 @@ class AbstractMahjonggGame(Game):
# check if this layout is solvable (backtracking) # check if this layout is solvable (backtracking)
ret = create_solvable(cards[:], nc) ret = create_solvable(cards[:], nc)
if ret: if ret:
ret = filter(lambda x: x != 1, ret)
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
drows = dict.fromkeys(rows) # optimization
for r in self.s.rows:
if r not in drows:
new_cards[r.id] = 1
del drows
while True: while True:
if time.time() - start_time > max_time: ret = create_solvable(cards[:], new_cards)
print 'oops! can\'t create a solvable game'
return cards
ret = create_solvable(cards[:], [None]*len(cards))
if ret: if ret:
ret.reverse() ret.reverse()
return ret return ret
if time.time() - start_time > max_time or \
iters[0] <= max_iters:
print 'oops! can\'t create a solvable game'
return None
iters = [0] iters = [0]
print 'oops! can\'t create a solvable game' print 'oops! can\'t create a solvable game'
return cards return None
def _mahjonggShuffle(self):
talon = self.s.talon
rows = []
cards = []
for r in self.s.rows:
if r.cards:
rows.append(r)
cards.append(r.cards[0])
if not rows:
return
if self.app.opt.mahjongg_create_solvable == 0:
self.playSample('turnwaste')
old_state = self.enterState(self.S_FILL)
self.saveSeedMove()
for r in rows:
self.moveMove(1, r, talon, frames=0)
self.shuffleStackMove(talon)
for r in rows:
self.moveMove(1, talon, r, frames=0)
self.leaveState(old_state)
self.finishMove()
return
self.playSample('turnwaste')
old_state = self.enterState(self.S_FILL)
self.saveSeedMove()
new_cards = self._shuffleHook2(rows, cards)
if new_cards is None:
d = MfxMessageDialog(self.top, title=_('Warning'),
text=_('''\
Sorry, I can\'t find
a solvable configuration.'''),
bitmap='warning')
self.leaveState(old_state)
##self.finishMove()
self.moves.current = [] # hack
return
# move new_cards to talon
for c in new_cards:
for r in rows:
if r.cards and r.cards[0] is c:
self.moveMove(1, r, talon, frames=0)
break
# deal
for r in rows:
self.moveMove(1, talon, r, frames=0)
self.leaveState(old_state)
self.finishMove()
def canShuffle(self):
return True
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()
self.s.talon.dealRow(rows = self.s.rows[self.NCARDS-n:]) self.s.talon.dealRow(rows=self.s.rows[self.NCARDS-n:])
assert len(self.s.talon.cards) == 0 assert len(self.s.talon.cards) == 0
def isGameWon(self): def isGameWon(self):
@ -763,6 +830,7 @@ class AbstractMahjonggGame(Game):
def updateText(self): def updateText(self):
if self.preview > 1 or self.texts.info is None: if self.preview > 1 or self.texts.info is None:
return return
# find matching tiles # find matching tiles
stacks = [] stacks = []
for r in self.s.rows: for r in self.s.rows:
@ -781,16 +849,21 @@ class AbstractMahjonggGame(Game):
i += 1 i += 1
if f == 0: if f == 0:
f = self.text_free_matching_pairs_0 f = _('No Free\nMatching\nPairs')
elif f == 1:
f = self.text_free_matching_pairs_1
else: else:
f = str(f) + self.text_free_matching_pairs_2 f = ungettext('%d Free\nMatching\nPair',
'%d Free\nMatching\nPairs',
f) % f
t = sum([len(i.cards) for i in self.s.foundations]) t = sum([len(i.cards) for i in self.s.foundations])
t = str(t) + self.text_tiles_removed \ r1 = ungettext('%d\nTile\nRemoved\n\n',
+ str(self.NCARDS - t) + self.text_tiles_remaining \ '%d\nTiles\nRemoved\n\n',
+ f t) % t
self.texts.info.config(text = t) r2 = ungettext('%d\nTile\nRemaining\n\n',
'%d\nTiles\nRemaining\n\n',
t) % (self.NCARDS - t)
t = r1 + r2 + f
self.texts.info.config(text=t)
# #
# Mahjongg special overrides # Mahjongg special overrides

View file

@ -417,6 +417,9 @@ class AbstractShisenGame(AbstractMahjonggGame):
def _shuffleHook(self, cards): def _shuffleHook(self, cards):
return cards return cards
def canShuffle(self):
return False
class Shisen_18x8(AbstractShisenGame): class Shisen_18x8(AbstractShisenGame):
L = (18, 8) L = (18, 8)

View file

@ -574,6 +574,8 @@ class PysolMenubar(PysolMenubarActions):
self._bindKey("", "F2", self.mStackDesk) self._bindKey("", "F2", self.mStackDesk)
# #
self._bindKey("", "slash", self.mGameInfo) # undocumented, devel self._bindKey("", "slash", self.mGameInfo) # undocumented, devel
#
self._bindKey("", "f", self.mShuffle)
for i in range(9): for i in range(9):
self._bindKey(ctrl, str(i+1), lambda event, self=self, i=i: self.mGotoBookmark(i, confirm=0)) self._bindKey(ctrl, str(i+1), lambda event, self=self, i=i: self.mGotoBookmark(i, confirm=0))

View file

@ -192,6 +192,7 @@ class PysolToolbar(PysolToolbarActions):
(n_("Undo"), self.mUndo, _("Undo last move")), (n_("Undo"), self.mUndo, _("Undo last move")),
(n_("Redo"), self.mRedo, _("Redo last move")), (n_("Redo"), self.mRedo, _("Redo last move")),
(n_("Autodrop"), self.mDrop, _("Auto drop cards")), (n_("Autodrop"), self.mDrop, _("Auto drop cards")),
(n_("Shuffle"), self.mShuffle, _("Shuffle tiles")),
(n_("Pause"), self.mPause, _("Pause game")), (n_("Pause"), self.mPause, _("Pause game")),
(None, None, None), (None, None, None),
(n_("Statistics"), self.mPlayerStats, _("View statistics")), (n_("Statistics"), self.mPlayerStats, _("View statistics")),

View file

@ -578,6 +578,8 @@ class PysolMenubar(PysolMenubarActions):
self._bindKey("", "F2", self.mStackDesk) self._bindKey("", "F2", self.mStackDesk)
# #
self._bindKey("", "slash", self.mGameInfo) # undocumented, devel self._bindKey("", "slash", self.mGameInfo) # undocumented, devel
#
self._bindKey("", "f", self.mShuffle)
for i in range(9): for i in range(9):
self._bindKey(ctrl, str(i+1), lambda event, self=self, i=i: self.mGotoBookmark(i, confirm=0)) self._bindKey(ctrl, str(i+1), lambda event, self=self, i=i: self.mGotoBookmark(i, confirm=0))

View file

@ -195,6 +195,7 @@ class PysolToolbar(PysolToolbarActions):
(n_("Undo"), self.mUndo, _("Undo last move")), (n_("Undo"), self.mUndo, _("Undo last move")),
(n_("Redo"), self.mRedo, _("Redo last move")), (n_("Redo"), self.mRedo, _("Redo last move")),
(n_("Autodrop"), self.mDrop, _("Auto drop cards")), (n_("Autodrop"), self.mDrop, _("Auto drop cards")),
(n_("Shuffle"), self.mShuffle, _("Shuffle tiles")),
(n_("Pause"), self.mPause, _("Pause game")), (n_("Pause"), self.mPause, _("Pause game")),
(None, None, None), (None, None, None),
(n_("Statistics"), self.mPlayerStats, _("View statistics")), (n_("Statistics"), self.mPlayerStats, _("View statistics")),