From 500d8635f9b737783c7779124d306b7602d6c409 Mon Sep 17 00:00:00 2001 From: skomoroh Date: Thu, 17 May 2007 21:39:29 +0000 Subject: [PATCH] + 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 --- pysollib/actions.py | 14 +++ pysollib/game.py | 4 + pysollib/games/mahjongg/mahjongg.py | 157 ++++++++++++++++++++------- pysollib/games/mahjongg/shisensho.py | 3 + pysollib/tile/menubar.py | 2 + pysollib/tile/toolbar.py | 1 + pysollib/tk/menubar.py | 2 + pysollib/tk/toolbar.py | 1 + 8 files changed, 142 insertions(+), 42 deletions(-) diff --git a/pysollib/actions.py b/pysollib/actions.py index f31ada60..1c69c74f 100644 --- a/pysollib/actions.py +++ b/pysollib/actions.py @@ -88,6 +88,7 @@ class PysolMenubarActions: hint = 0, autofaceup = 0, autodrop = 0, + shuffle = 0, autodeal = 0, quickplay = 0, demo = 0, @@ -195,6 +196,8 @@ class PysolMenubarActions: ms.pause = 1 if game.gameinfo.si.game_type == GI.GT_CUSTOM: ms.custom_game = 1 + if game.canShuffle(): + ms.shuffle = 1 # update menu items and toolbar def _updateMenus(self): @@ -235,6 +238,7 @@ class PysolMenubarActions: self.setToolbarState(ms.undo, "undo") self.setToolbarState(ms.redo, "redo") self.setToolbarState(ms.autodrop, "autodrop") + self.setToolbarState(ms.shuffle, "shuffle") self.setToolbarState(ms.pause, "pause") self.setToolbarState(ms.rules, "rules") @@ -487,6 +491,11 @@ class PysolMenubarActions: ##self.game.autoPlay(autofaceup=1, autodrop=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): if self._cancelDrag(break_pause=False): return self.mPlayerStats(mode=100) @@ -889,6 +898,11 @@ class PysolToolbarActions: self.menubar.mDrop() return 1 + def mShuffle(self, *args): + if not self._busy(): + self.menubar.mShuffle() + return 1 + def mPause(self, *args): if not self._busy(): self.menubar.mPause() diff --git a/pysollib/game.py b/pysollib/game.py index 6b67a47e..abaaaf78 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -1588,6 +1588,10 @@ class Game: def canRedo(self): return self.canUndo() + # Mahjongg + def canShuffle(self): + return False + # # Game - stats handlers diff --git a/pysollib/games/mahjongg/mahjongg.py b/pysollib/games/mahjongg/mahjongg.py index 5a989b5c..dabd9042 100644 --- a/pysollib/games/mahjongg/mahjongg.py +++ b/pysollib/games/mahjongg/mahjongg.py @@ -29,6 +29,7 @@ __all__ = [] # Imports import sys, re import time +from gettext import ungettext #from tkFont import Font # PySol imports @@ -39,8 +40,9 @@ 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, \ - EVENT_HANDLED, ANCHOR_NW +from pysollib.pysoltk import MfxCanvasText, MfxCanvasImage +from pysollib.pysoltk import bind, EVENT_HANDLED, ANCHOR_NW +from pysollib.pysoltk import MfxMessageDialog from pysollib.settings import TOOLKIT @@ -72,7 +74,14 @@ class Mahjongg_Hint(AbstractHint): for t in stacks[i+1:]: if game.cardsMatch(r.cards[0], t.cards[0]): # 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) i = i + 1 @@ -302,18 +311,10 @@ class AbstractMahjonggGame(Game): Hint_Class = Mahjongg_Hint RowStack_Class = Mahjongg_RowStack - GAME_VERSION = 2 + GAME_VERSION = 3 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): # decode tile positions L = self.L @@ -549,7 +550,10 @@ class AbstractMahjonggGame(Game): # easy return self._shuffleHook1(cards[:]) # 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): @@ -625,7 +629,7 @@ class AbstractMahjonggGame(Game): return old_cards - def _shuffleHook2(self, cards): + def _shuffleHook2(self, rows, cards): start_time = time.time() iters = [0] @@ -633,37 +637,35 @@ class AbstractMahjonggGame(Game): max_time = 2.0 # seconds max_iters = len(cards) - rows = self.s.rows - def is_suitable(stack, cards): for s in stack.blockmap.below: + if cards[s.id] == 1: + continue # check if below stacks are non-empty if cards[s.id] is None: return False - nleft = 0 for s in stack.blockmap.left: + if cards[s.id] == 1: + continue if cards[s.id] is None: for t in s.blockmap.all_left: + if cards[t.id] == 1: + continue if cards[t.id] is not None: # we have empty stack between two non-empty return False - else: - nleft += 1 - nright = 0 for s in stack.blockmap.right: + if cards[s.id] == 1: + continue if cards[s.id] is None: for t in s.blockmap.all_right: + if cards[t.id] == 1: + continue if cards[t.id] is not None: # we have empty stack between two non-empty return False - else: - nright += 1 - - if nleft > 0 and nright > 0: - # we have left and right non-empty stacks - return False return True def create_solvable(cards, new_cards): @@ -713,7 +715,7 @@ class AbstractMahjonggGame(Game): # select two suitable stacks s1 = suitable_stacks[r1] s2 = suitable_stacks[r2] - # + # check if s1 don't block s2 nc[s1.id] = c1 if not is_suitable(s2, nc): nc[s1.id] = None @@ -722,31 +724,96 @@ class AbstractMahjonggGame(Game): # check if this layout is solvable (backtracking) ret = create_solvable(cards[:], nc) if ret: + ret = filter(lambda x: x != 1, ret) return ret nc[s1.id] = nc[s2.id] = None # try another way 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: - if time.time() - start_time > max_time: - print 'oops! can\'t create a solvable game' - return cards - ret = create_solvable(cards[:], [None]*len(cards)) + ret = create_solvable(cards[:], new_cards) if ret: ret.reverse() 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] 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): 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.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:]) + self.s.talon.dealRow(rows=self.s.rows[self.NCARDS-n:]) assert len(self.s.talon.cards) == 0 def isGameWon(self): @@ -763,6 +830,7 @@ class AbstractMahjonggGame(Game): def updateText(self): if self.preview > 1 or self.texts.info is None: return + # find matching tiles stacks = [] for r in self.s.rows: @@ -781,16 +849,21 @@ class AbstractMahjonggGame(Game): i += 1 if f == 0: - f = self.text_free_matching_pairs_0 - elif f == 1: - f = self.text_free_matching_pairs_1 + f = _('No Free\nMatching\nPairs') 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 = str(t) + self.text_tiles_removed \ - + str(self.NCARDS - t) + self.text_tiles_remaining \ - + f - self.texts.info.config(text = t) + r1 = ungettext('%d\nTile\nRemoved\n\n', + '%d\nTiles\nRemoved\n\n', + t) % 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 diff --git a/pysollib/games/mahjongg/shisensho.py b/pysollib/games/mahjongg/shisensho.py index c47ae9c3..47325358 100644 --- a/pysollib/games/mahjongg/shisensho.py +++ b/pysollib/games/mahjongg/shisensho.py @@ -417,6 +417,9 @@ class AbstractShisenGame(AbstractMahjonggGame): def _shuffleHook(self, cards): return cards + def canShuffle(self): + return False + class Shisen_18x8(AbstractShisenGame): L = (18, 8) diff --git a/pysollib/tile/menubar.py b/pysollib/tile/menubar.py index c284900c..ec97a347 100644 --- a/pysollib/tile/menubar.py +++ b/pysollib/tile/menubar.py @@ -574,6 +574,8 @@ class PysolMenubar(PysolMenubarActions): self._bindKey("", "F2", self.mStackDesk) # self._bindKey("", "slash", self.mGameInfo) # undocumented, devel + # + self._bindKey("", "f", self.mShuffle) for i in range(9): self._bindKey(ctrl, str(i+1), lambda event, self=self, i=i: self.mGotoBookmark(i, confirm=0)) diff --git a/pysollib/tile/toolbar.py b/pysollib/tile/toolbar.py index 4b7662c1..00fdc02c 100644 --- a/pysollib/tile/toolbar.py +++ b/pysollib/tile/toolbar.py @@ -192,6 +192,7 @@ class PysolToolbar(PysolToolbarActions): (n_("Undo"), self.mUndo, _("Undo last move")), (n_("Redo"), self.mRedo, _("Redo last move")), (n_("Autodrop"), self.mDrop, _("Auto drop cards")), + (n_("Shuffle"), self.mShuffle, _("Shuffle tiles")), (n_("Pause"), self.mPause, _("Pause game")), (None, None, None), (n_("Statistics"), self.mPlayerStats, _("View statistics")), diff --git a/pysollib/tk/menubar.py b/pysollib/tk/menubar.py index 92ac7b59..35a4f9f4 100644 --- a/pysollib/tk/menubar.py +++ b/pysollib/tk/menubar.py @@ -578,6 +578,8 @@ class PysolMenubar(PysolMenubarActions): self._bindKey("", "F2", self.mStackDesk) # self._bindKey("", "slash", self.mGameInfo) # undocumented, devel + # + self._bindKey("", "f", self.mShuffle) for i in range(9): self._bindKey(ctrl, str(i+1), lambda event, self=self, i=i: self.mGotoBookmark(i, confirm=0)) diff --git a/pysollib/tk/toolbar.py b/pysollib/tk/toolbar.py index 9fbd5621..b4f59b80 100644 --- a/pysollib/tk/toolbar.py +++ b/pysollib/tk/toolbar.py @@ -195,6 +195,7 @@ class PysolToolbar(PysolToolbarActions): (n_("Undo"), self.mUndo, _("Undo last move")), (n_("Redo"), self.mRedo, _("Redo last move")), (n_("Autodrop"), self.mDrop, _("Auto drop cards")), + (n_("Shuffle"), self.mShuffle, _("Shuffle tiles")), (n_("Pause"), self.mPause, _("Pause game")), (None, None, None), (n_("Statistics"), self.mPlayerStats, _("View statistics")),