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

Revamped Pegged game and added manual first card removal option.

This commit is contained in:
Joe R 2021-12-02 20:40:44 -05:00
parent 940a5d584e
commit 7af8fde4c0
8 changed files with 106 additions and 19 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

View file

@ -9,8 +9,9 @@ Remove all but one card.
<h3>Rules</h3> <h3>Rules</h3>
<p> <p>
This is a classic puzzle game. Cards are removed by jumping over This is a classic puzzle game. At the start of the game, one card is
neighbour cards, and the space beyond the neighbour must be empty. removed. The remaining cards are removed by jumping over neighbour
cards, and the space beyond the neighbour must be empty.
<p> <p>
You win when there is only one card left. You win when there is only one card left.
@ -19,4 +20,8 @@ You win when there is only one card left.
To get awarded for a perfect game the remaining card must be To get awarded for a perfect game the remaining card must be
in the position of the initial free space. in the position of the initial free space.
<p> <p>
The first card can be removed automatically, or chosen by the
player and removed manually. This is based on an assist level
option that can be set in the Options menu.
<p>
<i>Autodrop</i> and <i>Quickplay</i> are disabled for this game. <i>Autodrop</i> and <i>Quickplay</i> are disabled for this game.

View file

@ -485,7 +485,7 @@ class GI:
('fc-2.12', tuple(range(774, 811)) + (16681,) + ('fc-2.12', tuple(range(774, 811)) + (16681,) +
tuple(range(22217, 22219))), tuple(range(22217, 22219))),
('fc-2.14', tuple(range(811, 827))), ('fc-2.14', tuple(range(811, 827))),
('fc-2.16', tuple(range(827, 839))) ('fc-2.16', tuple(range(827, 841)))
) )
# deprecated - the correct way is to or a GI.GT_XXX flag # deprecated - the correct way is to or a GI.GT_XXX flag

View file

@ -63,7 +63,21 @@ class Pegged_RowStack(ReserveStack):
def canDropCards(self, stacks): def canDropCards(self, stacks):
return (None, 0) return (None, 0)
def clickHandler(self, event):
game = self.game
for row in game.s.rows:
if len(row.cards) < 1:
return ReserveStack.clickHandler(self, event)
self.game.emptyStack = self.id
self.game.playSample("drop", priority=200)
self.playMoveMove(1, self.game.s.foundations[0])
return True
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
if type(to_stack) is Pegged_Foundation:
return ReserveStack.moveMove(self, ncards, to_stack, frames=frames,
shadow=shadow)
other_stack = to_stack._getMiddleStack(self) other_stack = to_stack._getMiddleStack(self)
old_state = self.game.enterState(self.game.S_FILL) old_state = self.game.enterState(self.game.S_FILL)
f = self.game.s.foundations[0] f = self.game.s.foundations[0]
@ -89,6 +103,16 @@ class Pegged_RowStack(ReserveStack):
clone.pos = self.pos clone.pos = self.pos
class Pegged_Foundation(AbstractFoundationStack):
def acceptsCards(self, from_stack, cards):
game = self.game
for row in game.s.rows:
if len(row.cards) < 1:
return False
return True
# ************************************************************************ # ************************************************************************
# * Pegged # * Pegged
# ************************************************************************ # ************************************************************************
@ -100,19 +124,20 @@ class Pegged(Game):
ROWS = (3, 5, 7, 7, 7, 5, 3) ROWS = (3, 5, 7, 7, 7, 5, 3)
EMPTY_STACK_ID = -1 EMPTY_STACK_ID = -1
GAME_VERSION = 2
# #
# game layout # game layout
# #
def createGame(self): def createGame(self):
self.emptyStack = self.EMPTY_STACK_ID
# create layout # create layout
l, s = Layout(self), self.s l, s = Layout(self), self.s
# set window # set window
n = m = max(self.ROWS) m = max(self.ROWS)
if self.ROWS[0] == m or self.ROWS[-1] == m: self.setSize(l.XM + m * l.XS, l.YM + len(self.ROWS) * l.YS)
n = n + 1
self.setSize(l.XM + n*l.XS, l.YM + len(self.ROWS)*l.YS)
# game extras 1) # game extras 1)
self.map = {} self.map = {}
@ -121,17 +146,17 @@ class Pegged(Game):
for i in range(len(self.ROWS)): for i in range(len(self.ROWS)):
r = self.ROWS[i] r = self.ROWS[i]
for j in range(r): for j in range(r):
d = m - r + 2*j d = m - r + 2 * j
x, y = l.XM + d*l.XS//2, l.YM + i*l.YS x, y = l.XM + d * l.XS // 2, l.YM + i * l.YS
stack = Pegged_RowStack(x, y, self) stack = Pegged_RowStack(x, y, self)
stack.pos = (d, 2*i) stack.pos = (d, 2 * i)
# print stack.id, stack.pos # print stack.id, stack.pos
s.rows.append(stack) s.rows.append(stack)
self.map[stack.pos] = stack self.map[stack.pos] = stack
x, y = self.width - l.XS, l.YM x, y = self.getInvisibleCoords()
s.foundations.append( s.foundations.append(
AbstractFoundationStack( Pegged_Foundation(
x, y, self, ANY_SUIT, max_move=0, max_accept=0, x, y, self, ANY_SUIT, max_move=0,
max_cards=self.gameinfo.ncards)) max_cards=self.gameinfo.ncards))
l.createText(s.foundations[0], "s") l.createText(s.foundations[0], "s")
y = self.height - l.YS y = self.height - l.YS
@ -160,13 +185,14 @@ class Pegged(Game):
card.showBack(unhide=0) card.showBack(unhide=0)
def startGame(self): def startGame(self):
n = len(self.cards) - len(self.s.rows) + 1
if n > 0:
self.moveMove(n, self.s.talon, self.s.internals[0], frames=0)
self.startDealSample() self.startDealSample()
rows = list(self.s.rows[:]) rows = list(self.s.rows[:])
rows.remove(rows[self.EMPTY_STACK_ID]) if self.app.opt.pegged_auto_remove:
rows.remove(rows[self.EMPTY_STACK_ID])
self.s.talon.dealRow(rows=rows, frames=4) self.s.talon.dealRow(rows=rows, frames=4)
if len(self.s.talon.cards) > 0:
self.moveMove(len(self.s.talon.cards), self.s.talon,
self.s.foundations[0], frames=0)
assert len(self.s.talon.cards) == 0 assert len(self.s.talon.cards) == 0
def isGameWon(self): def isGameWon(self):
@ -178,13 +204,23 @@ class Pegged(Game):
def getAutoStacks(self, event=None): def getAutoStacks(self, event=None):
return ((), (), ()) return ((), (), ())
def _restoreGameHook(self, game):
self.emptyStack = game.loadinfo.dval.get('EmptyStack')
def _loadGameHook(self, p):
self.loadinfo.addattr(dval=p.load())
def _saveGameHook(self, p):
dval = {'EmptyStack': self.emptyStack}
p.dump(dval)
# Pegged special: check for a perfect game # Pegged special: check for a perfect game
def getWinStatus(self): def getWinStatus(self):
won, status, updated = Game.getWinStatus(self) won, status, updated = Game.getWinStatus(self)
if status == 2: if status == 2:
stacks = [r for r in self.s.rows if r.cards] stacks = [r for r in self.s.rows if r.cards]
assert len(stacks) == 1 assert len(stacks) == 1
if stacks[0].id != self.EMPTY_STACK_ID: if stacks[0].id != self.emptyStack:
# not perfect # not perfect
return won, 1, self.U_WON return won, 1, self.U_WON
return won, status, updated return won, status, updated
@ -213,6 +249,19 @@ class PeggedCross2(Pegged):
ROWS = (3, 3, 3, 9, 9, 9, 3, 3, 3) ROWS = (3, 3, 3, 9, 9, 9, 3, 3, 3)
# The Continental Diamond layout - this one is commented
# because it's not known to be possible to have a perfect
# game, though it is winnable.
# class PeggedDiamond(Pegged):
# EMPTY_STACK_ID = 6
# ROWS = (1, 3, 5, 7, 9, 7, 5, 3, 1)
class PeggedDiamond(Pegged):
EMPTY_STACK_ID = 12
ROWS = (1, 3, 5, 7, 7, 5, 3, 1)
class Pegged6x6(Pegged): class Pegged6x6(Pegged):
EMPTY_STACK_ID = 14 EMPTY_STACK_ID = 14
ROWS = (6, 6, 6, 6, 6, 6) ROWS = (6, 6, 6, 6, 6, 6)
@ -236,6 +285,11 @@ class PeggedTriangle2(PeggedTriangle1):
ROWS = (1, 2, 3, 4, 5, 6) ROWS = (1, 2, 3, 4, 5, 6)
class PeggedStar(PeggedTriangle1):
EMPTY_STACK_ID = 0
ROWS = (1, 4, 3, 4, 1)
# ************************************************************************ # ************************************************************************
# * register the games # * register the games
# ************************************************************************ # ************************************************************************
@ -244,7 +298,6 @@ def r(id, gameclass, name):
ncards = 0 ncards = 0
for n in gameclass.ROWS: for n in gameclass.ROWS:
ncards += n ncards += n
ncards -= 1
gi = GameInfo(id, gameclass, name, gi = GameInfo(id, gameclass, name,
GI.GT_PEGGED, 1, 0, GI.SL_SKILL, GI.GT_PEGGED, 1, 0, GI.SL_SKILL,
category=GI.GC_TRUMP_ONLY, category=GI.GC_TRUMP_ONLY,
@ -262,4 +315,6 @@ r(183, Pegged6x6, "Pegged 6x6")
r(184, Pegged7x7, "Pegged 7x7") r(184, Pegged7x7, "Pegged 7x7")
r(210, PeggedTriangle1, "Pegged Triangle 1") r(210, PeggedTriangle1, "Pegged Triangle 1")
r(211, PeggedTriangle2, "Pegged Triangle 2") r(211, PeggedTriangle2, "Pegged Triangle 2")
r(839, PeggedDiamond, "Pegged Diamond")
r(840, PeggedStar, "Pegged Star")
del r del r

View file

@ -594,6 +594,11 @@ class OptionsMenuDialog(LMenuDialog):
self.menubar.tkopt.accordion_deal_all, self.menubar.tkopt.accordion_deal_all,
self.menubar.mOptAccordionDealAll) self.menubar.mOptAccordionDealAll)
self.addCheckNode(tv, rg,
_('Auto-remove first card (in Pegged games)'),
self.menubar.tkopt.accordion_deal_all,
self.menubar.mOptPeggedAutoRemove)
# submenu.add_separator() # submenu.add_separator()
# ------------------------------------------- # -------------------------------------------
@ -1253,6 +1258,7 @@ class PysolMenubarTk:
mahjongg_show_removed=BooleanVar(), mahjongg_show_removed=BooleanVar(),
shisen_show_hint=BooleanVar(), shisen_show_hint=BooleanVar(),
accordion_deal_all=BooleanVar(), accordion_deal_all=BooleanVar(),
pegged_auto_remove=BooleanVar(),
sound=BooleanVar(), sound=BooleanVar(),
sound_sample_volume=IntVar(), sound_sample_volume=IntVar(),
sound_music_volume=IntVar(), sound_music_volume=IntVar(),
@ -1315,6 +1321,7 @@ class PysolMenubarTk:
tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed) tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed)
tkopt.shisen_show_hint.set(opt.shisen_show_hint) tkopt.shisen_show_hint.set(opt.shisen_show_hint)
tkopt.accordion_deal_all.set(opt.accordion_deal_all) tkopt.accordion_deal_all.set(opt.accordion_deal_all)
tkopt.pegged_auto_remove.set(opt.pegged_auto_remove)
tkopt.sound.set(opt.sound) tkopt.sound.set(opt.sound)
tkopt.sound_sample_volume.set(opt.sound_sample_volume) tkopt.sound_sample_volume.set(opt.sound_sample_volume)
tkopt.sound_music_volume.set(opt.sound_music_volume) tkopt.sound_music_volume.set(opt.sound_music_volume)
@ -2118,6 +2125,12 @@ the next time you restart the %(app)s""") % {'app': TITLE})
self.app.opt.accordion_deal_all = self.tkopt.accordion_deal_all.get() self.app.opt.accordion_deal_all = self.tkopt.accordion_deal_all.get()
# self.game.updateMenus() # self.game.updateMenus()
def mOptPeggedAutoRemove(self, *args):
if self._cancelDrag(break_pause=False):
return
self.app.opt.pegged_auto_remove = self.tkopt.pegged_auto_remove.get()
# self.game.updateMenus()
def mOptCardset(self, *event): def mOptCardset(self, *event):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return

View file

@ -227,6 +227,7 @@ class Options:
('shisen_show_hint', 'bool'), ('shisen_show_hint', 'bool'),
('shisen_show_matching', 'bool'), ('shisen_show_matching', 'bool'),
('accordion_deal_all', 'bool'), ('accordion_deal_all', 'bool'),
('pegged_auto_remove', 'bool'),
('animations', 'int'), ('animations', 'int'),
('redeal_animation', 'bool'), ('redeal_animation', 'bool'),
('win_animation', 'bool'), ('win_animation', 'bool'),
@ -311,6 +312,7 @@ class Options:
self.mahjongg_show_removed = False self.mahjongg_show_removed = False
self.mahjongg_create_solvable = 2 # 0 - none, 1 - easy, 2 - hard self.mahjongg_create_solvable = 2 # 0 - none, 1 - easy, 2 - hard
self.accordion_deal_all = True self.accordion_deal_all = True
self.pegged_auto_remove = True
if TOOLKIT == 'kivy': if TOOLKIT == 'kivy':
self.mahjongg_create_solvable = 1 # 0 - none, 1 - easy, 2 - hard self.mahjongg_create_solvable = 1 # 0 - none, 1 - easy, 2 - hard
self.shisen_show_hint = True self.shisen_show_hint = True

View file

@ -169,6 +169,7 @@ class PysolMenubarTkCommon:
mahjongg_show_removed=tkinter.BooleanVar(), mahjongg_show_removed=tkinter.BooleanVar(),
shisen_show_hint=tkinter.BooleanVar(), shisen_show_hint=tkinter.BooleanVar(),
accordion_deal_all=tkinter.BooleanVar(), accordion_deal_all=tkinter.BooleanVar(),
pegged_auto_remove=tkinter.BooleanVar(),
sound=tkinter.BooleanVar(), sound=tkinter.BooleanVar(),
auto_scale=tkinter.BooleanVar(), auto_scale=tkinter.BooleanVar(),
preserve_aspect_ratio=tkinter.BooleanVar(), preserve_aspect_ratio=tkinter.BooleanVar(),
@ -224,6 +225,7 @@ class PysolMenubarTkCommon:
tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed) tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed)
tkopt.shisen_show_hint.set(opt.shisen_show_hint) tkopt.shisen_show_hint.set(opt.shisen_show_hint)
tkopt.accordion_deal_all.set(opt.accordion_deal_all) tkopt.accordion_deal_all.set(opt.accordion_deal_all)
tkopt.pegged_auto_remove.set(opt.pegged_auto_remove)
tkopt.sound.set(opt.sound) tkopt.sound.set(opt.sound)
tkopt.auto_scale.set(opt.auto_scale) tkopt.auto_scale.set(opt.auto_scale)
tkopt.preserve_aspect_ratio.set(opt.preserve_aspect_ratio) tkopt.preserve_aspect_ratio.set(opt.preserve_aspect_ratio)
@ -526,6 +528,10 @@ class PysolMenubarTkCommon:
label=n_("&Deal all cards (in Accordion type games)"), label=n_("&Deal all cards (in Accordion type games)"),
variable=self.tkopt.accordion_deal_all, variable=self.tkopt.accordion_deal_all,
command=self.mOptAccordionDealAll) command=self.mOptAccordionDealAll)
submenu.add_checkbutton(
label=n_("A&uto-remove first card (in Pegged games)"),
variable=self.tkopt.pegged_auto_remove,
command=self.mOptPeggedAutoRemove)
menu.add_separator() menu.add_separator()
label = n_("&Sound...") label = n_("&Sound...")
menu.add_command( menu.add_command(
@ -1472,6 +1478,12 @@ Unsupported game for import.
self.app.opt.accordion_deal_all = self.tkopt.accordion_deal_all.get() self.app.opt.accordion_deal_all = self.tkopt.accordion_deal_all.get()
# self.game.updateMenus() # self.game.updateMenus()
def mOptPeggedAutoRemove(self, *args):
if self._cancelDrag(break_pause=False):
return
self.app.opt.pegged_auto_remove = self.tkopt.pegged_auto_remove.get()
# self.game.updateMenus()
def _updateCardSize(self): def _updateCardSize(self):
geom = (self.app.canvas.winfo_width(), geom = (self.app.canvas.winfo_width(),
self.app.canvas.winfo_height()) self.app.canvas.winfo_height())