diff --git a/html-src/rules/accordionsrevenge.html b/html-src/rules/accordionsrevenge.html new file mode 100644 index 00000000..21d62ed3 --- /dev/null +++ b/html-src/rules/accordionsrevenge.html @@ -0,0 +1,20 @@ +
+One deck type. 1 deck. No redeal. + +
+Remove all the cards except the one card declared at the start. + +
+Like Accordion, +but at the start of the game, a single card is randomly declared. +This card must be the last remaining card in order to win the game. + + +
+Accordion's Revenge is unwinnable if the first or second card is +declared. As such, PySol will reselect the declared card if it +is chosen. diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py index b8346059..b4aa84a2 100644 --- a/pysollib/gamedb.py +++ b/pysollib/gamedb.py @@ -405,7 +405,8 @@ class GI: ('fc-2.1', tuple(range(767, 774))), ('fc-2.8', (343001,)), ('fc-2.12', tuple(range(774, 811)) + (16681,) + - tuple(range(22217, 22219))) + tuple(range(22217, 22219))), + ('fc-2.14', tuple(range(811, 812))) ) # deprecated - the correct way is to or a GI.GT_XXX flag diff --git a/pysollib/games/pushpin.py b/pysollib/games/pushpin.py index c9c90431..cb3585dc 100644 --- a/pysollib/games/pushpin.py +++ b/pysollib/games/pushpin.py @@ -25,12 +25,13 @@ from pysollib.game import Game from pysollib.gamedb import GI, GameInfo, registerGame from pysollib.hint import AbstractHint from pysollib.layout import Layout +from pysollib.pysoltk import MfxCanvasText from pysollib.stack import \ AbstractFoundationStack, \ DealRowTalonStack, \ ReserveStack, \ Stack -from pysollib.util import ANY_RANK, ANY_SUIT +from pysollib.util import ANY_RANK, ANY_SUIT, RANKS, SUITS_PL class PushPin_Hint(AbstractHint): @@ -125,6 +126,8 @@ class PushPin(Game): Hint_Class = PushPin_Hint RowStack_Class = PushPin_RowStack + Comment = False + # # game layout # @@ -133,9 +136,13 @@ class PushPin(Game): # create layout l, s = Layout(self), self.s + pad = 1 + if self.Comment: + pad = 5 + # set window xx, yy = 9, 6 - w, h = l.XM+xx*l.XS, l.YM+yy*l.YS + w, h = l.XM + xx * l.XS, (l.YM * pad) + yy * l.YS self.setSize(w, h) # create stacks @@ -149,9 +156,13 @@ class PushPin(Game): k = j if i % 2: k = xx-j-1 - x, y = l.XM + k*l.XS, l.YM + i*l.YS + x, y = l.XM + k*l.XS, (l.YM * pad) + i * l.YS s.rows.append(self.RowStack_Class(x, y, self)) - s.talon = PushPin_Talon(l.XM, l.YM, self) + s.talon = PushPin_Talon(l.XM, l.YM * pad, self) + if self.Comment: + self.texts.base_rank = \ + MfxCanvasText(self.canvas, l.XM, l.YM, anchor="nw", + font=self.app.getFont("canvas_default")) s.foundations.append(PushPin_Foundation(l.XM, h-l.YS, self, suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, max_accept=0, max_move=0, max_cards=52)) @@ -162,7 +173,11 @@ class PushPin(Game): def startGame(self): self.startDealSample() - self.s.talon.dealRow(rows=self.s.rows[:3]) + if self.app.opt.accordion_deal_all: + self.s.talon.dealRow(rows=self.s.rows[:47], frames=0) + self.s.talon.dealRow(rows=self.s.rows[47:52]) + else: + self.s.talon.dealRow(rows=self.s.rows[:3]) def isGameWon(self): return len(self.s.foundations[0].cards) == 50 @@ -270,10 +285,6 @@ class Accordion(PushPin): Hint_Class = Accordion_Hint RowStack_Class = Accordion_RowStack - def startGame(self): - self.startDealSample() - self.s.talon.dealRow(rows=self.s.rows[:2]) - def isGameWon(self): return len(self.s.foundations[0].cards) == 52 @@ -321,6 +332,60 @@ class RelaxedAccordion_RowStack(Accordion2_RowStack): class RelaxedAccordion(Accordion2): RowStack_Class = RelaxedAccordion_RowStack +# ************************************************************************ +# * Accordion's Revenge +# ************************************************************************ + + +class AccordionsRevenge(Accordion2): + Comment = True + + def createGame(self): + self.finalrank = -1 + self.finalsuit = -1 + + Accordion2.createGame(self) + + def startGame(self): + self.finalrank = -1 + self.finalsuit = -1 + self.updateText() + + Accordion2.startGame(self) + + while (self.finalrank == -1 or self.finalsuit == -1 or + (self.finalrank == self.s.rows[0].cards[0].rank and + self.finalsuit == self.s.rows[0].cards[0].suit) or + (self.finalrank == self.s.rows[1].cards[0].rank and + self.finalsuit == self.s.rows[1].cards[0].suit)): + self.finalsuit = self.random.choice(self.gameinfo.suits) + self.finalrank = self.random.choice(self.gameinfo.ranks) + + def isGameWon(self): + return (len(self.s.foundations[0].cards) == 51 and + self.s.rows[0].cards[0].rank == self.finalrank and + self.s.rows[0].cards[0].suit == self.finalsuit) + + def _restoreGameHook(self, game): + self.finalrank = game.loadinfo.dval.get('Rank') + self.finalsuit = game.loadinfo.dval.get('Suit') + + def _loadGameHook(self, p): + self.loadinfo.addattr(dval=p.load()) + + def _saveGameHook(self, p): + dval = {'Rank': self.finalrank, 'Suit': self.finalsuit} + p.dump(dval) + + def updateText(self): + if self.preview > 1: + return + if self.finalrank == -1 and self.finalsuit == -1: + self.texts.base_rank.config('') + else: + self.texts.base_rank.config(text=RANKS[self.finalrank] + + ' - ' + SUITS_PL[self.finalsuit]) + registerGame(GameInfo(287, PushPin, "Push Pin", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) @@ -335,3 +400,5 @@ registerGame(GameInfo(772, Accordion2, "Accordion", altnames=('Idle Year', 'Methuselah', 'Tower of Babel'))) registerGame(GameInfo(773, RelaxedAccordion, "Relaxed Accordion", GI.GT_1DECK_TYPE | GI.GT_RELAXED, 1, 0, GI.SL_BALANCED)) +registerGame(GameInfo(811, AccordionsRevenge, "Accordion's Revenge", + GI.GT_1DECK_TYPE | GI.GT_RELAXED, 1, 0, GI.SL_BALANCED)) diff --git a/pysollib/options.py b/pysollib/options.py index 78643018..e670e8cb 100644 --- a/pysollib/options.py +++ b/pysollib/options.py @@ -226,6 +226,7 @@ class Options: ('mahjongg_create_solvable', 'int'), ('shisen_show_hint', 'bool'), ('shisen_show_matching', 'bool'), + ('accordion_deal_all', 'bool'), ('animations', 'int'), ('redeal_animation', 'bool'), ('win_animation', 'bool'), @@ -308,6 +309,7 @@ class Options: self.highlight_not_matching = True self.mahjongg_show_removed = False self.mahjongg_create_solvable = 2 # 0 - none, 1 - easy, 2 - hard + self.accordion_deal_all = True if TOOLKIT == 'kivy': self.mahjongg_create_solvable = 1 # 0 - none, 1 - easy, 2 - hard self.shisen_show_hint = True diff --git a/pysollib/ui/tktile/menubar.py b/pysollib/ui/tktile/menubar.py index 1526a726..d810ee8d 100644 --- a/pysollib/ui/tktile/menubar.py +++ b/pysollib/ui/tktile/menubar.py @@ -169,6 +169,7 @@ class PysolMenubarTkCommon: highlight_not_matching=tkinter.BooleanVar(), mahjongg_show_removed=tkinter.BooleanVar(), shisen_show_hint=tkinter.BooleanVar(), + accordion_deal_all=tkinter.BooleanVar(), sound=tkinter.BooleanVar(), auto_scale=tkinter.BooleanVar(), spread_stacks=tkinter.BooleanVar(), @@ -222,6 +223,7 @@ class PysolMenubarTkCommon: tkopt.shade_filled_stacks.set(opt.shade_filled_stacks) tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed) tkopt.shisen_show_hint.set(opt.shisen_show_hint) + tkopt.accordion_deal_all.set(opt.accordion_deal_all) tkopt.sound.set(opt.sound) tkopt.auto_scale.set(opt.auto_scale) tkopt.spread_stacks.set(opt.spread_stacks) @@ -516,6 +518,10 @@ class PysolMenubarTkCommon: label=n_("Show hint &arrow (in Shisen-Sho games)"), variable=self.tkopt.shisen_show_hint, command=self.mOptShisenShowHint) + submenu.add_checkbutton( + label=n_("Deal all cards (in Accordion type games)"), + variable=self.tkopt.accordion_deal_all, + command=self.mOptAccordionDealAll) menu.add_separator() label = n_("&Sound...") menu.add_command( @@ -1429,6 +1435,12 @@ Unsupported game for import. self.app.opt.shisen_show_hint = self.tkopt.shisen_show_hint.get() # self.game.updateMenus() + def mOptAccordionDealAll(self, *args): + if self._cancelDrag(break_pause=False): + return + self.app.opt.accordion_deal_all = self.tkopt.accordion_deal_all.get() + # self.game.updateMenus() + def _updateCardSize(self): geom = (self.app.canvas.winfo_width(), self.app.canvas.winfo_height()) diff --git a/pysollib/util.py b/pysollib/util.py index 6dd40d7e..45b24ad6 100644 --- a/pysollib/util.py +++ b/pysollib/util.py @@ -43,6 +43,7 @@ from pysollib.settings import DATA_DIRS, TOOLKIT # Suits values are 0-3. This maps to colors 0-1. SUITS = (_("Club"), _("Spade"), _("Heart"), _("Diamond")) +SUITS_PL = (_("Clubs"), _("Spades"), _("Hearts"), _("Diamonds")) COLORS = (_("black"), _("red")) # Card ranks are 0-12. We also define symbolic names for the picture cards.