diff --git a/html-src/rules/nineacross.html b/html-src/rules/nineacross.html new file mode 100644 index 000000000..a8dca1ab9 --- /dev/null +++ b/html-src/rules/nineacross.html @@ -0,0 +1,16 @@ +

Nine Across

+

+Klondike type. 1 deck. Unlimited redeals. + +

Object

+

+Move all cards to the foundations. + +

Quick Description

+

+Like Klondike, +but with nine piles, and the base rank of the foundations +is chosen by the first card you play to one. Foundations +and tableau piles can turn the corner from king to ace as +necessary, and empty tableau piles can only be filled with +the rank one below the base foundation rank. diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py index 386334166..f12c7a13d 100644 --- a/pysollib/gamedb.py +++ b/pysollib/gamedb.py @@ -575,7 +575,7 @@ def _callback(gi, gt=game_type): ('fc-2.20', tuple(range(855, 897))), ('fc-2.21', tuple(range(897, 900)) + tuple(range(11014, 11017)) + tuple(range(13160, 13163)) + (16682,)), - ('dev', tuple(range(906, 913)) + tuple(range(11017, 11020)) + + ('dev', tuple(range(906, 914)) + tuple(range(11017, 11020)) + tuple(range(22303, 22311)) + tuple(range(22353, 22361))), ) diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py index 444478831..0f043b6b3 100644 --- a/pysollib/games/klondike.py +++ b/pysollib/games/klondike.py @@ -57,7 +57,7 @@ WasteStack, \ WasteTalonStack, \ isSameColorSequence -from pysollib.util import ACE, ANY_RANK, ANY_SUIT, KING, NO_RANK +from pysollib.util import ACE, ANY_RANK, ANY_SUIT, KING, NO_RANK, RANKS # ************************************************************************ # * Klondike @@ -168,6 +168,99 @@ class Trigon(Klondike): RowStack_Class = KingSS_RowStack +# ************************************************************************ +# * Nine Across +# ************************************************************************ + +class NineAcross_RowStack(AC_RowStack): + def __init__(self, x, y, game, **cap): + kwdefault(cap, mod=13) + AC_RowStack.__init__(self, x, y, game, **cap) + + def acceptsCards(self, from_stack, cards): + if not self.cards: + if self.game.base_rank == ANY_RANK: + return False + elif self.game.base_rank == ACE: + if cards[0].rank != KING: + return False + elif cards[0].rank != self.game.base_rank - 1: + return False + return AC_RowStack.acceptsCards(self, from_stack, cards) + + def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): + self.game.moveMove( + ncards, self, to_stack, frames=frames, shadow=shadow) + if to_stack in self.game.s.foundations and \ + self.game.base_rank == ANY_RANK: + old_state = self.game.enterState(self.game.S_FILL) + self.game.saveStateMove(2 | 16) # for undo + r = to_stack.cards[0].rank + for s in self.game.s.foundations: + s.cap.base_rank = r + self.game.base_rank = r + self.game.saveStateMove(1 | 16) # for redo + self.game.leaveState(old_state) + + +class NineAcross(Klondike): + Foundation_Class = StackWrapper(SS_FoundationStack, base_rank=ANY_RANK, + mod=13) + RowStack_Class = NineAcross_RowStack + + base_rank = ANY_RANK + + def createGame(self): + lay = Klondike.createGame(self, rows=9) + + tx, ty, ta, tf = lay.getTextAttr(self.s.foundations[0], "s") + + self.texts.info = \ + MfxCanvasText(self.canvas, tx, ty, anchor=ta, + font=self.app.getFont("canvas_default")) + + def startGame(self): + self.base_rank = ANY_RANK + for s in self.s.foundations: + s.cap.base_rank = ANY_RANK + self.updateText() + Klondike.startGame(self) + + def updateText(self): + if self.preview > 1: + return + if not self.texts.info: + return + if self.base_rank == ANY_RANK: + t = "" + else: + t = RANKS[self.base_rank] + self.texts.info.config(text=t) + + def _restoreGameHook(self, game): + self.base_rank = game.loadinfo.base_rank + for s in self.s.foundations: + s.cap.base_rank = self.base_rank + + def _loadGameHook(self, p): + self.loadinfo.addattr(base_rank=p.load()) + + def _saveGameHook(self, p): + base_rank = self.base_rank + p.dump(base_rank) + + def setState(self, state): + # restore saved vars (from undo/redo) + self.base_rank = state[0] + for s in self.s.foundations: + s.cap.base_rank = state[0] + break + + def getState(self): + # save vars (for undo/redo) + return [self.base_rank] + + # ************************************************************************ # * Thumb and Pouch # * Chinaman @@ -1685,3 +1778,5 @@ def startGame(self): GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(893, TakingSilk, "Taking Silk", GI.GT_KLONDIKE, 2, 0, GI.SL_BALANCED)) +registerGame(GameInfo(913, NineAcross, "Nine Across", + GI.GT_KLONDIKE, 1, -1, GI.SL_BALANCED))