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

* improved solitaire wizard

* removed round changes from turnStackMove


git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@160 39dd0a4e-7c14-0410-91b3-c4f2d318f732
This commit is contained in:
skomoroh 2007-05-06 21:42:40 +00:00
parent bc4d344348
commit 9fd4942f23
11 changed files with 164 additions and 112 deletions

View file

@ -24,7 +24,7 @@ from util import *
from stack import *
from game import Game
from layout import Layout
from hint import AbstractHint, DefaultHint, CautiousDefaultHint
from hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint
#from pysoltk import MfxCanvasText
from wizardutil import WizardWidgets
@ -58,10 +58,17 @@ class CustomGame(Game):
'base_rank': s['found_base_card'],
'mod': 13,
}
# max_move
if s['found_type'] not in (Spider_SS_Foundation,
Spider_AC_Foundation,):
kw['max_move'] = s['found_max_move']
else:
# suit
if s['found_type'] in (Spider_SS_Foundation,
Spider_AC_Foundation,):
kw['suit'] = ANY_SUIT
# fix dir and base_rank for Spider foundations
if s['found_type'] in (Spider_SS_Foundation,
Spider_AC_Foundation,):
kw['dir'] = -kw['dir']
if s['found_base_card'] == KING:
kw['base_rank'] = ACE
@ -101,7 +108,7 @@ class CustomGame(Game):
}
if s['talon'] is InitialDealTalonStack:
layout_kw['texts'] = False
layout_kw['playcards'] = 12+s['deal_to_rows']
layout_kw['playcards'] = max(16, 12+s['deal_face_down']+s['deal_face_up'])
# reserves
if s['reserves_num']:
@ -125,18 +132,23 @@ class CustomGame(Game):
**layout_kw
)
# shuffle
if s['talon_shuffle'] and s['talon'] in (WasteTalonStack,
DealRowRedealTalonStack):
self.s.talon.dealCards = self.s.talon.shuffleAndDealCards
# shallHighlightMatch
for c, f in (
((Spider_AC_RowStack, Spider_SS_RowStack),
(self._shallHighlightMatch_RK,
self._shallHighlightMatch_RKW)),
((AC_RowStack, UD_AC_RowStack),
((AC_RowStack, UD_AC_RowStack, Yukon_AC_RowStack),
(self._shallHighlightMatch_AC,
self._shallHighlightMatch_ACW)),
((SS_RowStack, UD_SS_RowStack),
((SS_RowStack, UD_SS_RowStack, Yukon_SS_RowStack),
(self._shallHighlightMatch_SS,
self._shallHighlightMatch_SSW)),
((RK_RowStack, UD_RK_RowStack),
((RK_RowStack, UD_RK_RowStack, Yukon_RK_RowStack),
(self._shallHighlightMatch_RK,
self._shallHighlightMatch_RKW)),
((SC_RowStack, UD_SC_RowStack),
@ -169,48 +181,71 @@ class CustomGame(Game):
stack.acceptsCards = stack.varyAcceptsCards
stack.getBaseCard = stack.varyGetBaseCard
# Hint_Class
# TODO
if s['rows_type'] in (Yukon_SS_RowStack,
Yukon_AC_RowStack,
Yukon_RK_RowStack):
self.Hint_Class = Yukon_Hint
def startGame(self):
def deal(rows, flip, frames, max_cards):
if max_cards <= 0:
return 0
return self.s.talon.dealRowAvail(rows=rows, flip=flip,
frames=frames)
frames = 0
s = self.SETTINGS
max_cards = s['deal_max_cards'] - len(self.s.rows)
if self.s.waste:
max_cards -= 1
anim_frames = -1
# deal to reserves
n = self.SETTINGS['deal_to_reserves']
n = s['deal_to_reserves']
for i in range(n):
self.s.talon.dealRowAvail(rows=self.s.reserves,
flip=True, frames=frames)
max_cards -= deal(self.s.reserves[:max_cards],
True, frames, max_cards)
if frames == 0 and len(self.s.talon.cards) < 16:
frames = -1
frames = anim_frames
self.startDealSample()
# deal to rows
flip = (self.SETTINGS['deal_faceup'] == 'All cards')
max_rows = self.SETTINGS['deal_to_rows']
if self.SETTINGS['deal_type'] == 'Triangle':
face_down = s['deal_face_down']
max_rows = s['deal_face_down'] + s['deal_face_up']
if s['deal_type'] == 'Triangle':
# triangle
for i in range(1, len(self.s.rows)):
self.s.talon.dealRowAvail(rows=self.s.rows[i:],
flip=flip, frames=frames)
flip = (face_down <= 0)
max_cards -= deal(self.s.rows[i:i+max_cards],
flip, frames, max_cards)
face_down -= 1
max_rows -= 1
if max_rows == 1:
break
if frames == 0 and len(self.s.talon.cards) < 16:
frames = -1
frames = anim_frames
self.startDealSample()
else:
# rectangle
for i in range(max_rows-1):
self.s.talon.dealRowAvail(rows=self.s.rows,
flip=flip, frames=frames)
flip = (face_down <= 0)
max_cards -= deal(self.s.rows[:max_cards],
flip, frames, max_cards)
face_down -= 1
if frames == 0 and len(self.s.talon.cards) < 16:
frames = -1
frames = anim_frames
self.startDealSample()
if frames == 0:
self.startDealSample()
self.s.talon.dealRowAvail()
self.s.talon.dealRowAvail(frames=anim_frames)
if isinstance(self.s.talon, InitialDealTalonStack):
while self.s.talon.cards:
self.s.talon.dealRowAvail()
self.s.talon.dealRowAvail(frames=anim_frames)
# deal to waste
if self.s.waste:

View file

@ -2548,10 +2548,10 @@ for %d moves.
self.hints.list = None
# move type 3
def turnStackMove(self, from_stack, to_stack, update_flags=1):
def turnStackMove(self, from_stack, to_stack):
assert from_stack and to_stack and (from_stack is not to_stack)
assert len(to_stack.cards) == 0
am = ATurnStackMove(from_stack, to_stack, update_flags=update_flags)
am = ATurnStackMove(from_stack, to_stack)
self.__storeMove(am)
am.do(self)
self.hints.list = None

View file

@ -456,8 +456,9 @@ class GameInfo(Struct):
altnames=tuple(altnames),
decks=decks, redeals=redeals, ncards=ncards,
category=category, skill_level=skill_level,
suits=tuple(suits), ranks=tuple(ranks), trumps=tuple(trumps),
si=gi_si, rules_filename=rules_filename, plugin=0)
suits=tuple(suits), ranks=tuple(ranks),
trumps=tuple(trumps),
si=gi_si, rules_filename=rules_filename)
class GameManager:
@ -472,8 +473,8 @@ class GameManager:
self.__all_games = {} # includes hidden games
self.__all_gamenames = {} # includes hidden games
self.__games_for_solver = []
self.loading_plugin = False
self.check_game = True
self.current_filename = None
self.registered_game_types = {}
def getSelected(self):
@ -508,12 +509,11 @@ class GameManager:
raise GameInfoException("duplicate game altname %s: %s" %
(gi.id, n))
def register(self, gi, check_game=True):
def register(self, gi):
##print gi.id, gi.short_name.encode('utf-8')
if not isinstance(gi, GameInfo):
raise GameInfoException("wrong GameInfo class")
gi.plugin = self.loading_plugin
if self.check_game and (self.loading_plugin or CHECK_GAMES):
if self.check_game and CHECK_GAMES:
self._check_game(gi)
##if 0 and gi.si.game_flags & GI.GT_XORIGINAL:
## return
@ -541,6 +541,8 @@ class GameManager:
if hasattr(gi.gameclass, 'Solver_Class') and \
gi.gameclass.Solver_Class is not None:
self.__games_for_solver.append(gi.id)
if self.current_filename is not None:
gi.gameclass.MODULE_FILENAME = self.current_filename
#
# access games database - we do not expose hidden games
@ -612,10 +614,11 @@ def registerGame(gameinfo):
return gameinfo
def loadGame(modname, filename, plugin=True, check_game=True):
def loadGame(modname, filename, check_game=False):
##print "load game", modname, filename
GAME_DB.loading_plugin = plugin
GAME_DB.check_game = check_game
GAME_DB.current_filename = filename
module = imp.load_source(modname, filename)
##execfile(filename, globals(), globals())
GAME_DB.current_filename = None

View file

@ -108,7 +108,9 @@ class Matriarchy_Talon(WasteTalonStack):
if n < ncards and len(waste.cards) > 0:
assert len(self.cards) == 0
assert self.round < self.max_rounds or update_flags == 0
self.game.turnStackMove(waste, self, update_flags=update_flags)
self.game.turnStackMove(waste, self)
if update_flags:
self.game.nextRoundMove(self)
# do not update self.round anymore in this deal
update_flags = 0
assert self.round <= self.max_rounds

View file

@ -38,9 +38,9 @@ from pysollib.util import *
from pysollib.stack import *
from pysollib.game import Game
from pysollib.layout import Layout
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint
from pysollib.games.gypsy import Gypsy
from pysollib.games.yukon import Yukon_Hint
# /************************************************************************
# // Sanibel

View file

@ -68,7 +68,8 @@ class ThreePeaks_TalonStack(WasteTalonStack):
if sound:
self.game.playSample("turnwaste", priority=20)
num_cards = len(waste.cards)
game.turnStackMove(waste, self, update_flags=1)
game.turnStackMove(waste, self)
game.nextRoundMove(self)
game.leaveState(old_state)
return num_cards

View file

@ -41,41 +41,13 @@ from pysollib.mfxutil import kwdefault
from pysollib.stack import *
from pysollib.game import Game
from pysollib.layout import Layout
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint, Yukon_Hint
from pysollib.hint import YukonType_Hint
from pysollib.hint import FreeCellSolverWrapper
from pysollib.pysoltk import MfxCanvasText
from spider import Spider_SS_Foundation
# /***********************************************************************
# //
# ************************************************************************/
class Yukon_Hint(YukonType_Hint):
BONUS_FLIP_CARD = 9000
BONUS_CREATE_EMPTY_ROW = 100
## FIXME: this is only a rough approximation and doesn't seem to help
## for Russian Solitaire
def _getMovePileScore(self, score, color, r, t, pile, rpile):
s, color = YukonType_Hint._getMovePileScore(self, score, color, r, t, pile, rpile)
bonus = s - score
assert 0 <= bonus <= 9999
# We must take care when moving piles that we won't block cards,
# i.e. if there is a card in pile which would be needed
# for a card in stack t.
tpile = t.getPile()
if tpile:
for cr in pile:
rr = self.ClonedStack(r, stackcards=[cr])
for ct in tpile:
if rr.acceptsCards(t, [ct]):
d = bonus / 1000
bonus = (d * 1000) + bonus % 100
break
return score + bonus, color
# /***********************************************************************
# // Yukon

View file

@ -678,6 +678,31 @@ class YukonType_Hint(CautiousDefaultHint):
p = p[1:] # note: we need a fresh shallow copy
return piles
class Yukon_Hint(YukonType_Hint):
BONUS_FLIP_CARD = 9000
BONUS_CREATE_EMPTY_ROW = 100
## FIXME: this is only a rough approximation and doesn't seem to help
## for Russian Solitaire
def _getMovePileScore(self, score, color, r, t, pile, rpile):
s, color = YukonType_Hint._getMovePileScore(self, score, color, r, t, pile, rpile)
bonus = s - score
assert 0 <= bonus <= 9999
# We must take care when moving piles that we won't block cards,
# i.e. if there is a card in pile which would be needed
# for a card in stack t.
tpile = t.getPile()
if tpile:
for cr in pile:
rr = self.ClonedStack(r, stackcards=[cr])
for ct in tpile:
if rr.acceptsCards(t, [ct]):
d = bonus / 1000
bonus = (d * 1000) + bonus % 100
break
return score + bonus, color
# FIXME
class FreeCellType_Hint(CautiousDefaultHint):
pass

View file

@ -224,11 +224,10 @@ class AFlipAllMove(AtomicMove):
# ************************************************************************/
class ATurnStackMove(AtomicMove):
def __init__(self, from_stack, to_stack, update_flags=1):
def __init__(self, from_stack, to_stack):
assert from_stack is not to_stack
self.from_stack_id = from_stack.id
self.to_stack_id = to_stack.id
self.update_flags = update_flags
def redo(self, game):
from_stack = game.allstacks[self.from_stack_id]
@ -246,16 +245,6 @@ class ATurnStackMove(AtomicMove):
to_stack.addCard(card, unhide=unhide, update=0)
card.showBack(unhide=unhide)
##print 3, unhide, to_stack.getCard().__dict__
if self.update_flags & 2:
### not used yet
assert 0
from_stack.round = from_stack.round + 1
if self.update_flags & 1:
assert to_stack is game.s.talon
assert to_stack.round < to_stack.max_rounds or to_stack.max_rounds < 0
to_stack.round = to_stack.round + 1
from_stack.updateText()
to_stack.updateText()
def undo(self, game):
from_stack = game.allstacks[self.to_stack_id]
@ -270,22 +259,10 @@ class ATurnStackMove(AtomicMove):
assert not card.face_up
card.showFace(unhide=unhide)
to_stack.addCard(card, unhide=unhide, update=0)
if self.update_flags & 2:
### not used yet
assert 0
assert to_stack.round > 1
to_stack.round = to_stack.round - 1
if self.update_flags & 1:
assert from_stack is game.s.talon
assert from_stack.round > 1
from_stack.round = from_stack.round - 1
from_stack.updateText()
to_stack.updateText()
def cmpForRedo(self, other):
return (cmp(self.from_stack_id, other.from_stack_id) or
cmp(self.to_stack_id, other.to_stack_id) or
cmp(self.update_flags, other.update_flags))
cmp(self.to_stack_id, other.to_stack_id))
# /***********************************************************************

View file

@ -1840,7 +1840,7 @@ class DealRowRedealTalonStack(TalonStack, RedealCards_StackMethods):
return True
return False
def dealCards(self, sound=0, rows=None):
def dealCards(self, sound=0, rows=None, shuffle=False):
num_cards = 0
if rows is None:
rows = self.game.s.rows
@ -1849,12 +1849,19 @@ class DealRowRedealTalonStack(TalonStack, RedealCards_StackMethods):
if not self.cards:
# move all cards to talon
num_cards = self._redeal(rows=rows, frames=4)
if shuffle:
# shuffle
self.game.shuffleStackMove(self)
self.game.nextRoundMove(self)
num_cards += self.dealRowAvail(rows=rows, sound=0)
if sound:
self.game.stopSamples()
return num_cards
def shuffleAndDealCards(self, sound=0, rows=None):
DealRowRedealTalonStack.dealCards(self, sound=sound,
rows=rows, shuffle=True)
class DealReserveRedealTalonStack(DealRowRedealTalonStack):
@ -2564,7 +2571,7 @@ class WasteTalonStack(TalonStack):
return 1
return 0
def dealCards(self, sound=0):
def dealCards(self, sound=0, shuffle=False):
old_state = self.game.enterState(self.game.S_DEAL)
num_cards = 0
waste = self.waste
@ -2587,10 +2594,17 @@ class WasteTalonStack(TalonStack):
if sound:
self.game.playSample("turnwaste", priority=20)
num_cards = len(waste.cards)
self.game.turnStackMove(waste, self, update_flags=1)
self.game.turnStackMove(waste, self)
if shuffle:
# shuffle
self.game.shuffleStackMove(self)
self.game.nextRoundMove(self)
self.game.leaveState(old_state)
return num_cards
def shuffleAndDealCards(self, sound=0):
WasteTalonStack.dealCards(self, sound=sound, shuffle=True)
class FaceUpWasteTalonStack(WasteTalonStack):
def canFlipCard(self):

View file

@ -42,14 +42,14 @@ class WizSetting:
self.values_map = values_map
self.default = gettext(default)
##self.values_dict = dict(self.values_map)
self.translate_map = {}
self.translation_map = {}
##self.values = [i[0] for i in self.values_map]
if widget == 'menu':
self.values = []
for k, v in self.values_map:
t = gettext(k)
self.values.append(t)
self.translate_map[t] = k
self.translation_map[t] = k
assert self.default in self.values
else:
self.values = self.values_map
@ -100,7 +100,7 @@ LayoutType = WizSetting(
TalonType = WizSetting(
values_map = ((n_('Initial dealing'), InitialDealTalonStack),
(n_('Deal to waste'), WasteTalonStack),
(n_('Deal to rows'), DealRowTalonStack),
(n_('Deal to rows'), DealRowRedealTalonStack),
),
default = n_('Initial dealing'),
label = _('Type:'),
@ -124,6 +124,13 @@ DealToWaste = WizSetting(
label = _('Deal to waste:'),
var_name = 'deal_to_waste',
)
TalonShuffle = WizSetting(
values_map = (0, 1),
default = 0,
label = _('Shuffle:'),
var_name = 'talon_shuffle',
widget = 'check',
)
FoundType = WizSetting(
values_map = ((n_('Same suit'), SS_FoundationStack),
(n_('Alternate color'), AC_FoundationStack),
@ -184,12 +191,18 @@ RowsType = WizSetting(
(n_('Same color'), SC_RowStack),
(n_('Rank'), RK_RowStack),
(n_('Any suit but the same'), BO_RowStack),
(n_('Up or down by same suit'), UD_SS_RowStack),
(n_('Up or down by alternate color'), UD_AC_RowStack),
(n_('Up or down by rank'), UD_RK_RowStack),
(n_('Up or down by same color'), UD_SC_RowStack),
(n_('Spider same suit'), Spider_SS_RowStack),
(n_('Spider alternate color'), Spider_AC_RowStack),
(n_('Yukon same suit'), Yukon_SS_RowStack),
(n_('Yukon alternate color'), Yukon_AC_RowStack),
(n_('Yukon rank'), Yukon_RK_RowStack),
),
default = n_('Alternate color'),
label = _('Type:'),
@ -246,26 +259,34 @@ DealType = WizSetting(
label = _('Type:'),
var_name = 'deal_type',
)
DealFaceUp = WizSetting(
values_map = ((n_('Top cards'), 'top'), (n_('All cards'), 'all')),
default = n_('All cards'),
label = _('Face-up:'),
var_name = 'deal_faceup',
)
DealMaxRows = WizSetting(
DealFaceDown = WizSetting(
values_map = (0, 20),
default = 7,
default = 0,
widget = 'spin',
label = _('Deal to rows:'),
var_name = 'deal_to_rows',
label = _('# of face-down cards:'),
var_name = 'deal_face_down',
)
DealFaceUp = WizSetting(
values_map = (1, 20),
default = 8,
widget = 'spin',
label = _('# of face-up cards:'),
var_name = 'deal_face_up',
)
DealToReseves = WizSetting(
values_map = (0, 20),
default = 0,
widget = 'spin',
label = _('Deal ro reserves:'),
label = _('Deal to reserves:'),
var_name = 'deal_to_reserves',
)
DealMaxCards = WizSetting(
values_map = (0, 208),
default = 52,
widget = 'spin',
label = _('Max # of dealt cards:'),
var_name = 'deal_max_cards',
)
WizardWidgets = (
_('General'),
@ -277,6 +298,7 @@ WizardWidgets = (
TalonType,
Redeals,
DealToWaste,
TalonShuffle,
_('Foundations'),
FoundType,
FoundBaseCard,
@ -296,9 +318,10 @@ WizardWidgets = (
ReservesMaxAccept,
_('Initial dealing'),
DealType,
DealFaceDown,
DealFaceUp,
DealMaxRows,
DealToReseves,
DealMaxCards,
)
@ -319,17 +342,16 @@ def write_game(app, game=None):
check_game = True
else:
# edit current game
fn = game.SETTINGS['file']
fn = os.path.join(app.dn.plugins, fn)
fn = game.MODULE_FILENAME
mn = game.__module__
gameid = game.SETTINGS['gameid']
n = gameid-200000
check_game = False
##print '===>', fn
fd = open(fn, 'w')
fd.write('''\
## -*- coding: utf-8 -*-
## THIS FILE WAS GENERATED AUTOMATICALLY BY SOLITAIRE WIZARD
## DO NOT EDIT
@ -345,18 +367,19 @@ class MyCustomGame(CustomGame):
continue
v = w.variable.get()
if w.widget == 'menu':
v = w.translate_map[v]
v = w.translation_map[v]
if isinstance(v, int):
fd.write(" '%s': %i,\n" % (w.var_name, v))
else:
if w.var_name == 'name':
v = v.replace('\\', '\\\\')
v = v.replace("'", "\\'")
if isinstance(v, unicode):
v = v.encode('utf-8')
if not v:
v = 'Invalid Game Name'
fd.write(" '%s': '%s',\n" % (w.var_name, v))
fd.write(" 'gameid': %i,\n" % gameid)
fd.write(" 'file': '%s',\n" % os.path.split(fn)[1])
fd.write('''\
}