mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
* improved solitaire wizard
git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@162 efabe8c0-fbe8-4139-b769-b5e6d273206e
This commit is contained in:
parent
ccc11cb64d
commit
2022dbe599
8 changed files with 361 additions and 81 deletions
|
@ -30,26 +30,32 @@ from hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint
|
||||||
from wizardutil import WizardWidgets
|
from wizardutil import WizardWidgets
|
||||||
|
|
||||||
|
|
||||||
|
gettext = _
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# //
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
|
def get_settings(ss):
|
||||||
|
s = {}
|
||||||
|
for w in WizardWidgets:
|
||||||
|
if isinstance(w, basestring):
|
||||||
|
continue
|
||||||
|
if w.var_name in ss:
|
||||||
|
v = ss[w.var_name]
|
||||||
|
else:
|
||||||
|
v = w.default
|
||||||
|
if w.widget == 'menu':
|
||||||
|
v = dict(w.values_map)[v]
|
||||||
|
s[w.var_name] = v
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
class CustomGame(Game):
|
class CustomGame(Game):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
|
||||||
ss = self.SETTINGS
|
s = get_settings(self.SETTINGS)
|
||||||
s = {}
|
|
||||||
for w in WizardWidgets:
|
|
||||||
if isinstance(w, basestring):
|
|
||||||
continue
|
|
||||||
if w.var_name in ss:
|
|
||||||
v = ss[w.var_name]
|
|
||||||
else:
|
|
||||||
v = w.default
|
|
||||||
if w.widget == 'menu':
|
|
||||||
v = dict(w.values_map)[v]
|
|
||||||
s[w.var_name] = v
|
|
||||||
##from pprint import pprint; pprint(s)
|
##from pprint import pprint; pprint(s)
|
||||||
|
|
||||||
# foundations
|
# foundations
|
||||||
|
@ -119,17 +125,25 @@ class CustomGame(Game):
|
||||||
}
|
}
|
||||||
if s['talon'] is InitialDealTalonStack:
|
if s['talon'] is InitialDealTalonStack:
|
||||||
layout_kw['texts'] = False
|
layout_kw['texts'] = False
|
||||||
layout_kw['playcards'] = max(16, 12+s['deal_face_down']+s['deal_face_up'])
|
layout_kw['playcards'] = max(
|
||||||
|
16, 12+s['deal_face_down']+s['deal_face_up'])
|
||||||
|
if s['talon'] in (DealRowRedealTalonStack,
|
||||||
|
SpiderTalonStack,
|
||||||
|
GroundForADivorceTalonStack):
|
||||||
|
layout_kw['playcards'] += 2 * s['decks']
|
||||||
|
|
||||||
# reserves
|
# reserves
|
||||||
if s['reserves_num']:
|
if s['reserves_num']:
|
||||||
kw = {
|
kw = {
|
||||||
'max_accept': s['reserves_max_accept'],
|
'max_cards': s['reserves_max_accept'],
|
||||||
}
|
}
|
||||||
if s['reserves_max_accept']:
|
if s['reserves_max_accept']:
|
||||||
layout_kw['reserve_class'] = StackWrapper(ReserveStack, **kw)
|
layout_kw['reserve_class'] = StackWrapper(ReserveStack, **kw)
|
||||||
else:
|
else:
|
||||||
layout_kw['reserve_class'] = StackWrapper(OpenStack, **kw)
|
layout_kw['reserve_class'] = StackWrapper(OpenStack, **kw)
|
||||||
|
if s['talon'] is DealReserveRedealTalonStack or \
|
||||||
|
s['reserves_max_accept'] > 1:
|
||||||
|
layout_kw['reserve_texts'] = True
|
||||||
|
|
||||||
# waste
|
# waste
|
||||||
if s['talon'] is WasteTalonStack:
|
if s['talon'] is WasteTalonStack:
|
||||||
|
@ -153,19 +167,22 @@ class CustomGame(Game):
|
||||||
((Spider_AC_RowStack, Spider_SS_RowStack),
|
((Spider_AC_RowStack, Spider_SS_RowStack),
|
||||||
(self._shallHighlightMatch_RK,
|
(self._shallHighlightMatch_RK,
|
||||||
self._shallHighlightMatch_RKW)),
|
self._shallHighlightMatch_RKW)),
|
||||||
((AC_RowStack, UD_AC_RowStack, Yukon_AC_RowStack),
|
((AC_RowStack, UD_AC_RowStack,
|
||||||
|
Yukon_AC_RowStack, SuperMoveAC_RowStack),
|
||||||
(self._shallHighlightMatch_AC,
|
(self._shallHighlightMatch_AC,
|
||||||
self._shallHighlightMatch_ACW)),
|
self._shallHighlightMatch_ACW)),
|
||||||
((SS_RowStack, UD_SS_RowStack, Yukon_SS_RowStack),
|
((SS_RowStack, UD_SS_RowStack,
|
||||||
|
Yukon_SS_RowStack, SuperMoveSS_RowStack),
|
||||||
(self._shallHighlightMatch_SS,
|
(self._shallHighlightMatch_SS,
|
||||||
self._shallHighlightMatch_SSW)),
|
self._shallHighlightMatch_SSW)),
|
||||||
((RK_RowStack, UD_RK_RowStack, Yukon_RK_RowStack),
|
((RK_RowStack, UD_RK_RowStack,
|
||||||
|
Yukon_RK_RowStack, SuperMoveRK_RowStack),
|
||||||
(self._shallHighlightMatch_RK,
|
(self._shallHighlightMatch_RK,
|
||||||
self._shallHighlightMatch_RKW)),
|
self._shallHighlightMatch_RKW)),
|
||||||
((SC_RowStack, UD_SC_RowStack),
|
((SC_RowStack, UD_SC_RowStack, SuperMoveSC_RowStack),
|
||||||
(self._shallHighlightMatch_SC,
|
(self._shallHighlightMatch_SC,
|
||||||
self._shallHighlightMatch_SCW)),
|
self._shallHighlightMatch_SCW)),
|
||||||
((BO_RowStack,),
|
((BO_RowStack, SuperMoveBO_RowStack),
|
||||||
(self._shallHighlightMatch_BO,
|
(self._shallHighlightMatch_BO,
|
||||||
self._shallHighlightMatch_BOW)),
|
self._shallHighlightMatch_BOW)),
|
||||||
):
|
):
|
||||||
|
@ -214,7 +231,7 @@ class CustomGame(Game):
|
||||||
frames=frames)
|
frames=frames)
|
||||||
|
|
||||||
frames = 0
|
frames = 0
|
||||||
s = self.SETTINGS
|
s = get_settings(self.SETTINGS)
|
||||||
max_cards = s['deal_max_cards'] - len(self.s.rows)
|
max_cards = s['deal_max_cards'] - len(self.s.rows)
|
||||||
if self.s.waste:
|
if self.s.waste:
|
||||||
max_cards -= 1
|
max_cards -= 1
|
||||||
|
@ -232,7 +249,7 @@ class CustomGame(Game):
|
||||||
# deal to rows
|
# deal to rows
|
||||||
face_down = s['deal_face_down']
|
face_down = s['deal_face_down']
|
||||||
max_rows = s['deal_face_down'] + s['deal_face_up']
|
max_rows = s['deal_face_down'] + s['deal_face_up']
|
||||||
if s['deal_type'] == 'Triangle':
|
if s['deal_type'] == 'triangle':
|
||||||
# triangle
|
# triangle
|
||||||
for i in range(1, len(self.s.rows)):
|
for i in range(1, len(self.s.rows)):
|
||||||
flip = (face_down <= 0)
|
flip = (face_down <= 0)
|
||||||
|
@ -269,25 +286,12 @@ class CustomGame(Game):
|
||||||
self.s.talon.dealCards()
|
self.s.talon.dealCards()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def registerCustomGame(gameclass):
|
def registerCustomGame(gameclass):
|
||||||
|
|
||||||
s = gameclass.SETTINGS
|
s = get_settings(gameclass.SETTINGS)
|
||||||
for w in WizardWidgets:
|
gameid = gameclass.SETTINGS['gameid']
|
||||||
if isinstance(w, basestring):
|
|
||||||
continue
|
|
||||||
if w.var_name == 'decks':
|
|
||||||
v = s['decks']
|
|
||||||
decks = dict(w.values_map)[v]
|
|
||||||
elif w.var_name == 'redeals':
|
|
||||||
v = s['redeals']
|
|
||||||
redeals = dict(w.values_map)[v]
|
|
||||||
elif w.var_name == 'skill_level':
|
|
||||||
v = s['skill_level']
|
|
||||||
skill_level = dict(w.values_map)[v]
|
|
||||||
gameid = s['gameid']
|
|
||||||
|
|
||||||
registerGame(GameInfo(gameid, gameclass, s['name'],
|
registerGame(GameInfo(gameid, gameclass, s['name'],
|
||||||
GI.GT_CUSTOM | GI.GT_ORIGINAL,
|
GI.GT_CUSTOM | GI.GT_ORIGINAL,
|
||||||
decks, redeals, skill_level))
|
s['decks'], s['redeals'], s['skill_level']))
|
||||||
|
|
||||||
|
|
|
@ -2064,15 +2064,22 @@ for %d moves.
|
||||||
#
|
#
|
||||||
|
|
||||||
def getQuickPlayScore(self, ncards, from_stack, to_stack):
|
def getQuickPlayScore(self, ncards, from_stack, to_stack):
|
||||||
|
if to_stack in self.s.reserves:
|
||||||
|
# if to_stack in reserves prefer empty stack
|
||||||
|
return 1000-len(to_stack.cards)
|
||||||
# prefer non-empty piles in to_stack
|
# prefer non-empty piles in to_stack
|
||||||
return (len(to_stack.cards) != 0)
|
return 1001 + int(len(to_stack.cards) != 0)
|
||||||
|
|
||||||
def _getSpiderQuickPlayScore(self, ncards, from_stack, to_stack):
|
def _getSpiderQuickPlayScore(self, ncards, from_stack, to_stack):
|
||||||
|
if to_stack in self.s.reserves:
|
||||||
|
# if to_stack in reserves prefer empty stack
|
||||||
|
return 1000-len(to_stack.cards)
|
||||||
# for spider-type stacks
|
# for spider-type stacks
|
||||||
if to_stack.cards:
|
if to_stack.cards:
|
||||||
# check suit
|
# check suit
|
||||||
return int(from_stack.cards[-ncards].suit == to_stack.cards[-1].suit)+1
|
same_suit = from_stack.cards[-ncards].suit == to_stack.cards[-1].suit
|
||||||
return 0
|
return int(same_suit)+1002
|
||||||
|
return 1001
|
||||||
|
|
||||||
#
|
#
|
||||||
# Score (I really don't like scores in Patience games...)
|
# Score (I really don't like scores in Patience games...)
|
||||||
|
|
|
@ -192,6 +192,14 @@ class Layout:
|
||||||
s.reserves.append(reserve_class(r.x, r.y, game))
|
s.reserves.append(reserve_class(r.x, r.y, game))
|
||||||
# default
|
# default
|
||||||
self.defaultAll()
|
self.defaultAll()
|
||||||
|
# reserves texts
|
||||||
|
if self.s.reserves and ('reserve_texts' in kw) and kw['reserve_texts']:
|
||||||
|
game = self.game
|
||||||
|
for i in range(len(game.s.reserves)):
|
||||||
|
s1 = game.s.reserves[i]
|
||||||
|
s2 = self.s.reserves[i]
|
||||||
|
s1.texts.ncards = self.defaultText(s2)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# public util for use by class Game
|
# public util for use by class Game
|
||||||
|
@ -333,7 +341,8 @@ class Layout:
|
||||||
# - left bottom: talon, waste
|
# - left bottom: talon, waste
|
||||||
#
|
#
|
||||||
|
|
||||||
def freeCellLayout(self, rows, reserves, waste=0, texts=0, playcards=18):
|
def freeCellLayout(self, rows, reserves, waste=0,
|
||||||
|
texts=0, reserve_texts=False, playcards=18):
|
||||||
S = self.__createStack
|
S = self.__createStack
|
||||||
CW, CH = self.CW, self.CH
|
CW, CH = self.CW, self.CH
|
||||||
XM, YM = self.XM, self.YM
|
XM, YM = self.XM, self.YM
|
||||||
|
@ -351,12 +360,17 @@ class Layout:
|
||||||
# set size so that at least 2/3 of a card is visible with 18 cards
|
# set size so that at least 2/3 of a card is visible with 18 cards
|
||||||
h = CH*2/3 + (playcards-1)*self.YOFFSET
|
h = CH*2/3 + (playcards-1)*self.YOFFSET
|
||||||
h = YM + YS + max(h, 3*YS)
|
h = YM + YS + max(h, 3*YS)
|
||||||
|
if reserves and reserve_texts:
|
||||||
|
h += self.TEXT_HEIGHT
|
||||||
|
|
||||||
# create reserves & foundations
|
# create reserves & foundations
|
||||||
x, y = (w - (toprows*XS - XM))/2, YM
|
x, y = (w - (toprows*XS - XM))/2, YM
|
||||||
if reserves:
|
if reserves:
|
||||||
for i in range(reserves):
|
for i in range(reserves):
|
||||||
self.s.reserves.append(S(x, y))
|
s = S(x, y)
|
||||||
|
self.s.reserves.append(s)
|
||||||
|
if reserve_texts:
|
||||||
|
self._setText(s, anchor="s")
|
||||||
x += XS
|
x += XS
|
||||||
x += XS
|
x += XS
|
||||||
for suit in range(suits):
|
for suit in range(suits):
|
||||||
|
@ -366,6 +380,8 @@ class Layout:
|
||||||
|
|
||||||
# create rows
|
# create rows
|
||||||
x, y = (w - (rows*XS - XM))/2, YM + YS
|
x, y = (w - (rows*XS - XM))/2, YM + YS
|
||||||
|
if reserves and reserve_texts:
|
||||||
|
y += self.TEXT_HEIGHT
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
self.s.rows.append(S(x, y))
|
self.s.rows.append(S(x, y))
|
||||||
x += XS
|
x += XS
|
||||||
|
@ -399,7 +415,8 @@ class Layout:
|
||||||
# - bottom: reserves
|
# - bottom: reserves
|
||||||
#
|
#
|
||||||
|
|
||||||
def gypsyLayout(self, rows, waste=0, reserves=0, texts=1, playcards=25):
|
def gypsyLayout(self, rows, waste=0, reserves=0,
|
||||||
|
texts=1, reserve_texts=False, playcards=25):
|
||||||
S = self.__createStack
|
S = self.__createStack
|
||||||
CW, CH = self.CW, self.CH
|
CW, CH = self.CW, self.CH
|
||||||
XM, YM = self.XM, self.YM
|
XM, YM = self.XM, self.YM
|
||||||
|
@ -415,6 +432,8 @@ class Layout:
|
||||||
# set size so that at least 2/3 of a card is visible with 25 cards
|
# set size so that at least 2/3 of a card is visible with 25 cards
|
||||||
h = CH*2/3 + (playcards-1)*self.YOFFSET
|
h = CH*2/3 + (playcards-1)*self.YOFFSET
|
||||||
h = YM + max(h, (suits+1)*YS)
|
h = YM + max(h, (suits+1)*YS)
|
||||||
|
if reserves and reserve_texts:
|
||||||
|
h += self.TEXT_HEIGHT
|
||||||
|
|
||||||
# create rows
|
# create rows
|
||||||
x, y = XM, YM
|
x, y = XM, YM
|
||||||
|
@ -451,7 +470,10 @@ class Layout:
|
||||||
# create reserves
|
# create reserves
|
||||||
x, y = XM, h-YS
|
x, y = XM, h-YS
|
||||||
for i in range(reserves):
|
for i in range(reserves):
|
||||||
self.s.reserves.append(S(x, y))
|
s = S(x, y)
|
||||||
|
self.s.reserves.append(s)
|
||||||
|
if reserve_texts:
|
||||||
|
self._setText(s, anchor="n")
|
||||||
x += XS
|
x += XS
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
|
@ -464,7 +486,8 @@ class Layout:
|
||||||
# - bottom: foundations, waste, talon
|
# - bottom: foundations, waste, talon
|
||||||
#
|
#
|
||||||
|
|
||||||
def harpLayout(self, rows, waste, reserves=0, texts=1, playcards=19):
|
def harpLayout(self, rows, waste, reserves=0,
|
||||||
|
texts=1, reserve_texts=False, playcards=19):
|
||||||
S = self.__createStack
|
S = self.__createStack
|
||||||
CW, CH = self.CW, self.CH
|
CW, CH = self.CW, self.CH
|
||||||
XM, YM = self.XM, self.YM
|
XM, YM = self.XM, self.YM
|
||||||
|
@ -483,14 +506,21 @@ class Layout:
|
||||||
if texts: h += self.TEXT_HEIGHT
|
if texts: h += self.TEXT_HEIGHT
|
||||||
if reserves:
|
if reserves:
|
||||||
h += YS
|
h += YS
|
||||||
|
if reserves and reserve_texts:
|
||||||
|
h += self.TEXT_HEIGHT
|
||||||
|
|
||||||
# top
|
# top
|
||||||
y = YM
|
y = YM
|
||||||
if reserves:
|
if reserves:
|
||||||
|
if reserve_texts:
|
||||||
|
y += self.TEXT_HEIGHT
|
||||||
x = (w - (reserves*XS - XM))/2
|
x = (w - (reserves*XS - XM))/2
|
||||||
for i in range(reserves):
|
for i in range(reserves):
|
||||||
self.s.reserves.append(S(x, y))
|
s = S(x, y)
|
||||||
|
self.s.reserves.append(s)
|
||||||
x += XS
|
x += XS
|
||||||
|
if reserve_texts:
|
||||||
|
self._setText(s, anchor="n")
|
||||||
y += YS
|
y += YS
|
||||||
x = (w - (rows*XS - XM))/2
|
x = (w - (rows*XS - XM))/2
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
|
@ -505,6 +535,8 @@ class Layout:
|
||||||
x += XS
|
x += XS
|
||||||
if reserves:
|
if reserves:
|
||||||
yy = YM + YS - CH/2
|
yy = YM + YS - CH/2
|
||||||
|
if reserve_texts:
|
||||||
|
yy += self.TEXT_HEIGHT
|
||||||
else:
|
else:
|
||||||
yy = -999
|
yy = -999
|
||||||
self.setRegion(self.s.rows, (-999, yy, 999999, y - YS / 2))
|
self.setRegion(self.s.rows, (-999, yy, 999999, y - YS / 2))
|
||||||
|
@ -532,7 +564,8 @@ class Layout:
|
||||||
#
|
#
|
||||||
|
|
||||||
def klondikeLayout(self, rows, waste, reserves=0,
|
def klondikeLayout(self, rows, waste, reserves=0,
|
||||||
texts=1, playcards=16, center=1, text_height=0):
|
texts=1, reserve_texts=False,
|
||||||
|
playcards=16, center=1, text_height=0):
|
||||||
S = self.__createStack
|
S = self.__createStack
|
||||||
CW, CH = self.CW, self.CH
|
CW, CH = self.CW, self.CH
|
||||||
XM, YM = self.XM, self.YM
|
XM, YM = self.XM, self.YM
|
||||||
|
@ -549,6 +582,8 @@ class Layout:
|
||||||
h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
|
h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
|
||||||
h = max(h, 2 * YS)
|
h = max(h, 2 * YS)
|
||||||
h += YM + YS * foundrows
|
h += YM + YS * foundrows
|
||||||
|
if reserves and reserve_texts:
|
||||||
|
h += self.TEXT_HEIGHT
|
||||||
|
|
||||||
# top
|
# top
|
||||||
##text_height = 0
|
##text_height = 0
|
||||||
|
@ -601,8 +636,11 @@ class Layout:
|
||||||
y = h
|
y = h
|
||||||
h += YS
|
h += YS
|
||||||
for i in range(reserves):
|
for i in range(reserves):
|
||||||
self.s.reserves.append(S(x, y))
|
s = S(x, y)
|
||||||
|
self.s.reserves.append(s)
|
||||||
x += XS
|
x += XS
|
||||||
|
if reserve_texts:
|
||||||
|
self._setText(s, anchor="n")
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
self.size = (XM + maxrows * XS, h)
|
self.size = (XM + maxrows * XS, h)
|
||||||
|
|
|
@ -52,6 +52,8 @@ __all__ = ['cardsFaceUp',
|
||||||
'RedealTalonStack',
|
'RedealTalonStack',
|
||||||
'DealRowRedealTalonStack',
|
'DealRowRedealTalonStack',
|
||||||
'DealReserveRedealTalonStack',
|
'DealReserveRedealTalonStack',
|
||||||
|
'SpiderTalonStack',
|
||||||
|
'GroundForADivorceTalonStack',
|
||||||
'OpenStack',
|
'OpenStack',
|
||||||
'AbstractFoundationStack',
|
'AbstractFoundationStack',
|
||||||
'SS_FoundationStack',
|
'SS_FoundationStack',
|
||||||
|
@ -1875,6 +1877,29 @@ class DealReserveRedealTalonStack(DealRowRedealTalonStack):
|
||||||
return DealRowRedealTalonStack.dealCards(self, sound=sound,
|
return DealRowRedealTalonStack.dealCards(self, sound=sound,
|
||||||
rows=self.game.s.reserves)
|
rows=self.game.s.reserves)
|
||||||
|
|
||||||
|
# Spider Talons
|
||||||
|
class SpiderTalonStack(DealRowRedealTalonStack):
|
||||||
|
def canDealCards(self):
|
||||||
|
if not DealRowRedealTalonStack.canDealCards(self):
|
||||||
|
return False
|
||||||
|
# no row may be empty
|
||||||
|
for r in self.game.s.rows:
|
||||||
|
if not r.cards:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
class GroundForADivorceTalonStack(DealRowRedealTalonStack):
|
||||||
|
# A single click deals a new cards to each non-empty row.
|
||||||
|
def dealCards(self, sound=1):
|
||||||
|
if self.cards:
|
||||||
|
rows = filter(lambda r: r.cards, self.game.s.rows)
|
||||||
|
## if not rows:
|
||||||
|
## # deal one card to first row if all rows are emtpy
|
||||||
|
## rows = self.game.s.rows[:1]
|
||||||
|
return DealRowRedealTalonStack.dealRowAvail(self, rows=rows,
|
||||||
|
sound=sound)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# // An OpenStack is a stack where cards can be placed and dragged
|
# // An OpenStack is a stack where cards can be placed and dragged
|
||||||
|
|
|
@ -28,12 +28,15 @@ from Tile import *
|
||||||
# PySol imports
|
# PySol imports
|
||||||
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct
|
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct
|
||||||
from pysollib.wizardutil import WizardWidgets
|
from pysollib.wizardutil import WizardWidgets
|
||||||
|
from pysollib.wizardpresets import presets
|
||||||
|
|
||||||
# Toolkit imports
|
# Toolkit imports
|
||||||
from tkwidget import MfxDialog
|
from tkwidget import MfxDialog
|
||||||
from tkwidget import PysolScale
|
from tkwidget import PysolScale
|
||||||
|
|
||||||
|
|
||||||
|
gettext = _
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# //
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
@ -62,7 +65,21 @@ class WizardDialog(MfxDialog):
|
||||||
|
|
||||||
Label(frame, text=w.label).grid(row=row, column=0)
|
Label(frame, text=w.label).grid(row=row, column=0)
|
||||||
|
|
||||||
if w.widget == 'entry':
|
if w.widget == 'preset':
|
||||||
|
if w.variable is None:
|
||||||
|
w.variable = StringVar()
|
||||||
|
values = [gettext(v) for v in w.values]
|
||||||
|
default = gettext(w.default)
|
||||||
|
values.remove(default)
|
||||||
|
values.sort()
|
||||||
|
values.insert(0, default)
|
||||||
|
cb = Combobox(frame, values=tuple(values),
|
||||||
|
textvariable=w.variable,
|
||||||
|
state='readonly', width=32)
|
||||||
|
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
callback = lambda e, w=w: self.presetSelected(e, w)
|
||||||
|
cb.bind('<<ComboboxSelected>>', callback)
|
||||||
|
elif w.widget == 'entry':
|
||||||
if w.variable is None:
|
if w.variable is None:
|
||||||
w.variable = StringVar()
|
w.variable = StringVar()
|
||||||
en = Entry(frame, textvariable=w.variable)
|
en = Entry(frame, textvariable=w.variable)
|
||||||
|
@ -70,7 +87,8 @@ class WizardDialog(MfxDialog):
|
||||||
elif w.widget == 'menu':
|
elif w.widget == 'menu':
|
||||||
if w.variable is None:
|
if w.variable is None:
|
||||||
w.variable = StringVar()
|
w.variable = StringVar()
|
||||||
cb = Combobox(frame, values=tuple(w.values),
|
values = [gettext(v) for v in w.values]
|
||||||
|
cb = Combobox(frame, values=tuple(values),
|
||||||
textvariable=w.variable,
|
textvariable=w.variable,
|
||||||
state='readonly', width=32)
|
state='readonly', width=32)
|
||||||
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
@ -94,17 +112,32 @@ class WizardDialog(MfxDialog):
|
||||||
ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
|
||||||
if w.current_value is None:
|
if w.current_value is None:
|
||||||
w.variable.set(w.default)
|
w.variable.set(gettext(w.default))
|
||||||
else:
|
else:
|
||||||
w.variable.set(w.current_value)
|
w.variable.set(gettext(w.current_value))
|
||||||
|
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
|
||||||
focus = self.createButtons(bottom_frame, kw)
|
focus = self.createButtons(bottom_frame, kw)
|
||||||
self.mainloop(focus, kw.timeout)
|
self.mainloop(focus, kw.timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def presetSelected(self, e, w):
|
||||||
|
n = e.widget.get()
|
||||||
|
n = w.translation_map[n]
|
||||||
|
p = presets[n]
|
||||||
|
for w in WizardWidgets:
|
||||||
|
if isinstance(w, basestring):
|
||||||
|
continue
|
||||||
|
if w.var_name in p:
|
||||||
|
v = p[w.var_name]
|
||||||
|
else:
|
||||||
|
v = w.default
|
||||||
|
if w.widget in ('menu', 'preset'):
|
||||||
|
v = gettext(v)
|
||||||
|
w.variable.set(v)
|
||||||
|
|
||||||
|
|
||||||
def initKw(self, kw):
|
def initKw(self, kw):
|
||||||
kw = KwStruct(kw,
|
kw = KwStruct(kw,
|
||||||
strings=(_('&OK'), _('&Cancel')),
|
strings=(_('&OK'), _('&Cancel')),
|
||||||
|
|
|
@ -29,11 +29,14 @@ from tabpage import TabPageSet
|
||||||
# PySol imports
|
# PySol imports
|
||||||
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct
|
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct
|
||||||
from pysollib.wizardutil import WizardWidgets
|
from pysollib.wizardutil import WizardWidgets
|
||||||
|
from pysollib.wizardpresets import presets
|
||||||
|
|
||||||
# Toolkit imports
|
# Toolkit imports
|
||||||
from tkwidget import MfxDialog
|
from tkwidget import MfxDialog
|
||||||
|
|
||||||
|
|
||||||
|
gettext = _
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# //
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
@ -63,7 +66,19 @@ class WizardDialog(MfxDialog):
|
||||||
|
|
||||||
Label(frame, text=w.label).grid(row=row, column=0, padx=2)
|
Label(frame, text=w.label).grid(row=row, column=0, padx=2)
|
||||||
|
|
||||||
if w.widget == 'entry':
|
if w.widget == 'preset':
|
||||||
|
if w.variable is None:
|
||||||
|
w.variable = StringVar()
|
||||||
|
values = [gettext(v) for v in w.values]
|
||||||
|
default = gettext(w.default)
|
||||||
|
values.remove(default)
|
||||||
|
values.sort()
|
||||||
|
values.insert(0, default)
|
||||||
|
callback = lambda v, w=w: self.presetSelected(v, w)
|
||||||
|
om = OptionMenu(frame, w.variable,
|
||||||
|
command=callback, *values)
|
||||||
|
om.grid(row=row, column=1, sticky='ew', padx=2)
|
||||||
|
elif w.widget == 'entry':
|
||||||
if w.variable is None:
|
if w.variable is None:
|
||||||
w.variable = StringVar()
|
w.variable = StringVar()
|
||||||
en = Entry(frame, textvariable=w.variable)
|
en = Entry(frame, textvariable=w.variable)
|
||||||
|
@ -71,15 +86,15 @@ class WizardDialog(MfxDialog):
|
||||||
elif w.widget == 'menu':
|
elif w.widget == 'menu':
|
||||||
if w.variable is None:
|
if w.variable is None:
|
||||||
w.variable = StringVar()
|
w.variable = StringVar()
|
||||||
om = OptionMenu(frame, w.variable, *w.values)
|
values = [gettext(v) for v in w.values]
|
||||||
|
om = OptionMenu(frame, w.variable, *values)
|
||||||
om.grid(row=row, column=1, sticky='ew', padx=2)
|
om.grid(row=row, column=1, sticky='ew', padx=2)
|
||||||
elif w.widget == 'spin':
|
elif w.widget == 'spin':
|
||||||
if w.variable is None:
|
if w.variable is None:
|
||||||
w.variable = IntVar()
|
w.variable = IntVar()
|
||||||
from_, to = w.values
|
from_, to = w.values
|
||||||
s = Scale(frame, from_=from_, to=to, resolution=1,
|
s = Scale(frame, from_=from_, to=to, resolution=1,
|
||||||
orient='horizontal',
|
orient='horizontal', length=200, variable=w.variable)
|
||||||
variable=w.variable)
|
|
||||||
s.grid(row=row, column=1, sticky='ew', padx=2)
|
s.grid(row=row, column=1, sticky='ew', padx=2)
|
||||||
elif w.widget == 'check':
|
elif w.widget == 'check':
|
||||||
if w.variable is None:
|
if w.variable is None:
|
||||||
|
@ -89,9 +104,9 @@ class WizardDialog(MfxDialog):
|
||||||
ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
|
|
||||||
if w.current_value is None:
|
if w.current_value is None:
|
||||||
w.variable.set(w.default)
|
w.variable.set(gettext(w.default))
|
||||||
else:
|
else:
|
||||||
w.variable.set(w.current_value)
|
w.variable.set(gettext(w.current_value))
|
||||||
|
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
@ -101,6 +116,21 @@ class WizardDialog(MfxDialog):
|
||||||
self.mainloop(focus, kw.timeout)
|
self.mainloop(focus, kw.timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def presetSelected(self, v, w):
|
||||||
|
n = w.translation_map[v]
|
||||||
|
p = presets[n]
|
||||||
|
for w in WizardWidgets:
|
||||||
|
if isinstance(w, basestring):
|
||||||
|
continue
|
||||||
|
if w.var_name in p:
|
||||||
|
v = p[w.var_name]
|
||||||
|
else:
|
||||||
|
v = w.default
|
||||||
|
if w.widget in ('menu', 'preset'):
|
||||||
|
v = gettext(v)
|
||||||
|
w.variable.set(v)
|
||||||
|
|
||||||
|
|
||||||
def initKw(self, kw):
|
def initKw(self, kw):
|
||||||
kw = KwStruct(kw,
|
kw = KwStruct(kw,
|
||||||
strings=(_('&OK'), _('&Cancel')),
|
strings=(_('&OK'), _('&Cancel')),
|
||||||
|
|
128
pysollib/wizardpresets.py
Normal file
128
pysollib/wizardpresets.py
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
##
|
||||||
|
## PySol -- a Python Solitaire game
|
||||||
|
##
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with this program; see the file COPYING.
|
||||||
|
## If not, write to the Free Software Foundation, Inc.,
|
||||||
|
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
##
|
||||||
|
##---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
n_ = lambda x: x
|
||||||
|
|
||||||
|
presets = {
|
||||||
|
'None': {
|
||||||
|
'preset': 'None',
|
||||||
|
'name': n_('My Game'),
|
||||||
|
},
|
||||||
|
|
||||||
|
'Klondike': {
|
||||||
|
'preset': 'Klondike',
|
||||||
|
'name': n_('My Klondike'),
|
||||||
|
'layout': 'Klondike',
|
||||||
|
'talon': 'Deal to waste',
|
||||||
|
'redeals': 'Unlimited redeals',
|
||||||
|
'rows_num': 7,
|
||||||
|
'rows_base_card': 'King',
|
||||||
|
'reserves_num': 0,
|
||||||
|
'deal_type': 'Triangle',
|
||||||
|
'deal_face_down': 6,
|
||||||
|
'deal_face_up': 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
'FreeCell': {
|
||||||
|
'preset': 'FreeCell',
|
||||||
|
'name': n_('My FreeCell'),
|
||||||
|
'skill_level': 'Mostly skill',
|
||||||
|
'rows_max_move': 'Top card',
|
||||||
|
'rows_super_move': 1,
|
||||||
|
'deal_face_up': 6,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Spider': {
|
||||||
|
'preset': 'Spider',
|
||||||
|
'name': n_('My Spider'),
|
||||||
|
'skill_level': 'Mostly skill',
|
||||||
|
'decks': 'Two',
|
||||||
|
'layout': 'Klondike',
|
||||||
|
'talon': 'Spider',
|
||||||
|
'found_type': 'Spider same suit',
|
||||||
|
'found_max_move': 'None',
|
||||||
|
'rows_num': 10,
|
||||||
|
'rows_type': 'Spider same suit',
|
||||||
|
'reserves_num': 0,
|
||||||
|
'deal_face_down': 5,
|
||||||
|
'deal_face_up': 1,
|
||||||
|
'deal_max_cards': 54,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Gypsy': {
|
||||||
|
'preset': 'Gypsy',
|
||||||
|
'name': n_('My Gypsy'),
|
||||||
|
'skill_level': 'Mostly skill',
|
||||||
|
'decks': 'Two',
|
||||||
|
'layout': 'Gypsy',
|
||||||
|
'talon': 'Deal to tableau',
|
||||||
|
'found_max_move': 'None',
|
||||||
|
'reserves_num': 0,
|
||||||
|
'deal_face_down': 2,
|
||||||
|
'deal_face_up': 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Ground for a Divorce': {
|
||||||
|
'preset': 'Ground for a Divorce',
|
||||||
|
'name': n_('My Ground for a Divorce'),
|
||||||
|
'skill_level': 'Mostly skill',
|
||||||
|
'decks': 'Two',
|
||||||
|
'layout': 'Harp',
|
||||||
|
'talon': 'Ground for a Divorce',
|
||||||
|
'found_type': 'Spider same suit',
|
||||||
|
'found_base_card': 'Any',
|
||||||
|
'found_equal': 0,
|
||||||
|
'rows_num': 10,
|
||||||
|
'rows_type': 'Spider same suit',
|
||||||
|
'rows_wrap': 1,
|
||||||
|
'reserves_num': 0,
|
||||||
|
'deal_face_up': 5,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Double Klondike': {
|
||||||
|
'preset': 'Double Klondike',
|
||||||
|
'name': n_('My Double Klondike'),
|
||||||
|
'decks': 'Two',
|
||||||
|
'layout': 'Harp',
|
||||||
|
'talon': 'Deal to waste',
|
||||||
|
'redeals': 'Unlimited redeals',
|
||||||
|
'rows_num': 9,
|
||||||
|
'rows_base_card': 'King',
|
||||||
|
'reserves_num': 0,
|
||||||
|
'deal_type': 'Triangle',
|
||||||
|
'deal_face_down': 8,
|
||||||
|
'deal_face_up': 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Simple Simon': {
|
||||||
|
'preset': 'Simple Simon',
|
||||||
|
'name': n_('My Simple Simon'),
|
||||||
|
'skill_level': 'Mostly skill',
|
||||||
|
'found_type': 'Spider same suit',
|
||||||
|
'found_max_move': 'None',
|
||||||
|
'rows_num': 10,
|
||||||
|
'rows_type': 'Spider same suit',
|
||||||
|
'reserves_num': 0,
|
||||||
|
'deal_type': 'Triangle',
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -24,10 +24,8 @@ import sys, os
|
||||||
from gamedb import GI, loadGame
|
from gamedb import GI, loadGame
|
||||||
from util import *
|
from util import *
|
||||||
from stack import *
|
from stack import *
|
||||||
#from game import Game
|
|
||||||
from layout import Layout
|
from layout import Layout
|
||||||
#from hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
from wizardpresets import presets
|
||||||
#from pysoltk import MfxCanvasText
|
|
||||||
|
|
||||||
gettext = _
|
gettext = _
|
||||||
n_ = lambda x: x
|
n_ = lambda x: x
|
||||||
|
@ -40,15 +38,20 @@ class WizSetting:
|
||||||
def __init__(self, values_map, default, var_name,
|
def __init__(self, values_map, default, var_name,
|
||||||
label, widget='menu'):
|
label, widget='menu'):
|
||||||
self.values_map = values_map
|
self.values_map = values_map
|
||||||
self.default = gettext(default)
|
self.default = default
|
||||||
##self.values_dict = dict(self.values_map)
|
##self.values_dict = dict(self.values_map)
|
||||||
self.translation_map = {}
|
self.translation_map = {}
|
||||||
if widget == 'menu':
|
if widget == 'menu':
|
||||||
self.values = []
|
self.values = []
|
||||||
for k, v in self.values_map:
|
for k, v in self.values_map:
|
||||||
t = gettext(k)
|
self.values.append(k)
|
||||||
self.values.append(t)
|
self.translation_map[gettext(k)] = k
|
||||||
self.translation_map[t] = k
|
assert self.default in self.values
|
||||||
|
elif widget == 'preset':
|
||||||
|
self.values = []
|
||||||
|
for v in self.values_map:
|
||||||
|
self.values.append(v)
|
||||||
|
self.translation_map[gettext(v)] = v
|
||||||
assert self.default in self.values
|
assert self.default in self.values
|
||||||
else:
|
else:
|
||||||
self.values = self.values_map
|
self.values = self.values_map
|
||||||
|
@ -59,6 +62,13 @@ class WizSetting:
|
||||||
self.current_value = None
|
self.current_value = None
|
||||||
|
|
||||||
|
|
||||||
|
WizardPresets = WizSetting(
|
||||||
|
values_map = presets.keys(),
|
||||||
|
default = 'None',
|
||||||
|
widget = 'preset',
|
||||||
|
label = _('Initial setting:'),
|
||||||
|
var_name = 'preset',
|
||||||
|
)
|
||||||
GameName = WizSetting(
|
GameName = WizSetting(
|
||||||
values_map = (),
|
values_map = (),
|
||||||
default = 'My Game',
|
default = 'My Game',
|
||||||
|
@ -97,10 +107,12 @@ LayoutType = WizSetting(
|
||||||
var_name = 'layout',
|
var_name = 'layout',
|
||||||
)
|
)
|
||||||
TalonType = WizSetting(
|
TalonType = WizSetting(
|
||||||
values_map = ((n_('Initial dealing'), InitialDealTalonStack),
|
values_map = ((n_('Initial dealing'), InitialDealTalonStack),
|
||||||
(n_('Deal to waste'), WasteTalonStack),
|
(n_('Deal to waste'), WasteTalonStack),
|
||||||
(n_('Deal to tableau'), DealRowRedealTalonStack),
|
(n_('Deal to tableau'), DealRowRedealTalonStack),
|
||||||
(n_('Deal to reserves'), DealReserveRedealTalonStack),
|
(n_('Deal to reserves'), DealReserveRedealTalonStack),
|
||||||
|
(n_('Spider'), SpiderTalonStack),
|
||||||
|
(n_('Ground for a Divorce'), GroundForADivorceTalonStack),
|
||||||
),
|
),
|
||||||
default = n_('Initial dealing'),
|
default = n_('Initial dealing'),
|
||||||
label = _('Type:'),
|
label = _('Type:'),
|
||||||
|
@ -166,15 +178,15 @@ FoundWrap = WizSetting(
|
||||||
widget = 'check',
|
widget = 'check',
|
||||||
)
|
)
|
||||||
FoundMaxMove = WizSetting(
|
FoundMaxMove = WizSetting(
|
||||||
values_map = ((n_('None'), 0,), (n_('One card'), 1)),
|
values_map = ((n_('None'), 0,), (n_('Top card'), 1)),
|
||||||
default = n_('One card'),
|
default = n_('Top card'),
|
||||||
label = _('Max move cards:'),
|
label = _('Move:'),
|
||||||
var_name = 'found_max_move',
|
var_name = 'found_max_move',
|
||||||
)
|
)
|
||||||
FoundEqual = WizSetting(
|
FoundEqual = WizSetting(
|
||||||
values_map = (0, 1),
|
values_map = (0, 1),
|
||||||
default = 1,
|
default = 1,
|
||||||
label = _('First card sets first rank:'),
|
label = _('First card sets base rank:'),
|
||||||
var_name = 'found_equal',
|
var_name = 'found_equal',
|
||||||
widget = 'check',
|
widget = 'check',
|
||||||
)
|
)
|
||||||
|
@ -225,9 +237,9 @@ RowsDir = WizSetting(
|
||||||
var_name = 'rows_dir',
|
var_name = 'rows_dir',
|
||||||
)
|
)
|
||||||
RowsMaxMove = WizSetting(
|
RowsMaxMove = WizSetting(
|
||||||
values_map = ((n_('One card'), 1), (n_('Unlimited'), UNLIMITED_MOVES)),
|
values_map = ((n_('Top card'), 1), (n_('Sequence'), UNLIMITED_MOVES)),
|
||||||
default = n_('Unlimited'),
|
default = n_('Sequence'),
|
||||||
label = _('Max # of moved cards:'),
|
label = _('Move:'),
|
||||||
var_name = 'rows_max_move',
|
var_name = 'rows_max_move',
|
||||||
)
|
)
|
||||||
RowsWrap = WizSetting(
|
RowsWrap = WizSetting(
|
||||||
|
@ -284,7 +296,7 @@ DealToReseves = WizSetting(
|
||||||
values_map = (0, 20),
|
values_map = (0, 20),
|
||||||
default = 0,
|
default = 0,
|
||||||
widget = 'spin',
|
widget = 'spin',
|
||||||
label = _('# cards dealt to reserve:'),
|
label = _('# of cards dealt to reserve:'),
|
||||||
var_name = 'deal_to_reserves',
|
var_name = 'deal_to_reserves',
|
||||||
)
|
)
|
||||||
DealMaxCards = WizSetting(
|
DealMaxCards = WizSetting(
|
||||||
|
@ -297,6 +309,7 @@ DealMaxCards = WizSetting(
|
||||||
|
|
||||||
WizardWidgets = (
|
WizardWidgets = (
|
||||||
_('General'),
|
_('General'),
|
||||||
|
WizardPresets,
|
||||||
GameName,
|
GameName,
|
||||||
SkillLevel,
|
SkillLevel,
|
||||||
NumDecks,
|
NumDecks,
|
||||||
|
@ -374,12 +387,16 @@ class MyCustomGame(CustomGame):
|
||||||
if isinstance(w, basestring):
|
if isinstance(w, basestring):
|
||||||
continue
|
continue
|
||||||
v = w.variable.get()
|
v = w.variable.get()
|
||||||
if w.widget == 'menu':
|
if w.widget in ('menu', 'presets'):
|
||||||
v = w.translation_map[v]
|
v = w.translation_map[v]
|
||||||
|
if v == w.default:
|
||||||
|
# save only unique values
|
||||||
|
continue
|
||||||
if isinstance(v, int):
|
if isinstance(v, int):
|
||||||
fd.write(" '%s': %i,\n" % (w.var_name, v))
|
fd.write(" '%s': %i,\n" % (w.var_name, v))
|
||||||
else:
|
else:
|
||||||
if w.var_name == 'name':
|
if w.var_name == 'name':
|
||||||
|
# escape
|
||||||
v = v.replace('\\', '\\\\')
|
v = v.replace('\\', '\\\\')
|
||||||
v = v.replace("'", "\\'")
|
v = v.replace("'", "\\'")
|
||||||
if isinstance(v, unicode):
|
if isinstance(v, unicode):
|
||||||
|
@ -413,8 +430,6 @@ def reset_wizard(game):
|
||||||
v = game.SETTINGS[w.var_name]
|
v = game.SETTINGS[w.var_name]
|
||||||
else:
|
else:
|
||||||
v = w.default
|
v = w.default
|
||||||
if w.widget == 'menu':
|
|
||||||
v = gettext(v)
|
|
||||||
w.current_value = v
|
w.current_value = v
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue