diff --git a/pysollib/games/grandfathersclock.py b/pysollib/games/grandfathersclock.py index 01296434..187fa3bf 100644 --- a/pysollib/games/grandfathersclock.py +++ b/pysollib/games/grandfathersclock.py @@ -181,10 +181,182 @@ class Dial(Game): self.s.talon.dealCards() # deal first card to WasteStack +# /*********************************************************************** +# // Hemispheres +# ************************************************************************/ + +BLACK, RED = 0, 1 + +class Hemispheres_RowStack(SC_RowStack): + + def _canSwapPair(self, from_stack): + if from_stack not in self.game.s.rows[4:]: + return False + if len(self.cards) != 1 or len(from_stack.cards) != 1: + return False + if self in self.game.s.rows[4:10]: + alt_rows = self.game.s.rows[10:] + color = RED + else: + alt_rows = self.game.s.rows[4:10] + color = BLACK + if from_stack not in alt_rows: + return False + c0, c1 = from_stack.cards[0], self.cards[0] + return c0.color == color and c1.color != color + + def acceptsCards(self, from_stack, cards): + if self._canSwapPair(from_stack): + return True + if not SC_RowStack.acceptsCards(self, from_stack, cards): + return False + if self in self.game.s.rows[4:10]: + if cards[0].color == BLACK: + return False + return (from_stack in self.game.s.rows[4:10] or + from_stack is self.game.s.waste) + if self in self.game.s.rows[10:]: + if cards[0].color == RED: + return False + return (from_stack in self.game.s.rows[10:] or + from_stack is self.game.s.waste) + return False + + def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): + if self._canSwapPair(to_stack): + self._swapPairMove(ncards, to_stack, frames=-1, shadow=0) + else: + SC_RowStack.moveMove(self, ncards, to_stack, + frames=frames, shadow=shadow) + + def _swapPairMove(self, n, other_stack, frames=-1, shadow=-1): + game = self.game + old_state = game.enterState(game.S_FILL) + swap = game.s.internals[0] + game.moveMove(n, self, swap, frames=0) + game.moveMove(n, other_stack, self, frames=frames, shadow=shadow) + game.moveMove(n, swap, other_stack, frames=0) + game.leaveState(old_state) + + +class Hemispheres(Game): + Hint_Class = CautiousDefaultHint + + def createGame(self): + + l, s = Layout(self), self.s + self.setSize(l.XM+9.5*l.XS, l.YM+5*l.YS) + + # internal stack (for swap) + s.internals.append(InvisibleStack(self)) + + x0, y0 = l.XM+1.5*l.XS, l.YM + # barriers + for xx, yy in ((0, 2), + (7, 2), + (3.5, 0), + (3.5, 4), + ): + x, y = x0+xx*l.XS, y0+yy*l.YS + s.rows.append(BasicRowStack(x, y, self, max_accept=0)) + + # northern hemisphere (red) + for xx, yy in ((0.5, 1), + (1.5, 0.5), + (2.5, 0.3), + (4.5, 0.3), + (5.5, 0.5), + (6.5, 1), + ): + x, y = x0+xx*l.XS, y0+yy*l.YS + stack = Hemispheres_RowStack(x, y, self, + base_color=RED, max_move=1) + stack.CARD_YOFFSET = 0 + s.rows.append(stack) + + # southern hemisphere (black) + for xx, yy in ((6.5, 3), + (5.5, 3.5), + (4.5, 3.8), + (2.5, 3.8), + (1.5, 3.5), + (0.5, 3), + ): + x, y = x0+xx*l.XS, y0+yy*l.YS + stack = Hemispheres_RowStack(x, y, self, + base_color=BLACK, max_move=1, dir=1) + stack.CARD_YOFFSET = 0 + s.rows.append(stack) + + # foundations + x, y = x0+2*l.XS, y0+1.5*l.YS + for i in range(4): + s.foundations.append(SS_FoundationStack(x, y, self, suit=2+i/2, + max_move=0)) + x += l.XS + x, y = x0+2*l.XS, y+l.YS + for i in range(4): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i/2, + max_move=0, base_rank=KING, dir=-1)) + x += l.XS + + # talon & waste + x, y = l.XM, l.YM + s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 'ne') + y += l.YS + s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'ne') + + l.defaultStackGroups() + + + def _shuffleHook(self, cards): + founds_cards = [] # foundations + rows_cards = [] # rows + for c in cards[:]: + if c.rank in (ACE, KING): + if ((c.rank == ACE and c.color == RED) or + (c.rank == KING and c.color == BLACK)): + cards.remove(c) + founds_cards.append(c) + elif c.deck == 0: + cards.remove(c) + rows_cards.append(c) + founds_cards.sort(lambda a, b: cmp((-a.rank, -a.suit), (-b.rank, -b.suit))) + rows_cards.sort(lambda a, b: cmp((a.rank, a.suit), (b.rank, b.suit))) + return cards+rows_cards+founds_cards + + + def startGame(self): + self.s.talon.dealRow(rows=self.s.foundations, frames=0) + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() # deal first card to WasteStack + + + def fillStack(self, stack): + if stack in self.s.rows[4:] and not stack.cards: + old_state = self.enterState(self.S_FILL) + if not self.s.waste.cards: + self.s.talon.dealCards() + if self.s.waste.cards: + self.s.waste.moveMove(1, stack) + self.leaveState(old_state) + + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + # by color + return card1.color == card2.color and abs(card1.rank-card2.rank) == 1 + + # register the game registerGame(GameInfo(261, GrandfathersClock, "Grandfather's Clock", GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED)) registerGame(GameInfo(682, Dial, "Dial", GI.GT_1DECK_TYPE, 1, 1, GI.SL_LUCK)) +registerGame(GameInfo(690, Hemispheres, "Hemispheres", + GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED, + altnames=("The Four Continents",) )) diff --git a/pysollib/games/harp.py b/pysollib/games/harp.py index cc0b8384..fd94adfd 100644 --- a/pysollib/games/harp.py +++ b/pysollib/games/harp.py @@ -320,7 +320,7 @@ class ThievesOfEgypt(DoubleKlondike): class Brush(DoubleKlondike): Layout_Method = Layout.klondikeLayout Foundation_Class = Spider_SS_Foundation - RowStack_Class = Spider_SS_RowStack + RowStack_Class = Spider_RowStack Hint_Class = Spider_Hint def createGame(self): diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py index d59da55e..f646cac0 100644 --- a/pysollib/games/sultan.py +++ b/pysollib/games/sultan.py @@ -959,6 +959,55 @@ class Toni(Game): self.s.talon.dealRow() +# /*********************************************************************** +# // Khedive +# ************************************************************************/ + +class Khedive(Game): + + def createGame(self): + + l, s = Layout(self), self.s + self.setSize(l.XM+10*l.XS, l.YM+5*l.YS) + + x, y = l.XM, l.YM + for i in range(4): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i)) + s.foundations.append(SS_FoundationStack(x+6*l.XS, y, self, suit=i)) + x += l.XS + + x, y = l.XM+4*l.XS, l.YM + r = range(11) + for i in range(5,0,-1): + for j in r[i:-i]: + x, y = l.XM+(j-0.5)*l.XS, l.YM+(5-i)*l.YS + s.rows.append(BasicRowStack(x, y, self, max_accept=0)) + + + x, y = l.XM, l.YM+1.5*l.YS + s.talon = WasteTalonStack(x, y, self, max_rounds=1) + l.createText(s.talon, 'ne') + y += l.YS + s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'ne') + + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + self.s.talon.dealCards() + + def fillStack(self, stack): + if stack in self.s.rows and not stack.cards: + old_state = self.enterState(self.S_FILL) + if not self.s.waste.cards: + self.s.talon.dealCards() + if self.s.waste.cards: + self.s.waste.moveMove(1, stack) + self.leaveState(old_state) + + # register the game registerGame(GameInfo(330, Sultan, "Sultan", @@ -999,3 +1048,5 @@ registerGame(GameInfo(646, Adela, "Adela", GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(660, Toni, "Toni", GI.GT_2DECK_TYPE, 2, 2, GI.SL_MOSTLY_LUCK)) +registerGame(GameInfo(691, Khedive, "Khedive", + GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK))