diff --git a/html-src/rules/rainbowfan.html b/html-src/rules/rainbowfan.html new file mode 100644 index 00000000..393b257b --- /dev/null +++ b/html-src/rules/rainbowfan.html @@ -0,0 +1,33 @@ +
+Fan game type. 2 decks. 3 redeals. + +
+Move all cards to the foundations. + +
+There are eight foundations. At the start of the game, a king of +each suit is placed on the bottom of four of them, and an ace on the +other four. The foundations that start with a king are built down +by suit, while the ones that start with an ace are built up. +
+The tableau consists of twenty piles of three cards, and may be +built up or down by suit. When building tableau piles, sequences +can turn the corner, so aces may be played on kings and vice versa. +However, this cannot be done in the foundation. +
+If there are still cards in the talon, three cards are dealt from +the talon to fill in empty tableau piles. Once the talon is empty, +empty tableau piles can no longer be filled. +
+Three redeals are allowed. During each redeal, the bottom card of +each tableau pile is moved to the top of that pile. The remaining +cards are unmoved. + +
+This game is traditionally known as Rainbow - it is often renamed +Rainbow Fan to avoid confusion with a Canfield variation of the same +name. diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py index d9d2e582..b85b6433 100644 --- a/pysollib/gamedb.py +++ b/pysollib/gamedb.py @@ -337,6 +337,12 @@ class GI: ("Microsoft Solitaire Collection", (2, 8, 11, 38, 22231,)), # XM Solitaire + # NOTE: This collection has a lot of games with the same name as + # established games but completely different rules, or more obscure + # variations with more generic names. As such rules/names may + # conflict with other attempts to add games in the future, games + # from XM Solitaire should be researched before being added to PySol. + # # still missing: # Ace of Hearts, Affinity, Agnes Three, Antares, Archway, # Avenue, Baker's Fan, Baker's Spider, Bedeviled, Binding, @@ -353,7 +359,7 @@ class GI: # La Cabane, La Double Entente, Little Gazette, Magic FreeCell, # Mini Gaps, Montreal, Napoleon at Iena, Napoleon at Waterloo, # Napoleon's Guards, Nationale, Oasis, Opera, Ordered Suits, - # Osmotic FreeCell, Pair FreeCell, Pairs 2, Petal, Rainbow Fan, + # Osmotic FreeCell, Pair FreeCell, Pairs 2, Petal, # Reserved Thirteens, Sea Spider, Sept Piles 0, Short Solitaire, # Simple Alternations, Simple Spark, Step By Step, Strategy 7, # Stripped FreeCell, Tarantula, Triple Dispute, Trusty Twenty, @@ -368,7 +374,7 @@ class GI: 363, 364, 372, 376, 383, 384, 385, 386, 390, 391, 393, 398, 405, 415, 416, 425, 451, 453, 461, 464, 466, 467, 476, 480, 484, 511, 512, 516, 561, 610, 625, 629, 631, 638, 641, 647, - 650, 655, 678, 734, 751, 784, 825, 829, 901, + 650, 655, 678, 734, 751, 784, 825, 829, 834, 901, )), # xpat2 1.06 (we have 14 out of 16 games) @@ -479,7 +485,7 @@ class GI: ('fc-2.12', tuple(range(774, 811)) + (16681,) + tuple(range(22217, 22219))), ('fc-2.14', tuple(range(811, 827))), - ('fc-2.16', tuple(range(827, 834))) + ('fc-2.16', tuple(range(827, 835))) ) # deprecated - the correct way is to or a GI.GT_XXX flag diff --git a/pysollib/games/fan.py b/pysollib/games/fan.py index afc0aa7c..4416a8be 100644 --- a/pysollib/games/fan.py +++ b/pysollib/games/fan.py @@ -699,6 +699,7 @@ class FascinationFan(Fan): # ************************************************************************ # * Crescent +# * Rainbow Fan # ************************************************************************ class Crescent_Talon(RedealTalonStack): @@ -715,12 +716,12 @@ class Crescent_Talon(RedealTalonStack): ncards += len(r.cards) # move cards to internal stacks while len(r.cards) != 1: - self.game.moveMove(1, r, intern1, frames=4) - self.game.moveMove(1, r, intern2, frames=4) + self.game.moveMove(1, r, intern1, frames=2) + self.game.moveMove(1, r, intern2, frames=2) # move back while intern1.cards: - self.game.moveMove(1, intern1, r, frames=4) - self.game.moveMove(1, intern2, r, frames=4) + self.game.moveMove(1, intern1, r, frames=2) + self.game.moveMove(1, intern2, r, frames=2) self.game.nextRoundMove(self) if sound: self.game.stopSamples() @@ -731,14 +732,23 @@ class Crescent_Talon(RedealTalonStack): class Crescent(Game): Hint_Class = CautiousDefaultHint + ROWS = 4 + COLS = 4 + INIT_CARDS = 6 + + SHOW_TALON_COUNT = False + def createGame(self): l, s = Layout(self), self.s playcards = 10 - w0 = l.XS+(playcards-1)*l.XOFFSET - w, h = l.XM+max(4*w0, 9*l.XS), l.YM + 5 * l.YS + l.TEXT_HEIGHT + w0 = l.XS + (playcards - 1) * l.XOFFSET + w, h = l.XM + max(self.COLS * w0, 9 * l.XS), \ + l.YM + (self.ROWS + 1) * l.YS + l.TEXT_HEIGHT self.setSize(w, h) x, y = l.XM, l.YM s.talon = Crescent_Talon(x, y, self, max_rounds=4) + if self.SHOW_TALON_COUNT: + l.createText(s.talon, 'ne') l.createRoundText(s.talon, 's') x, y = w-8*l.XS, l.YM for i in range(4): @@ -749,9 +759,9 @@ class Crescent(Game): base_rank=KING, dir=-1)) x += l.XS y = l.YM + l.YS + l.TEXT_HEIGHT - for i in range(4): + for i in range(self.ROWS): x = l.XM - for j in range(4): + for j in range(self.COLS): stack = UD_SS_RowStack(x, y, self, base_rank=NO_RANK, mod=13) s.rows.append(stack) stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0 @@ -770,11 +780,27 @@ class Crescent(Game): def startGame(self): self.s.talon.dealRow(rows=self.s.foundations, frames=0) - self._startDealNumRowsAndDealSingleRow(5) + self._startDealNumRowsAndDealSingleRow(self.INIT_CARDS - 1) shallHighlightMatch = Game._shallHighlightMatch_SSW +class RainbowFan(Crescent): + ROWS = 4 + COLS = 5 + INIT_CARDS = 3 + SHOW_TALON_COUNT = True + + def fillStack(self, stack): + if stack in self.s.rows and len(stack.cards) == 0 \ + and len(self.s.talon.cards) > 0: + old_state = self.enterState(self.S_FILL) + for i in range(3): + self.s.talon.flipMove(1) + self.s.talon.moveMove(1, stack) + self.leaveState(old_state) + + # ************************************************************************ # * School # ************************************************************************ @@ -1069,3 +1095,5 @@ registerGame(GameInfo(767, QuadsPlus, "Quads +", GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(819, BearRiver, "Bear River", GI.GT_FAN_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(834, RainbowFan, "Rainbow Fan", + GI.GT_FAN_TYPE, 2, 3, GI.SL_MOSTLY_SKILL))