mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
+ 3 new games
+ new stack - ArbitraryStack, new AtomicMove - ASingleCardMove git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@22 39dd0a4e-7c14-0410-91b3-c4f2d318f732
This commit is contained in:
parent
d71672694a
commit
2c7c722413
6 changed files with 272 additions and 21 deletions
|
@ -62,7 +62,7 @@ from pysoltk import Card
|
|||
from move import AMoveMove, AFlipMove, ATurnStackMove
|
||||
from move import ANextRoundMove, ASaveSeedMove, AShuffleStackMove
|
||||
from move import AUpdateStackMove, AFlipAllMove, ASaveStateMove
|
||||
from move import ACloseStackMove
|
||||
from move import ACloseStackMove, ASingleCardMove
|
||||
from hint import DefaultHint
|
||||
from help import helpAbout
|
||||
|
||||
|
@ -228,6 +228,7 @@ class Game:
|
|||
start_y = 0, # Y coord of initial drag event
|
||||
stack = None, #
|
||||
cards = [], #
|
||||
index = -1, #
|
||||
shadows = [], # list of canvas images
|
||||
shade_stack = None, # stack currently shaded
|
||||
shade_img = None, # canvas image
|
||||
|
@ -1963,6 +1964,13 @@ for %d moves.
|
|||
self.__storeMove(am)
|
||||
am.do(self)
|
||||
|
||||
def singleCardMove(self, from_stack, to_stack, position, frames=-1, shadow=-1):
|
||||
am = ASingleCardMove(from_stack, to_stack, position, frames, shadow)
|
||||
self.__storeMove(am)
|
||||
am.do(self)
|
||||
self.hints.list = None
|
||||
|
||||
|
||||
|
||||
# Finish the current move.
|
||||
def finishMove(self):
|
||||
|
|
|
@ -219,6 +219,35 @@ class Arabella(DoubleKlondike):
|
|||
return 0
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# // Big Deal
|
||||
# ************************************************************************/
|
||||
|
||||
class BigDeal(DoubleKlondike):
|
||||
def createGame(self, rows=12, max_rounds=2):
|
||||
l, s = Layout(self), self.s
|
||||
self.setSize(l.XM+(rows+2)*l.XS, l.YM+8*l.YS)
|
||||
x, y = l.XM, l.YM
|
||||
for i in range(rows):
|
||||
s.rows.append(AC_RowStack(x, y, self, base_rank=KING))
|
||||
x += l.XS
|
||||
for i in range(2):
|
||||
y = l.YM
|
||||
for j in range(8):
|
||||
s.foundations.append(SS_FoundationStack(x, y, self, suit=j%4))
|
||||
y += l.YS
|
||||
x += l.XS
|
||||
x, y = l.XM, self.height-l.YS
|
||||
s.talon = WasteTalonStack(x, y, self, max_rounds=max_rounds)
|
||||
l.createText(s.talon, 'n')
|
||||
x += l.XS
|
||||
s.waste = WasteStack(x, y, self)
|
||||
l.createText(s.waste, 'n')
|
||||
self.setRegion(s.rows, (-999, -999, l.XM+rows*l.XS-l.CW/2, 999999), priority=1)
|
||||
l.defaultStackGroups()
|
||||
|
||||
|
||||
|
||||
# register the game
|
||||
registerGame(GameInfo(21, DoubleKlondike, "Double Klondike",
|
||||
GI.GT_KLONDIKE, 2, -1, GI.SL_BALANCED))
|
||||
|
@ -241,4 +270,6 @@ registerGame(GameInfo(496, Inquisitor, "Inquisitor",
|
|||
GI.GT_KLONDIKE, 2, 2, GI.SL_BALANCED))
|
||||
registerGame(GameInfo(497, Arabella, "Arabella",
|
||||
GI.GT_KLONDIKE, 3, 0, GI.SL_BALANCED))
|
||||
registerGame(GameInfo(545, BigDeal, "Big Deal",
|
||||
GI.GT_KLONDIKE | GI.GT_ORIGINAL, 4, 1, GI.SL_BALANCED))
|
||||
|
||||
|
|
|
@ -486,7 +486,7 @@ class FlowerGarden(Stonewall):
|
|||
# // Brigade
|
||||
# ************************************************************************/
|
||||
|
||||
class KingAlbert(Klondike):
|
||||
class KingAlbertOld(Klondike):
|
||||
Talon_Class = InitialDealTalonStack
|
||||
RowStack_Class = StackWrapper(AC_RowStack, max_move=1)
|
||||
Hint_Class = CautiousDefaultHint
|
||||
|
@ -511,6 +511,19 @@ class KingAlbert(Klondike):
|
|||
self.s.talon.dealRow(rows=self.s.reserves)
|
||||
|
||||
|
||||
class KingAlbert(KingAlbertOld):
|
||||
|
||||
def createGame(self):
|
||||
l = Klondike.createGame(self, max_rounds=1, rows=self.ROWS, waste=0, texts=0)
|
||||
self.setSize(self.width+l.XM+l.XS, self.height)
|
||||
self.s.reserves.append(ArbitraryStack(self.width-l.XS, l.YM, self))
|
||||
l.defaultStackGroups()
|
||||
|
||||
def startGame(self):
|
||||
Klondike.startGame(self, flip=1, reverse=0)
|
||||
self.s.talon.dealRow(rows=self.s.reserves*7)
|
||||
|
||||
|
||||
class Raglan(KingAlbert):
|
||||
RESERVES = (2, 2, 2)
|
||||
|
||||
|
|
|
@ -396,11 +396,13 @@ class Wasp(Scorpion):
|
|||
|
||||
# /***********************************************************************
|
||||
# // Three Blind Mice
|
||||
# // Farmer's Wife
|
||||
# ************************************************************************/
|
||||
|
||||
class ThreeBlindMice(Scorpion):
|
||||
|
||||
Talon_Class = InitialDealTalonStack
|
||||
ReserveStack_Class = OpenStack
|
||||
|
||||
def createGame(self):
|
||||
# create layout
|
||||
|
@ -420,7 +422,7 @@ class ThreeBlindMice(Scorpion):
|
|||
x += l.XS
|
||||
x, y = l.XM, l.YM
|
||||
for i in range(2):
|
||||
s.reserves.append(OpenStack(x, y, self, max_move=1, max_accept=0))
|
||||
s.reserves.append(self.ReserveStack_Class(x, y, self))
|
||||
x += l.XS
|
||||
# default
|
||||
l.defaultAll()
|
||||
|
@ -435,6 +437,15 @@ class ThreeBlindMice(Scorpion):
|
|||
self.s.talon.dealRow(rows=self.s.reserves)
|
||||
|
||||
|
||||
class FarmersWife(ThreeBlindMice):
|
||||
Foundation_Class = Spider_AC_Foundation
|
||||
RowStack_Class = StackWrapper(ScorpionTail_RowStack, base_rank=KING)
|
||||
|
||||
|
||||
class HowTheyRun(ThreeBlindMice):
|
||||
ReserveStack_Class = ReserveStack
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# // Rouge et Noir
|
||||
# ************************************************************************/
|
||||
|
@ -1109,4 +1120,8 @@ registerGame(GameInfo(511, DoubleScorpion, "Double Scorpion",
|
|||
GI.GT_SPIDER, 2, 0, GI.SL_MOSTLY_SKILL))
|
||||
registerGame(GameInfo(512, TripleScorpion, "Triple Scorpion",
|
||||
GI.GT_SPIDER, 3, 0, GI.SL_MOSTLY_SKILL))
|
||||
registerGame(GameInfo(543, FarmersWife, "Farmer's Wife",
|
||||
GI.GT_SPIDER, 1, 0, GI.SL_MOSTLY_SKILL))
|
||||
registerGame(GameInfo(544, HowTheyRun, "How They Run",
|
||||
GI.GT_SPIDER, 1, 0, GI.SL_MOSTLY_SKILL))
|
||||
|
||||
|
|
|
@ -446,15 +446,79 @@ class ACloseStackMove(AtomicMove):
|
|||
def redo(self, game):
|
||||
stack = game.allstacks[self.stack_id]
|
||||
assert stack.cards
|
||||
stack.is_closed = True
|
||||
stack.is_filled = True
|
||||
stack._shadeStack()
|
||||
|
||||
def undo(self, game):
|
||||
stack = game.allstacks[self.stack_id]
|
||||
assert stack.cards
|
||||
stack.is_closed = False
|
||||
stack.is_filled = False
|
||||
stack._unshadeStack()
|
||||
|
||||
def cmpForRedo(self, other):
|
||||
return cmp(self.stack_id, other.stack_id)
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# // ASingleCardMove - move single card from *anyone* position
|
||||
# ************************************************************************/
|
||||
|
||||
class ASingleCardMove(AtomicMove):
|
||||
|
||||
def __init__(self, from_stack, to_stack, from_pos, frames, shadow=-1):
|
||||
self.from_stack_id = from_stack.id
|
||||
self.to_stack_id = to_stack.id
|
||||
self.from_pos = from_pos
|
||||
self.frames = frames
|
||||
self.shadow = shadow
|
||||
|
||||
def redo(self, game):
|
||||
from_stack = game.allstacks[self.from_stack_id]
|
||||
to_stack = game.allstacks[self.to_stack_id]
|
||||
from_pos = self.from_pos
|
||||
if game.moves.state == game.S_PLAY:
|
||||
assert to_stack.acceptsCards(from_stack, [from_stack.cards[from_pos]])
|
||||
card = from_stack.cards[from_pos]
|
||||
card = from_stack.removeCard(card, update_positions=1)
|
||||
if self.frames != 0:
|
||||
x, y = to_stack.getPositionFor(card)
|
||||
game.animatedMoveTo(from_stack, to_stack, [card], x, y,
|
||||
frames=self.frames, shadow=self.shadow)
|
||||
to_stack.addCard(card)
|
||||
|
||||
def undo(self, game):
|
||||
from_stack = game.allstacks[self.from_stack_id]
|
||||
to_stack = game.allstacks[self.to_stack_id]
|
||||
from_pos = self.from_pos
|
||||
card = to_stack.removeCard()
|
||||
## if self.frames != 0:
|
||||
## x, y = to_stack.getPositionFor(card)
|
||||
## game.animatedMoveTo(from_stack, to_stack, [card], x, y,
|
||||
## frames=self.frames, shadow=self.shadow)
|
||||
from_stack.insertCard(card, from_pos)
|
||||
|
||||
def cmpForRedo(self, other):
|
||||
return cmp((self.from_stack_id, self.to_stack_id, self.from_pos),
|
||||
(other.from_stack_id, other.to_stack_id, other.from_pos))
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# // AInnerMove - change position of single card in stack
|
||||
# ************************************************************************/
|
||||
|
||||
class AInnerMove(AtomicMove):
|
||||
|
||||
def __init__(self, stack, from_pos, to_pos):
|
||||
self.stack_id = stack.id
|
||||
self.from_pos, self.to_pos = from_pos, to_pos
|
||||
|
||||
def redo(self, game):
|
||||
pass
|
||||
|
||||
def undo(self, game):
|
||||
pass
|
||||
|
||||
def cmpForRedo(self, other):
|
||||
return cmp((self.stack_id, self.from_pos, self.to_pos),
|
||||
(other.stack_id, other.from_pos, other.to_pos))
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ __all__ = ['cardsFaceUp',
|
|||
'StackWrapper',
|
||||
'WeakStackWrapper',
|
||||
'FullStackWrapper',
|
||||
'ArbitraryStack',
|
||||
]
|
||||
|
||||
# imports
|
||||
|
@ -301,7 +302,7 @@ class Stack:
|
|||
view.can_hide_cards = -1
|
||||
view.max_shadow_cards = -1
|
||||
#
|
||||
view.is_closed = False
|
||||
view.is_filled = False
|
||||
|
||||
def destruct(self):
|
||||
# help breaking circular references
|
||||
|
@ -431,8 +432,24 @@ class Stack:
|
|||
self.closeStackMove()
|
||||
return card
|
||||
|
||||
def insertCard(self, card, positon, unhide=1, update=1):
|
||||
model, view = self, self
|
||||
model.cards.insert(positon, card)
|
||||
for c in model.cards[positon:]:
|
||||
c.tkraise(unhide=unhide)
|
||||
if view.can_hide_cards and len(model.cards) >= 3 and len(model.cards)-positon <= 2:
|
||||
# we only need to display the 2 top cards
|
||||
model.cards[-3].hide(self)
|
||||
card.item.addtag(view.group)
|
||||
for c in model.cards[positon:]:
|
||||
view._position(c)
|
||||
if update:
|
||||
view.updateText()
|
||||
self.closeStackMove()
|
||||
return card
|
||||
|
||||
# Remove a card from the stack. Also update display. {model -> view}
|
||||
def removeCard(self, card=None, unhide=1, update=1):
|
||||
def removeCard(self, card=None, unhide=1, update=1, update_positions=0):
|
||||
model, view = self, self
|
||||
assert len(model.cards) > 0
|
||||
if card is None:
|
||||
|
@ -453,12 +470,16 @@ class Stack:
|
|||
if card is model.cards[-1] or model is self.cards[-2]:
|
||||
# Make sure that 2 top cards will be un-hidden.
|
||||
model.cards[-3].unhide()
|
||||
card_index = model.cards.index(card)
|
||||
model.cards.remove(card)
|
||||
if update_positions:
|
||||
for c in model.cards[card_index:]:
|
||||
view._position(c)
|
||||
if update:
|
||||
view.updateText()
|
||||
if self.is_closed:
|
||||
if self.is_filled:
|
||||
self._unshadeStack()
|
||||
self.is_closed = False
|
||||
self.is_filled = False
|
||||
return card
|
||||
|
||||
# Get the top card {model}
|
||||
|
@ -979,6 +1000,9 @@ class Stack:
|
|||
# Drag internals {controller -> model -> view}
|
||||
#
|
||||
|
||||
def getDragCards(self, index):
|
||||
return self.cards[index:]
|
||||
|
||||
# begin a drag operation
|
||||
def startDrag(self, event, sound=1):
|
||||
#print event.x, event.y
|
||||
|
@ -986,7 +1010,7 @@ class Stack:
|
|||
i = self._findCard(event)
|
||||
if i < 0 or not self.canMoveCards(self.cards[i:]):
|
||||
return
|
||||
if self.is_closed:
|
||||
if self.is_filled:
|
||||
self.items.shade_item.config(state='hidden')
|
||||
x_offset, y_offset = self.cards[i].x, self.cards[i].y
|
||||
if sound:
|
||||
|
@ -999,7 +1023,8 @@ class Stack:
|
|||
drag.start_y = event.y
|
||||
drag.stack = self
|
||||
drag.noshade_stacks = [ self ]
|
||||
drag.cards = self.cards[i:]
|
||||
drag.cards = self.getDragCards(i)
|
||||
drag.index = i
|
||||
images = game.app.images
|
||||
drag.shadows = self.createShadows(drag.cards)
|
||||
##sx, sy = 0, 0
|
||||
|
@ -1199,7 +1224,7 @@ class Stack:
|
|||
drag.shadows = []
|
||||
drag.stack = None
|
||||
drag.cards = []
|
||||
if self.is_closed:
|
||||
if self.is_filled:
|
||||
self.items.shade_item.config(state='normal')
|
||||
self.items.shade_item.tkraise()
|
||||
|
||||
|
@ -1639,6 +1664,9 @@ class OpenStack(Stack):
|
|||
return self.highlightMatchingCards(event)
|
||||
return 0
|
||||
|
||||
def dragMove(self, drag, stack, sound=1):
|
||||
self.playMoveMove(len(drag.cards), stack, frames=0, sound=sound)
|
||||
|
||||
def releaseHandler(self, event, drag, sound=1):
|
||||
cards = drag.cards
|
||||
# check if we moved the card by at least 10 pixels
|
||||
|
@ -1657,7 +1685,8 @@ class OpenStack(Stack):
|
|||
Stack.releaseHandler(self, event, drag, sound=sound)
|
||||
else:
|
||||
# this code actually moves the cards to the new stack
|
||||
self.playMoveMove(len(cards), stack, frames=0, sound=sound)
|
||||
##self.playMoveMove(len(cards), stack, frames=0, sound=sound)
|
||||
self.dragMove(drag, stack, sound=sound)
|
||||
|
||||
def quickPlayHandler(self, event, from_stacks=None, to_stacks=None):
|
||||
##print 'quickPlayHandler', from_stacks, to_stacks
|
||||
|
@ -1697,12 +1726,11 @@ class OpenStack(Stack):
|
|||
#
|
||||
if moves:
|
||||
moves.sort()
|
||||
moves.reverse()
|
||||
##from pprint import pprint
|
||||
##pprint(moves)
|
||||
if moves[0][0] >= 0:
|
||||
##from pprint import pprint; pprint(moves)
|
||||
score, len_moves, ncards, from_stack, to_stack = moves[-1]
|
||||
if score >= 0:
|
||||
##self.game.playSample("startdrag")
|
||||
moves[0][3].playMoveMove(moves[0][2], moves[0][4])
|
||||
from_stack.playMoveMove(ncards, to_stack)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
@ -2163,6 +2191,101 @@ class InvisibleStack(Stack):
|
|||
return None
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# // ArbitraryStack (stack with arbitrary access)
|
||||
# ************************************************************************/
|
||||
|
||||
class ArbitraryStack(OpenStack):
|
||||
|
||||
def __init__(self, x, y, game, **cap):
|
||||
kwdefault(cap, max_accept=0)
|
||||
apply(OpenStack.__init__, (self, x, y, game), cap)
|
||||
self.CARD_YOFFSET = game.app.images.CARD_YOFFSET
|
||||
|
||||
def canMoveCards(self, cards):
|
||||
return True
|
||||
|
||||
def getDragCards(self, index):
|
||||
return [ self.cards[index] ]
|
||||
|
||||
def startDrag(self, event, sound=1):
|
||||
OpenStack.startDrag(self, event, sound=sound)
|
||||
|
||||
def doubleclickHandler(self, event):
|
||||
# flip or drop a card
|
||||
flipstacks, dropstacks, quickstacks = self.game.getAutoStacks(event)
|
||||
if self in flipstacks and self.canFlipCard():
|
||||
self.playFlipMove()
|
||||
return -1 # continue this event (start a drag)
|
||||
if self in dropstacks:
|
||||
i = self._findCard(event)
|
||||
if i < 0:
|
||||
return 0
|
||||
cards = [ self.cards[i] ]
|
||||
for s in self.game.s.foundations:
|
||||
if s is not self and s.acceptsCards(self, cards):
|
||||
self.game.playSample("autodrop", priority=30)
|
||||
self.playSingleCardMove(i, s, sound=0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
## def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
|
||||
## i = len(self.cards)-1
|
||||
## self.singleCardMove(i, to_stack, frames=frames, shadow=shadow)
|
||||
|
||||
def moveCardsBackHandler(self, event, drag):
|
||||
i = self.cards.index(drag.cards[0])
|
||||
for card in self.cards[i:]:
|
||||
self._position(card)
|
||||
card.tkraise()
|
||||
|
||||
def singleCardMove(self, index, to_stack, frames=-1, shadow=-1):
|
||||
self.game.singleCardMove(self, to_stack, index, frames=frames, shadow=shadow)
|
||||
self.fillStack()
|
||||
|
||||
def dragMove(self, drag, to_stack, sound=1):
|
||||
self.playSingleCardMove(drag.index, to_stack, frames=0, sound=sound)
|
||||
|
||||
def playSingleCardMove(self, index, to_stack, frames=-1, shadow=-1, sound=1):
|
||||
if sound:
|
||||
if to_stack in self.game.s.foundations:
|
||||
self.game.playSample("drop", priority=30)
|
||||
else:
|
||||
self.game.playSample("move", priority=10)
|
||||
self.singleCardMove(index, to_stack, frames=frames, shadow=shadow)
|
||||
if not self.game.checkForWin():
|
||||
# let the player put cards back from the foundations
|
||||
if not self in self.game.s.foundations:
|
||||
self.game.autoPlay()
|
||||
self.game.finishMove()
|
||||
|
||||
def quickPlayHandler(self, event, from_stacks=None, to_stacks=None):
|
||||
if to_stacks is None:
|
||||
to_stacks = self.game.s.foundations + self.game.sg.dropstacks
|
||||
if not self.cards:
|
||||
return 0
|
||||
#
|
||||
moves = []
|
||||
i = self._findCard(event)
|
||||
if i < 0:
|
||||
return 0
|
||||
pile = [ self.cards[i] ]
|
||||
for s in to_stacks:
|
||||
if s is not self and s.acceptsCards(self, pile):
|
||||
score = self.game.getQuickPlayScore(1, self, s)
|
||||
moves.append((score, -len(moves), i, s))
|
||||
#
|
||||
if moves:
|
||||
moves.sort()
|
||||
##from pprint import pprint; pprint(moves)
|
||||
score, len_moves, index, to_stack = moves[-1]
|
||||
if score >= 0:
|
||||
##self.game.playSample("startdrag")
|
||||
self.playSingleCardMove(index, to_stack)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# // A StackWrapper is a functor (function object) that creates a
|
||||
# // new stack when called, i.e. it wraps the constructor.
|
||||
|
@ -2199,7 +2322,4 @@ class FullStackWrapper(StackWrapper):
|
|||
return apply(self.stack_class, (x, y, game), self.cap)
|
||||
|
||||
|
||||
# /***********************************************************************
|
||||
# //
|
||||
# ************************************************************************/
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue