diff --git a/html-src/rules/fourkingdoms.html b/html-src/rules/fourkingdoms.html new file mode 100644 index 000000000..9b0e2d9e9 --- /dev/null +++ b/html-src/rules/fourkingdoms.html @@ -0,0 +1,51 @@ +

Four Kingdoms

+

+One-Deck game type. 1 deck. No redeal. + +

Object

+

+Move all cards to the different foundations. + +

Rules

+

+Cards are dealt to seven piles of four cards each, with only the top +card of each pile face-up. These are the free lands, and may be built +up by same suit. Any valid sequence can be moved, and any card or +sequence can be played in an empty space. +

+Above the free lands are multiple columns of foundations/reserves, +which accept different cards according depending on which other +piles have been played to. There is one row of these piles for each +suit. From left to right, these are: +

+

+Cards can be dealt from the talon one at a time, and moved to an +appropriate pile in the free lands, or any of the aforementioned +foundation/reserve piles. No redeal is allowed. +

+The game is won if all cards can be moved to their appropriate foundations, +thus uniting the four kingdoms. + +

Notes

+

+Four Kingdoms was invented by David Bernazzani. It was designed to try and +reclaim some of the original historical feel for the cards. diff --git a/po/de_pysol.po b/po/de_pysol.po index 3e6516c87..440265386 100644 --- a/po/de_pysol.po +++ b/po/de_pysol.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: PySol 0.0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2024-08-04 20:21-0400\n" +"PO-Revision-Date: 2024-09-08 09:52-0400\n" "Last-Translator: H. Schaekel \n" "Language-Team: German\n" "Language: de\n" @@ -2347,6 +2347,21 @@ msgstr "" "7: A 8 2 9 3 T 4 J 5 Q 6 K\n" "8: 3 J 6 A 9 4 Q 7 2 T 5 K" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "Tableau. Erstellt nach unten nach Farbe oder denselben Rang." diff --git a/po/fr_pysol.po b/po/fr_pysol.po index b426185bb..b36966e4d 100644 --- a/po/fr_pysol.po +++ b/po/fr_pysol.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: 1.02\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2024-08-04 20:20-0400\n" +"PO-Revision-Date: 2024-09-08 09:52-0400\n" "Last-Translator: Eric Rausch \n" "Language-Team: French\n" "Language: fr\n" @@ -2387,6 +2387,21 @@ msgstr "" "7: A 8 2 9 3 T 4 J 5 Q 6 K\n" "8: 3 J 6 A 9 4 Q 7 2 T 5 K" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "Tableau. Décroissant par enseigne ou de même valeur." diff --git a/po/it_pysol.po b/po/it_pysol.po index 68513c642..f6a651fbf 100644 --- a/po/it_pysol.po +++ b/po/it_pysol.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: it_pysol\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2024-08-04 20:19-0400\n" +"PO-Revision-Date: 2024-09-08 09:54-0400\n" "Last-Translator: Giuliano Colla \n" "Language-Team: Italiano \n" "Language: it\n" @@ -2395,6 +2395,21 @@ msgstr "" "7: A 8 2 9 3 T 4 J 5 Q 6 K\n" "8: 3 J 6 A 9 4 Q 7 2 T 5 K" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "Tableau: Sequenza decrescente dello stesso seme" diff --git a/po/pl_pysol.po b/po/pl_pysol.po index 523f5340d..460ef3ccc 100644 --- a/po/pl_pysol.po +++ b/po/pl_pysol.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PySolFC\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2024-08-04 20:19-0400\n" +"PO-Revision-Date: 2024-09-08 09:53-0400\n" "Last-Translator: Jerzy Trzeciak \n" "Language-Team: Polish \n" "Language: pl\n" @@ -2401,6 +2401,21 @@ msgstr "" "7: A 8 2 9 3 T 4 J 5 Q 6 K\n" "8: 3 J 6 A 9 4 Q 7 2 T 5 K" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "Stół gry. Układaj w dół wg koloru lub wg tej samej wartości." diff --git a/po/pt_BR_pysol.po b/po/pt_BR_pysol.po index 84c087fdf..2f5116791 100644 --- a/po/pt_BR_pysol.po +++ b/po/pt_BR_pysol.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2024-08-04 20:18-0400\n" +"PO-Revision-Date: 2024-09-08 09:53-0400\n" "Last-Translator: Matheus Knack \n" "Language-Team: \n" "Language: pt_BR\n" @@ -2408,6 +2408,21 @@ msgstr "" "7: A 8 2 9 3 T 4 J 5 Q 6 K\n" "8: 3 J 6 A 9 4 Q 7 2 T 5 K" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "Tableau. Construa decrescente por naipe or por valor igual." diff --git a/po/pysol.pot b/po/pysol.pot index 3a37bccd0..c5c54aa1d 100644 --- a/po/pysol.pot +++ b/po/pysol.pot @@ -2234,6 +2234,21 @@ msgid "\n" "8: 3 J 6 A 9 4 Q 7 2 T 5 K" msgstr "" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "" diff --git a/po/ru_pysol.po b/po/ru_pysol.po index 987de1d57..9f460da27 100644 --- a/po/ru_pysol.po +++ b/po/ru_pysol.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2024-08-04 20:17-0400\n" +"PO-Revision-Date: 2024-09-08 09:54-0400\n" "Last-Translator: Skomoroh \n" "Language-Team: Russian \n" "Language: ru\n" @@ -2393,6 +2393,21 @@ msgstr "" "7: A 8 2 9 3 10 4 В 5 Д 6 K\n" "8: 3 В 6 A 9 4 Д 7 2 10 5 K" +msgid "Dungeon" +msgstr "" + +msgid "Tower" +msgstr "" + +msgid "Guest" +msgstr "" + +msgid "Castle" +msgstr "" + +msgid "Subjects" +msgstr "" + #: pysollib/games/curdsandwhey.py:76 msgid "Tableau. Build down by suit or of the same rank." msgstr "" diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py index 25720084e..56d8f4ecd 100644 --- a/pysollib/gamedb.py +++ b/pysollib/gamedb.py @@ -418,7 +418,7 @@ def _callback(gi, gt=game_type): # Solitude for Windows # still missing: - # Bowling (Sackson version), Four Kingdoms, Icicles + # Bowling (Sackson version), Icicles ("Solitude for Windows", ( 2, 8, 11, 13, 19, 24, 25, 29, 30, 31, 33, 34, 36, 38, 42, 43, 45, 48, 50, 53, 56, 57, 58, 62, 64, 67, 69, 71, 86, 87, @@ -426,7 +426,7 @@ def _callback(gi, gt=game_type): 128, 133, 134, 135, 139, 146, 147, 171, 172, 173, 221, 222, 224, 228, 233, 234, 235, 256, 257, 258, 282, 314, 327, 330, 355, 356, 398, 406, 414, 418, 434, 437, 484, 593, 715, 716, - 737, 751, 805, 830, 845, 847, 888, 901, 903 + 737, 751, 805, 830, 845, 847, 888, 901, 903, 970 )), # XM Solitaire @@ -479,7 +479,7 @@ def _callback(gi, gt=game_type): ("Paul Alfille", (8,)), ("C.L. Baker", (45,)), ("Mark S. Ball", (909,)), - ("David Bernazzani", (314, 830,)), + ("David Bernazzani", (314, 830, 970,)), ("Gordon Bower", (763, 783, 852, 959,)), ("Art Cabral", (9,)), ("Richard A. Canfield", (105, 835,)), @@ -603,7 +603,7 @@ def _callback(gi, gt=game_type): tuple(range(13168, 13170)) + tuple(range(18000, 18005)) + tuple(range(19000, 19012)) + tuple(range(22303, 22311)) + tuple(range(22353, 22361))), - ('dev', tuple(range(961, 970))), + ('dev', tuple(range(961, 971))), ) # deprecated - the correct way is to or a GI.GT_XXX flag diff --git a/pysollib/games/moojub.py b/pysollib/games/moojub.py index 4f581001f..a83f1bffc 100644 --- a/pysollib/games/moojub.py +++ b/pysollib/games/moojub.py @@ -24,17 +24,25 @@ from pysollib.game import Game from pysollib.gamedb import GI, GameInfo, registerGame from pysollib.layout import Layout +from pysollib.mygettext import _ +from pysollib.pysoltk import MfxCanvasText from pysollib.stack import \ DealRowTalonStack, \ OpenStack, \ - RK_FoundationStack -from pysollib.util import ACE, ANY_SUIT, KING + RK_FoundationStack, \ + ReserveStack, \ + SS_FoundationStack, \ + SS_RowStack, \ + Stack, \ + WasteStack, \ + WasteTalonStack +from pysollib.util import ACE, ANY_SUIT, JACK, KING, QUEEN + # ************************************************************************ # * Moojub # ************************************************************************ - class Moojub_Foundation(RK_FoundationStack): def acceptsCards(self, from_stack, cards): if len(self.cards) > 0: @@ -107,6 +115,143 @@ def startGame(self): self._startAndDealRow() +# ************************************************************************ +# * Four Kingdoms +# ************************************************************************ + +class FourKingdoms_Foundation(SS_FoundationStack): + RequiredStacks = () + + def acceptsCards(self, from_stack, cards): + for stackID in self.RequiredStacks: + if len(self.game.s.foundations[self.id + stackID].cards) == 0: + return False + return SS_FoundationStack.acceptsCards(self, from_stack, cards) + + def getHelp(self): + return _('Foundation.') + + +class FourKingdoms_DungeonFoundation(FourKingdoms_Foundation): + RequiredStacks = (1, 2, 3, 4) + + +class FourKingdoms_QueenFoundation(FourKingdoms_Foundation): + RequiredStacks = (-1,) + + +class FourKingdoms_JackFoundation(FourKingdoms_Foundation): + RequiredStacks = (-1, -2) + + +class FourKingdoms_SubjectsFoundation(FourKingdoms_Foundation): + RequiredStacks = (-1, -2, -3) + + +class FourKingdoms_Reserve(ReserveStack): + getBottomImage = Stack._getSuitBottomImage + + def acceptsCards(self, from_stack, cards): + if cards[0].rank == ACE: + return False + checkStack = (6 * self.cap.base_suit) + 2 + for s in range(2): + if len(self.game.s.foundations[checkStack + s].cards) == 0: + return False + return ReserveStack.acceptsCards(self, from_stack, cards) + + +class FourKingdoms_RowStack(SS_RowStack): + + def acceptsCards(self, from_stack, cards): + if self.cards and self.cards[-1].rank == ACE: + return False + return SS_RowStack.acceptsCards(self, from_stack, cards) + + +class FourKingdoms(Game): + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + self.setSize(l.XM + (l.XS * 9), + l.YM + (6 * l.YS) + l.TEXT_HEIGHT) + + # create stacks + for i in range(4): + x, y = l.XM, l.YM + l.TEXT_HEIGHT + (l.YS * i) + s.foundations.append( + FourKingdoms_DungeonFoundation(x, y, self, i, base_rank=ACE, + max_cards=1, max_accept=1)) + x += (1.5 * l.XS) + s.foundations.append( + FourKingdoms_Foundation(x, y, self, i, base_rank=9, + max_cards=1, max_accept=1)) + x += (3 * l.XS) + s.foundations.append( + FourKingdoms_Foundation(x, y, self, i, base_rank=KING, + max_cards=1, max_accept=1)) + x += l.XS + s.foundations.append( + FourKingdoms_QueenFoundation(x, y, self, i, base_rank=QUEEN, + max_cards=1, max_accept=1)) + x += l.XS + s.foundations.append( + FourKingdoms_JackFoundation(x, y, self, i, base_rank=JACK, + max_cards=1, max_accept=1)) + x += (1.5 * l.XS) + s.foundations.append( + FourKingdoms_SubjectsFoundation(x, y, self, i, base_rank=8, + dir=-1, max_cards=8, + max_accept=1)) + + for i in range(4): + x, y = l.XM + (l.XS * 3), l.YM + l.TEXT_HEIGHT + (l.YS * i) + s.reserves.append( + FourKingdoms_Reserve(x, y, self, max_cards=1, max_accept=1)) + s.reserves[i].cap.base_suit = i + + if self.preview <= 1: + self.setLabel(l, self.s.foundations[0], "Dungeon") + self.setLabel(l, self.s.foundations[1], "Tower") + self.setLabel(l, self.s.foundations[3], "Castle") + self.setLabel(l, self.s.foundations[5], "Subjects") + self.setLabel(l, self.s.reserves[0], "Guest") + + x, y, = l.XM, l.YM + l.TEXT_HEIGHT + (l.YS * 4) + s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 'se') + y += l.YS + s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'se') + + x, y, = l.XM + l.XS, l.YM + l.TEXT_HEIGHT + (l.YS * 4) + for i in range(7): + x += l.XS + s.rows.append(FourKingdoms_RowStack(x, y, self, dir=1)) + + # define stack-groups + l.defaultStackGroups() + + def setLabel(self, layout, stack, text): + font = self.app.getFont("canvas_default") + tx, ty, ta, tf = layout.getTextAttr(stack, anchor="n") + stack.texts.misc = MfxCanvasText(self.canvas, + tx, ty, + anchor=ta, + font=font) + stack.texts.misc.config(text=_(text)) + + def startGame(self): + for i in range(3): + self.s.talon.dealRow(frames=0, flip=0) + self._startAndDealRowAndCards() + + # register the game registerGame(GameInfo(845, Moojub, "Moojub", GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) +registerGame(GameInfo(970, FourKingdoms, "Four Kingdoms", + GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED))