mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
+ 3 new games
+ bind undo/redo to mouse click on background + `find card' dialog (unfinished) git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@32 efabe8c0-fbe8-4139-b769-b5e6d273206e
This commit is contained in:
parent
51b5dc135c
commit
8283cc8f02
12 changed files with 390 additions and 33 deletions
|
@ -45,6 +45,7 @@ from pysolrandom import constructRandom
|
||||||
from version import VERSION
|
from version import VERSION
|
||||||
from settings import PACKAGE, PACKAGE_URL
|
from settings import PACKAGE, PACKAGE_URL
|
||||||
from settings import TOP_TITLE
|
from settings import TOP_TITLE
|
||||||
|
from gamedb import GI
|
||||||
|
|
||||||
# stats imports
|
# stats imports
|
||||||
from stats import PysolStatsFormatter
|
from stats import PysolStatsFormatter
|
||||||
|
@ -66,6 +67,7 @@ from pysoltk import ColorsDialog
|
||||||
from pysoltk import FontsDialog
|
from pysoltk import FontsDialog
|
||||||
from pysoltk import EditTextDialog
|
from pysoltk import EditTextDialog
|
||||||
from pysoltk import TOOLBAR_BUTTONS
|
from pysoltk import TOOLBAR_BUTTONS
|
||||||
|
from pysoltk import create_find_card_dialog, connect_game_find_card_dialog, destroy_find_card_dialog
|
||||||
from help import helpAbout, helpHTML
|
from help import helpAbout, helpHTML
|
||||||
|
|
||||||
gettext = _
|
gettext = _
|
||||||
|
@ -95,6 +97,7 @@ class PysolMenubarActions:
|
||||||
quickplay = 0,
|
quickplay = 0,
|
||||||
demo = 0,
|
demo = 0,
|
||||||
highlight_piles = 0,
|
highlight_piles = 0,
|
||||||
|
find_card = 0,
|
||||||
rules = 0,
|
rules = 0,
|
||||||
pause = 0,
|
pause = 0,
|
||||||
)
|
)
|
||||||
|
@ -188,9 +191,12 @@ class PysolMenubarActions:
|
||||||
tkopt.splashscreen.set(opt.splashscreen)
|
tkopt.splashscreen.set(opt.splashscreen)
|
||||||
tkopt.sticky_mouse.set(opt.sticky_mouse)
|
tkopt.sticky_mouse.set(opt.sticky_mouse)
|
||||||
tkopt.negative_bottom.set(opt.negative_bottom)
|
tkopt.negative_bottom.set(opt.negative_bottom)
|
||||||
|
|
||||||
for w in TOOLBAR_BUTTONS:
|
for w in TOOLBAR_BUTTONS:
|
||||||
tkopt.toolbar_vars[w].set(opt.toolbar_vars[w])
|
tkopt.toolbar_vars[w].set(opt.toolbar_vars[w])
|
||||||
|
if game.gameinfo.category == GI.GC_FRENCH:
|
||||||
|
connect_game_find_card_dialog(game)
|
||||||
|
else:
|
||||||
|
destroy_find_card_dialog()
|
||||||
|
|
||||||
# will get called after connectGame()
|
# will get called after connectGame()
|
||||||
def updateRecentGamesMenu(self, gameids):
|
def updateRecentGamesMenu(self, gameids):
|
||||||
|
@ -274,6 +280,8 @@ class PysolMenubarActions:
|
||||||
ms.quickplay = 1
|
ms.quickplay = 1
|
||||||
if opt.highlight_piles and game.getHighlightPilesStacks():
|
if opt.highlight_piles and game.getHighlightPilesStacks():
|
||||||
ms.highlight_piles = 1
|
ms.highlight_piles = 1
|
||||||
|
if game.gameinfo.category == GI.GC_FRENCH:
|
||||||
|
ms.find_card = 1
|
||||||
if game.app.getGameRulesFilename(game.id): # note: this may return ""
|
if game.app.getGameRulesFilename(game.id): # note: this may return ""
|
||||||
ms.rules = 1
|
ms.rules = 1
|
||||||
if not game.finished:
|
if not game.finished:
|
||||||
|
@ -301,6 +309,7 @@ class PysolMenubarActions:
|
||||||
# Assist menu
|
# Assist menu
|
||||||
self.setMenuState(ms.hint, "assist.hint")
|
self.setMenuState(ms.hint, "assist.hint")
|
||||||
self.setMenuState(ms.highlight_piles, "assist.highlightpiles")
|
self.setMenuState(ms.highlight_piles, "assist.highlightpiles")
|
||||||
|
self.setMenuState(ms.find_card, "assist.findcard")
|
||||||
self.setMenuState(ms.demo, "assist.demo")
|
self.setMenuState(ms.demo, "assist.demo")
|
||||||
self.setMenuState(ms.demo, "assist.demoallgames")
|
self.setMenuState(ms.demo, "assist.demoallgames")
|
||||||
# Options menu
|
# Options menu
|
||||||
|
@ -589,6 +598,10 @@ class PysolMenubarActions:
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
self.mPlayerStats(mode=106)
|
self.mPlayerStats(mode=106)
|
||||||
|
|
||||||
|
def mFindCard(self, *args):
|
||||||
|
create_find_card_dialog(self.game.top, self.game,
|
||||||
|
self.app.getFindCardImagesDir())
|
||||||
|
|
||||||
def mEditGameComment(self, *args):
|
def mEditGameComment(self, *args):
|
||||||
if self._cancelDrag(break_pause=False): return
|
if self._cancelDrag(break_pause=False): return
|
||||||
game, gi = self.game, self.game.gameinfo
|
game, gi = self.game, self.game.gameinfo
|
||||||
|
|
|
@ -892,6 +892,9 @@ class Application:
|
||||||
return None
|
return None
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def getFindCardImagesDir(self):
|
||||||
|
return self._getImagesDir('cards')
|
||||||
|
|
||||||
def getToolbarImagesDir(self):
|
def getToolbarImagesDir(self):
|
||||||
if self.opt.toolbar_size:
|
if self.opt.toolbar_size:
|
||||||
size = 'large'
|
size = 'large'
|
||||||
|
|
|
@ -142,6 +142,7 @@ class Game:
|
||||||
#
|
#
|
||||||
data = [], # raw data
|
data = [], # raw data
|
||||||
)
|
)
|
||||||
|
self.event_handled = False # if click event handled by Stack (???)
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
# main constructor
|
# main constructor
|
||||||
|
@ -214,9 +215,13 @@ class Game:
|
||||||
|
|
||||||
def initBindings(self):
|
def initBindings(self):
|
||||||
# note: a Game is only allowed to bind self.canvas and not to self.top
|
# note: a Game is only allowed to bind self.canvas and not to self.top
|
||||||
bind(self.canvas, "<1>", self.clickHandler)
|
##bind(self.canvas, "<1>", self.clickHandler)
|
||||||
bind(self.canvas, "<2>", self.clickHandler)
|
bind(self.canvas, "<2>", self.clickHandler)
|
||||||
bind(self.canvas, "<3>", self.clickHandler)
|
##bind(self.canvas, "<3>", self.clickHandler)
|
||||||
|
##bind(self.canvas, "<Double-1>", self.undoHandler)
|
||||||
|
##bind(self.canvas, "<Double-1>", self.undoHandler)
|
||||||
|
bind(self.canvas, "<1>", self.undoHandler)
|
||||||
|
bind(self.canvas, "<3>", self.redoHandler)
|
||||||
bind(self.top, '<Unmap>', self._unmapHandler)
|
bind(self.top, '<Unmap>', self._unmapHandler)
|
||||||
|
|
||||||
def __createCommon(self, app):
|
def __createCommon(self, app):
|
||||||
|
@ -721,12 +726,29 @@ class Game:
|
||||||
#
|
#
|
||||||
# UI & graphics support
|
# UI & graphics support
|
||||||
#
|
#
|
||||||
|
def _defaultHandler(self):
|
||||||
def clickHandler(self, *args):
|
|
||||||
self.interruptSleep()
|
self.interruptSleep()
|
||||||
self.deleteStackDesc()
|
self.deleteStackDesc()
|
||||||
if self.demo:
|
if self.demo:
|
||||||
self.stopDemo()
|
self.stopDemo()
|
||||||
|
|
||||||
|
def clickHandler(self, event):
|
||||||
|
self._defaultHandler()
|
||||||
|
self.event_handled = False
|
||||||
|
return EVENT_PROPAGATE
|
||||||
|
|
||||||
|
def undoHandler(self, event):
|
||||||
|
self._defaultHandler()
|
||||||
|
if not self.event_handled:
|
||||||
|
self.app.menubar.mUndo()
|
||||||
|
self.event_handled = False
|
||||||
|
return EVENT_PROPAGATE
|
||||||
|
|
||||||
|
def redoHandler(self, event):
|
||||||
|
self._defaultHandler()
|
||||||
|
if not self.event_handled:
|
||||||
|
self.app.menubar.mRedo()
|
||||||
|
self.event_handled = False
|
||||||
return EVENT_PROPAGATE
|
return EVENT_PROPAGATE
|
||||||
|
|
||||||
def updateStatus(self, **kw):
|
def updateStatus(self, **kw):
|
||||||
|
@ -1392,6 +1414,16 @@ for %d moves.
|
||||||
return self.dealCards(sound=sound)
|
return self.dealCards(sound=sound)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
## for find_card_dialog
|
||||||
|
def highlightCard(self, suit, rank):
|
||||||
|
col = self.app.opt.highlight_samerank_colors[3]
|
||||||
|
info = []
|
||||||
|
for s in self.allstacks:
|
||||||
|
for c in s.cards:
|
||||||
|
if c.suit == suit and c.rank == rank:
|
||||||
|
if s.basicShallHighlightSameRank(c):
|
||||||
|
info.append((s, c, c, col))
|
||||||
|
return self._highlightCards(info, 0)
|
||||||
|
|
||||||
### highlight all moveable piles
|
### highlight all moveable piles
|
||||||
def getHighlightPilesStacks(self):
|
def getHighlightPilesStacks(self):
|
||||||
|
@ -1429,12 +1461,15 @@ for %d moves.
|
||||||
if not items:
|
if not items:
|
||||||
return 0
|
return 0
|
||||||
self.canvas.update_idletasks()
|
self.canvas.update_idletasks()
|
||||||
self.sleep(sleep)
|
if sleep:
|
||||||
items.reverse()
|
self.sleep(sleep)
|
||||||
for r in items:
|
items.reverse()
|
||||||
r.delete()
|
for r in items:
|
||||||
self.canvas.update_idletasks()
|
r.delete()
|
||||||
return EVENT_HANDLED
|
self.canvas.update_idletasks()
|
||||||
|
return EVENT_HANDLED
|
||||||
|
else:
|
||||||
|
return items
|
||||||
|
|
||||||
def highlightNotMatching(self):
|
def highlightNotMatching(self):
|
||||||
if self.demo:
|
if self.demo:
|
||||||
|
|
|
@ -108,12 +108,17 @@ class DoubleKlondikeByThrees(DoubleKlondike):
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Gargantua (Double Klondike with one redeal)
|
# // Gargantua (Double Klondike with one redeal)
|
||||||
|
# // Pantagruel
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class Gargantua(DoubleKlondike):
|
class Gargantua(DoubleKlondike):
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
DoubleKlondike.createGame(self, max_rounds=2)
|
DoubleKlondike.createGame(self, max_rounds=2)
|
||||||
|
|
||||||
|
class Pantagruel(DoubleKlondike):
|
||||||
|
RowStack_Class = AC_RowStack
|
||||||
|
def createGame(self):
|
||||||
|
DoubleKlondike.createGame(self, max_rounds=1)
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Harp (Double Klondike with 10 non-king rows and no redeal)
|
# // Harp (Double Klondike with 10 non-king rows and no redeal)
|
||||||
|
@ -311,5 +316,7 @@ registerGame(GameInfo(562, Delivery, "Delivery",
|
||||||
registerGame(GameInfo(590, ChineseKlondike, "Chinese Klondike",
|
registerGame(GameInfo(590, ChineseKlondike, "Chinese Klondike",
|
||||||
GI.GT_KLONDIKE, 3, -1, GI.SL_BALANCED,
|
GI.GT_KLONDIKE, 3, -1, GI.SL_BALANCED,
|
||||||
suits=(0, 1, 2) ))
|
suits=(0, 1, 2) ))
|
||||||
|
registerGame(GameInfo(591, Pantagruel, "Pantagruel",
|
||||||
|
GI.GT_KLONDIKE, 2, 0, GI.SL_BALANCED))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,9 @@ class Mahjongg_Foundation(OpenStack):
|
||||||
fnds[n].group.tkraise()
|
fnds[n].group.tkraise()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def getHelp(self):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# //
|
||||||
|
@ -211,6 +214,7 @@ class Mahjongg_RowStack(OpenStack):
|
||||||
bind(group, "<Control-1>", self.__controlclickEventHandler)
|
bind(group, "<Control-1>", self.__controlclickEventHandler)
|
||||||
|
|
||||||
def __defaultClickEventHandler(self, event, handler):
|
def __defaultClickEventHandler(self, event, handler):
|
||||||
|
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:
|
||||||
|
@ -527,7 +531,7 @@ class AbstractMahjonggGame(Game):
|
||||||
#
|
#
|
||||||
i = factorial(len(free_stacks))/2/factorial(len(free_stacks)-2)
|
i = factorial(len(free_stacks))/2/factorial(len(free_stacks)-2)
|
||||||
old_pairs = []
|
old_pairs = []
|
||||||
for _ in xrange(i):
|
for j in xrange(i):
|
||||||
nc = new_cards[:]
|
nc = new_cards[:]
|
||||||
while True:
|
while True:
|
||||||
# create uniq pair
|
# create uniq pair
|
||||||
|
|
|
@ -394,6 +394,7 @@ class MountOlympus_RowStack(SS_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class MountOlympus(Game):
|
class MountOlympus(Game):
|
||||||
|
RowStack_Class = MountOlympus_RowStack
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
|
@ -415,7 +416,7 @@ class MountOlympus(Game):
|
||||||
x += l.XS
|
x += l.XS
|
||||||
x, y = l.XM, l.YM+2*l.YS
|
x, y = l.XM, l.YM+2*l.YS
|
||||||
for i in range(9):
|
for i in range(9):
|
||||||
s.rows.append(MountOlympus_RowStack(x, y, self, dir=-2))
|
s.rows.append(self.RowStack_Class(x, y, self, dir=-2))
|
||||||
x += l.XS
|
x += l.XS
|
||||||
s.talon=DealRowTalonStack(l.XM, l.YM, self)
|
s.talon=DealRowTalonStack(l.XM, l.YM, self)
|
||||||
l.createText(s.talon, 's')
|
l.createText(s.talon, 's')
|
||||||
|
@ -446,7 +447,16 @@ class MountOlympus(Game):
|
||||||
(card1.rank + 2 == card2.rank or card2.rank + 2 == card1.rank))
|
(card1.rank + 2 == card2.rank or card2.rank + 2 == card1.rank))
|
||||||
|
|
||||||
|
|
||||||
|
class Zeus_RowStack(MountOlympus_RowStack):
|
||||||
|
def acceptsCards(self, from_stack, cards):
|
||||||
|
if not MountOlympus_RowStack.acceptsCards(self, from_stack, cards):
|
||||||
|
return False
|
||||||
|
if not self.cards:
|
||||||
|
return cards[0].rank in (QUEEN, KING)
|
||||||
|
return True
|
||||||
|
|
||||||
class Zeus(MountOlympus):
|
class Zeus(MountOlympus):
|
||||||
|
RowStack_Class = Zeus_RowStack
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.s.talon.dealRow(rows=self.s.foundations, frames=0)
|
self.s.talon.dealRow(rows=self.s.foundations, frames=0)
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
|
|
|
@ -183,7 +183,7 @@ class Pyramid(Game):
|
||||||
w = l.XM + max_rows*l.XS
|
w = l.XM + max_rows*l.XS
|
||||||
h = l.YM + 4*l.YS
|
h = l.YM + 4*l.YS
|
||||||
if reserves:
|
if reserves:
|
||||||
h += l.YS+4*l.YOFFSET
|
h += l.YS+2*l.YOFFSET
|
||||||
self.setSize(w, h)
|
self.setSize(w, h)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
|
@ -331,6 +331,53 @@ class Thirteen(Pyramid):
|
||||||
self.s.talon.dealCards() # deal first card to WasteStack
|
self.s.talon.dealCards() # deal first card to WasteStack
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# // Thirteens
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class Thirteens(Pyramid):
|
||||||
|
|
||||||
|
|
||||||
|
def createGame(self):
|
||||||
|
# create layout
|
||||||
|
l, s = Layout(self), self.s
|
||||||
|
|
||||||
|
# set window
|
||||||
|
self.setSize(l.XM+5*l.XS, l.YM+4*l.YS)
|
||||||
|
|
||||||
|
# create stacks
|
||||||
|
x, y = l.XM, l.YM
|
||||||
|
for i in range(2):
|
||||||
|
x = l.XM
|
||||||
|
for j in range(5):
|
||||||
|
s.rows.append(Giza_Reserve(x, y, self, max_accept=1))
|
||||||
|
x += l.XS
|
||||||
|
y += l.YS
|
||||||
|
x, y = l.XM, self.height-l.YS
|
||||||
|
s.talon = TalonStack(x, y, self)
|
||||||
|
l.createText(s.talon, 'n')
|
||||||
|
x, y = self.width-l.XS, self.height-l.YS
|
||||||
|
s.foundations.append(Pyramid_Foundation(x, y, self,
|
||||||
|
suit=ANY_SUIT, dir=0, base_rank=ANY_RANK,
|
||||||
|
max_move=0, max_cards=52))
|
||||||
|
|
||||||
|
# define stack-groups
|
||||||
|
l.defaultStackGroups()
|
||||||
|
|
||||||
|
def startGame(self):
|
||||||
|
self.startDealSample()
|
||||||
|
self.s.talon.dealRow()
|
||||||
|
|
||||||
|
def fillStack(self, stack):
|
||||||
|
if stack in self.s.rows:
|
||||||
|
if not stack.cards and self.s.talon.cards:
|
||||||
|
old_state = self.enterState(self.S_FILL)
|
||||||
|
self.s.talon.flipMove()
|
||||||
|
self.s.talon.moveMove(1, stack)
|
||||||
|
self.leaveState(old_state)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# register the game
|
# register the game
|
||||||
registerGame(GameInfo(38, Pyramid, "Pyramid",
|
registerGame(GameInfo(38, Pyramid, "Pyramid",
|
||||||
GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK))
|
GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK))
|
||||||
|
@ -338,8 +385,10 @@ registerGame(GameInfo(193, RelaxedPyramid, "Relaxed Pyramid",
|
||||||
GI.GT_PAIRING_TYPE | GI.GT_RELAXED, 1, 2, GI.SL_MOSTLY_LUCK))
|
GI.GT_PAIRING_TYPE | GI.GT_RELAXED, 1, 2, GI.SL_MOSTLY_LUCK))
|
||||||
##registerGame(GameInfo(44, Thirteen, "Thirteen",
|
##registerGame(GameInfo(44, Thirteen, "Thirteen",
|
||||||
## GI.GT_PAIRING_TYPE, 1, 0))
|
## GI.GT_PAIRING_TYPE, 1, 0))
|
||||||
registerGame(GameInfo(591, Giza, "Giza",
|
registerGame(GameInfo(592, Giza, "Giza",
|
||||||
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED))
|
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED))
|
||||||
|
registerGame(GameInfo(593, Thirteens, "Thirteens",
|
||||||
|
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,7 @@ class IdleAces(Game):
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Lady of the Manor
|
# // Lady of the Manor
|
||||||
|
# // Archway
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class LadyOfTheManor_RowStack(BasicRowStack):
|
class LadyOfTheManor_RowStack(BasicRowStack):
|
||||||
|
|
|
@ -38,9 +38,12 @@
|
||||||
import sys, os, re, time, types
|
import sys, os, re, time, types
|
||||||
import random
|
import random
|
||||||
|
|
||||||
##----------------------------------------------------------------------
|
|
||||||
|
|
||||||
class PysolRandom(random.Random):
|
# /***********************************************************************
|
||||||
|
# // system based random (need python >= 2.3)
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class SysRandom(random.Random):
|
||||||
#MAX_SEED = 0L
|
#MAX_SEED = 0L
|
||||||
#MAX_SEED = 0xffffffffffffffffL # 64 bits
|
#MAX_SEED = 0xffffffffffffffffL # 64 bits
|
||||||
MAX_SEED = 100000000000000000000L # 20 digits
|
MAX_SEED = 100000000000000000000L # 20 digits
|
||||||
|
@ -91,7 +94,7 @@ class PysolRandom(random.Random):
|
||||||
# // We use a seed of type long in the range [0, MAX_SEED].
|
# // We use a seed of type long in the range [0, MAX_SEED].
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class PysolRandomMFX:
|
class MFXRandom:
|
||||||
MAX_SEED = 0L
|
MAX_SEED = 0L
|
||||||
|
|
||||||
ORIGIN_UNKNOWN = 0
|
ORIGIN_UNKNOWN = 0
|
||||||
|
@ -188,12 +191,36 @@ class PysolRandomMFX:
|
||||||
seq[n], seq[j] = seq[j], seq[n]
|
seq[n], seq[j] = seq[j], seq[n]
|
||||||
n = n - 1
|
n = n - 1
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# // Linear Congruential random generator
|
||||||
|
# //
|
||||||
|
# // Knuth, Donald.E., "The Art of Computer Programming,", Vol 2,
|
||||||
|
# // Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
|
||||||
|
# // p. 106 (line 26) & p. 108
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class LCRandom64(MFXRandom):
|
||||||
|
MAX_SEED = 0xffffffffffffffffL # 64 bits
|
||||||
|
|
||||||
|
def str(self, seed):
|
||||||
|
s = repr(long(seed))
|
||||||
|
if s[-1:] == "L":
|
||||||
|
s = s[:-1]
|
||||||
|
s = "0"*(20-len(s)) + s
|
||||||
|
return s
|
||||||
|
|
||||||
|
def random(self):
|
||||||
|
self.seed = (self.seed*6364136223846793005L + 1L) & self.MAX_SEED
|
||||||
|
return ((self.seed >> 21) & 0x7fffffffL) / 2147483648.0
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // Linear Congruential random generator
|
# // Linear Congruential random generator
|
||||||
# // In PySol this is only used for 0 <= seed <= 32000.
|
# // In PySol this is only used for 0 <= seed <= 32000.
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
class LCRandom31(PysolRandomMFX):
|
class LCRandom31(MFXRandom):
|
||||||
MAX_SEED = 0x7fffffffL # 31 bits
|
MAX_SEED = 0x7fffffffL # 31 bits
|
||||||
|
|
||||||
def str(self, seed):
|
def str(self, seed):
|
||||||
|
@ -207,6 +234,9 @@ class LCRandom31(PysolRandomMFX):
|
||||||
self.seed = (self.seed*214013L + 2531011L) & self.MAX_SEED
|
self.seed = (self.seed*214013L + 2531011L) & self.MAX_SEED
|
||||||
return a + (int(self.seed >> 16) % (b+1-a))
|
return a + (int(self.seed >> 16) % (b+1-a))
|
||||||
|
|
||||||
|
# select
|
||||||
|
##PysolRandom = LCRandom64
|
||||||
|
PysolRandom = SysRandom
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // PySol support code
|
# // PySol support code
|
||||||
|
|
|
@ -895,6 +895,7 @@ class Stack:
|
||||||
#
|
#
|
||||||
|
|
||||||
def __defaultClickEventHandler(self, event, handler, start_drag=0, cancel_drag=1):
|
def __defaultClickEventHandler(self, event, handler, start_drag=0, cancel_drag=1):
|
||||||
|
self.game.event_handled = True # for Game.clickHandler
|
||||||
if self.game.demo:
|
if self.game.demo:
|
||||||
self.game.stopDemo(event)
|
self.game.stopDemo(event)
|
||||||
self.game.interruptSleep()
|
self.game.interruptSleep()
|
||||||
|
|
|
@ -315,6 +315,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
menu = MfxMenu(self.__menubar, label=n_("&Assist"))
|
menu = MfxMenu(self.__menubar, label=n_("&Assist"))
|
||||||
menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H")
|
menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H")
|
||||||
menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I")
|
menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I")
|
||||||
|
menu.add_command(label=n_("Find card"), command=self.mFindCard, accelerator="F")
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D")
|
menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D")
|
||||||
menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo)
|
menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo)
|
||||||
|
@ -417,6 +418,7 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
##self._bindKey("", "Shift_L", self.mHighlightPiles)
|
##self._bindKey("", "Shift_L", self.mHighlightPiles)
|
||||||
##self._bindKey("", "Shift_R", self.mHighlightPiles)
|
##self._bindKey("", "Shift_R", self.mHighlightPiles)
|
||||||
self._bindKey("", "i", self.mHighlightPiles)
|
self._bindKey("", "i", self.mHighlightPiles)
|
||||||
|
self._bindKey("", "f", self.mFindCard)
|
||||||
self._bindKey(ctrl, "d", self.mDemo)
|
self._bindKey(ctrl, "d", self.mDemo)
|
||||||
self._bindKey(ctrl, "e", self.mSelectCardsetDialog)
|
self._bindKey(ctrl, "e", self.mSelectCardsetDialog)
|
||||||
self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented
|
self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented
|
||||||
|
|
|
@ -39,6 +39,9 @@ __all__ = ['MfxMessageDialog',
|
||||||
'MfxTooltip',
|
'MfxTooltip',
|
||||||
'MfxScrolledCanvas',
|
'MfxScrolledCanvas',
|
||||||
'StackDesc',
|
'StackDesc',
|
||||||
|
'create_find_card_dialog',
|
||||||
|
'connect_game_find_card_dialog',
|
||||||
|
'destroy_find_card_dialog',
|
||||||
]
|
]
|
||||||
|
|
||||||
# imports
|
# imports
|
||||||
|
@ -55,7 +58,7 @@ from tkconst import EVENT_HANDLED, EVENT_PROPAGATE
|
||||||
from tkutil import after, after_idle, after_cancel
|
from tkutil import after, after_idle, after_cancel
|
||||||
from tkutil import bind, unbind_destroy, makeImage
|
from tkutil import bind, unbind_destroy, makeImage
|
||||||
from tkutil import makeToplevel, setTransient
|
from tkutil import makeToplevel, setTransient
|
||||||
from tkcanvas import MfxCanvas
|
from tkcanvas import MfxCanvas, MfxCanvasGroup, MfxCanvasImage, MfxCanvasRectangle
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
|
@ -78,23 +81,24 @@ class MfxDialog: # ex. _ToplevelDialog
|
||||||
bind(self.top, "WM_DELETE_WINDOW", self.wmDeleteWindow)
|
bind(self.top, "WM_DELETE_WINDOW", self.wmDeleteWindow)
|
||||||
#
|
#
|
||||||
|
|
||||||
def mainloop(self, focus=None, timeout=0):
|
def mainloop(self, focus=None, timeout=0, transient=True):
|
||||||
bind(self.top, "<Escape>", self.mCancel)
|
bind(self.top, "<Escape>", self.mCancel)
|
||||||
bind(self.top, '<Alt-Key>', self.altKeyEvent) # for accelerators
|
bind(self.top, '<Alt-Key>', self.altKeyEvent) # for accelerators
|
||||||
if focus is not None:
|
if focus is not None:
|
||||||
focus.focus()
|
focus.focus()
|
||||||
setTransient(self.top, self.parent)
|
if transient:
|
||||||
try:
|
setTransient(self.top, self.parent)
|
||||||
self.top.grab_set()
|
try:
|
||||||
except Tkinter.TclError:
|
self.top.grab_set()
|
||||||
if traceback: traceback.print_exc()
|
except Tkinter.TclError:
|
||||||
pass
|
if traceback: traceback.print_exc()
|
||||||
if timeout > 0:
|
pass
|
||||||
self.timer = after(self.top, timeout, self.mTimeout)
|
if timeout > 0:
|
||||||
try: self.top.mainloop()
|
self.timer = after(self.top, timeout, self.mTimeout)
|
||||||
except SystemExit:
|
try: self.top.mainloop()
|
||||||
pass
|
except SystemExit:
|
||||||
self.destroy()
|
pass
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
after_cancel(self.timer)
|
after_cancel(self.timer)
|
||||||
|
@ -716,5 +720,203 @@ class StackDesc:
|
||||||
self.label.unbind('<ButtonPress>', b)
|
self.label.unbind('<ButtonPress>', b)
|
||||||
|
|
||||||
|
|
||||||
|
# /***********************************************************************
|
||||||
|
# //
|
||||||
|
# ************************************************************************/
|
||||||
|
|
||||||
|
class FindCardDialog(MfxDialog):
|
||||||
|
SUIT_IMAGES = {} # key: (suit, color)
|
||||||
|
RANK_IMAGES = {} # key: (rank, color)
|
||||||
|
|
||||||
|
def __init__(self, parent, game, dir, title='Find card', **kw):
|
||||||
|
kw = self.initKw(kw)
|
||||||
|
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
|
||||||
|
top_frame, bottom_frame = self.createFrames(kw)
|
||||||
|
self.createBitmaps(top_frame, kw)
|
||||||
|
self.images_dir = dir
|
||||||
|
#self.default_color = top_frame['bg']
|
||||||
|
#self.bg_colors = ('#f9e3d2', '#c9e3d2')
|
||||||
|
#self.highlight_color = 'white'
|
||||||
|
self.label_width, self.label_height = 36, 30
|
||||||
|
self.top_frame = top_frame
|
||||||
|
self.canvas = MfxCanvas(top_frame, bg='white')
|
||||||
|
self.canvas.pack(expand=True, fill='both')
|
||||||
|
#
|
||||||
|
self.button = kw.default
|
||||||
|
self.labels = []
|
||||||
|
self.tk_images = []
|
||||||
|
self.highlight_items = None
|
||||||
|
self.last_card = None
|
||||||
|
self.connectGame(game)
|
||||||
|
#
|
||||||
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
|
##self.mainloop(focus, kw.timeout, transient=False)
|
||||||
|
|
||||||
|
def initKw(self, kw):
|
||||||
|
kw = KwStruct(kw,
|
||||||
|
strings=(_("&Close"),), default=0,
|
||||||
|
resizable=0,
|
||||||
|
padx=4, pady=4,
|
||||||
|
separatorwidth=0,
|
||||||
|
)
|
||||||
|
return MfxDialog.initKw(self, kw)
|
||||||
|
|
||||||
|
def createCardLabel(self, suit, rank, x0, y0):
|
||||||
|
dx, dy = self.label_width, self.label_height
|
||||||
|
dir = self.images_dir
|
||||||
|
images = self.tk_images
|
||||||
|
canvas = self.canvas
|
||||||
|
group = MfxCanvasGroup(canvas)
|
||||||
|
s = 'cshd'[suit]
|
||||||
|
if suit >= 2: c = 'red'
|
||||||
|
else: c = 'black'
|
||||||
|
x1, y1 = x0+dx-2, y0+dy-2
|
||||||
|
rect = MfxCanvasRectangle(self.canvas, x0, y0, x1, y1,
|
||||||
|
width=2, fill='white', outline='white')
|
||||||
|
rect.addtag(group)
|
||||||
|
#
|
||||||
|
fn = os.path.join(dir, c+'-'+str(rank)+'.gif')
|
||||||
|
rim = FindCardDialog.RANK_IMAGES.get((rank, c))
|
||||||
|
if not rim:
|
||||||
|
rim = Tkinter.PhotoImage(file=fn)
|
||||||
|
FindCardDialog.RANK_IMAGES[(rank, c)] = rim
|
||||||
|
fn = os.path.join(dir, 'large-'+s+'.gif')
|
||||||
|
sim = FindCardDialog.SUIT_IMAGES.get((suit, c))
|
||||||
|
if not sim:
|
||||||
|
sim = Tkinter.PhotoImage(file=fn)
|
||||||
|
FindCardDialog.SUIT_IMAGES[(suit, c)] = sim
|
||||||
|
#
|
||||||
|
x0 = x0+(dx-rim.width()-sim.width())/2
|
||||||
|
x, y = x0, y0+(dy-rim.height())/2
|
||||||
|
im = MfxCanvasImage(canvas, x, y, image=rim, anchor='nw')
|
||||||
|
im.addtag(group)
|
||||||
|
x, y = x0+rim.width(), y0+(dy-sim.height())/2
|
||||||
|
im = MfxCanvasImage(canvas, x, y, image=sim, anchor='nw')
|
||||||
|
im.addtag(group)
|
||||||
|
bind(group, '<Enter>',
|
||||||
|
lambda e, suit=suit, rank=rank, rect=rect:
|
||||||
|
self.enterEvent(suit, rank, rect))
|
||||||
|
bind(group, '<Leave>',
|
||||||
|
lambda e, suit=suit, rank=rank, rect=rect:
|
||||||
|
self.leaveEvent(suit, rank, rect))
|
||||||
|
self.labels.append(group)
|
||||||
|
|
||||||
|
|
||||||
|
def connectGame(self, game):
|
||||||
|
self.game = game
|
||||||
|
suits = game.gameinfo.suits
|
||||||
|
ranks = game.gameinfo.ranks
|
||||||
|
dx, dy = self.label_width, self.label_height
|
||||||
|
i = 0
|
||||||
|
for suit in suits:
|
||||||
|
j = 0
|
||||||
|
for rank in ranks:
|
||||||
|
x, y = dx*j+2, dy*i+2
|
||||||
|
self.createCardLabel(suit=suit, rank=rank, x0=x, y0=y)
|
||||||
|
j += 1
|
||||||
|
i += 1
|
||||||
|
w, h = dx*j, dy*i
|
||||||
|
self.canvas.config(width=w, height=h)
|
||||||
|
|
||||||
|
|
||||||
|
## if self.labels:
|
||||||
|
## for l in self.labels:
|
||||||
|
## unbind_destroy(l)
|
||||||
|
## l.grid_forget()
|
||||||
|
## frame = self.top_frame
|
||||||
|
## from pysollib.util import SUITS, RANKS
|
||||||
|
## suits = game.gameinfo.suits
|
||||||
|
## ranks = game.gameinfo.ranks
|
||||||
|
## ns = 0
|
||||||
|
## for i in suits:
|
||||||
|
## color = self.bg_colors[ns%2]
|
||||||
|
## suit = SUITS[i]
|
||||||
|
## suit_label = Tkinter.Label(frame, text=suit, bg=color)
|
||||||
|
## suit_label.grid(row=i, column=0, sticky='ew')
|
||||||
|
## self.labels.append(suit_label)
|
||||||
|
## ns += 1
|
||||||
|
## nk = 0
|
||||||
|
## for j in ranks:
|
||||||
|
## color = self.bg_colors[(ns+nk)%2]
|
||||||
|
## rank = RANKS[j]
|
||||||
|
## rank_label = Tkinter.Label(frame, text=rank, bg=color)
|
||||||
|
## bind(rank_label, '<Enter>', lambda e, label=rank_label, suit=i, rank=j: self.enterEvent(label, suit, rank))
|
||||||
|
## bind(rank_label, '<Leave>', lambda e, label=rank_label, suit=i, rank=j: self.leaveEvent(label, suit, rank))
|
||||||
|
## self.labels.append(rank_label)
|
||||||
|
## #rank_label.config(highlightthickness=1,
|
||||||
|
## # highlightbackground='black')
|
||||||
|
## rank_label.grid(row=i, column=j+1, sticky='ew')
|
||||||
|
## nk += 1
|
||||||
|
|
||||||
|
## def showCard(self, suit, rank, rect):
|
||||||
|
## print suit, rank
|
||||||
|
|
||||||
|
def enterEvent(self, suit, rank, rect):
|
||||||
|
#print 'enterEvent', suit, rank
|
||||||
|
#if (suit, rank) == self.last_card: return
|
||||||
|
self.last_card = (suit, rank)
|
||||||
|
self.highlight_items = self.game.highlightCard(suit, rank)
|
||||||
|
if not self.highlight_items:
|
||||||
|
self.highlight_items = []
|
||||||
|
## dx, dy = self.label_width, self.label_height
|
||||||
|
## x0, y0 = dx*rank, dy*suit
|
||||||
|
## x1, y1 = dx*(rank+1), dy*(suit+1)
|
||||||
|
rect.config(outline='red')
|
||||||
|
#item = MfxCanvasRectangle(self.canvas, x0, y0, x1, y1,
|
||||||
|
# width=2, fill=None, outline='red')
|
||||||
|
#self.highlight_items.append(item)
|
||||||
|
|
||||||
|
def leaveEvent(self, suit, rank, rect):
|
||||||
|
#print 'leaveEvent', suit, rank
|
||||||
|
#if (suit, rank) == self.last_card: return
|
||||||
|
for i in self.highlight_items:
|
||||||
|
i.delete()
|
||||||
|
#self.game.canvas.update_idletasks()
|
||||||
|
#self.canvas.update_idletasks()
|
||||||
|
rect.config(outline='white')
|
||||||
|
self.last_card = None
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
for l in self.labels:
|
||||||
|
unbind_destroy(l)
|
||||||
|
unbind_destroy(self.top)
|
||||||
|
self.top.wm_withdraw()
|
||||||
|
self.top.destroy()
|
||||||
|
|
||||||
|
def tkraise(self):
|
||||||
|
self.top.tkraise()
|
||||||
|
|
||||||
|
def mDone(self, button):
|
||||||
|
self.destroy()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def wmDeleteWindow(self, *event):
|
||||||
|
self.destroy()
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
find_card_dialog = None
|
||||||
|
|
||||||
|
def create_find_card_dialog(parent, game, dir):
|
||||||
|
global find_card_dialog
|
||||||
|
try:
|
||||||
|
find_card_dialog.tkraise()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
find_card_dialog = FindCardDialog(parent, game, dir)
|
||||||
|
|
||||||
|
def connect_game_find_card_dialog(game):
|
||||||
|
try:
|
||||||
|
find_card_dialog.connectGame(game)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def destroy_find_card_dialog():
|
||||||
|
global find_card_dialog
|
||||||
|
try:
|
||||||
|
find_card_dialog.destroy()
|
||||||
|
except:
|
||||||
|
##traceback.print_exc()
|
||||||
|
pass
|
||||||
|
find_card_dialog = None
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue