From 83a3307a23fef334e22af3210bd2bfac192881b2 Mon Sep 17 00:00:00 2001 From: Dominika Plewinska Date: Thu, 15 Jan 2026 05:18:55 +0100 Subject: [PATCH 1/3] Crispy: fix hint/demo stuck check for picture-card moves --- pysollib/games/montecarlo.py | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/pysollib/games/montecarlo.py b/pysollib/games/montecarlo.py index df5d3a3aa..f62ed2374 100644 --- a/pysollib/games/montecarlo.py +++ b/pysollib/games/montecarlo.py @@ -380,6 +380,65 @@ def isGameWon(self): # * Crispy # ************************************************************************ +class Crispy_Hint(MonteCarlo_Hint): + + def step010_movePile(self, r, pile, rows): + PICTURE_DESTS = { + KING: (1, 2, 13, 14), + QUEEN: (4, 7, 8, 11), + JACK: (0, 3, 12, 15), + } + lp = len(pile) + lr = len(r.cards) + assert 1 <= lp <= lr + rpile = r.cards[: (lr - lp)] + + empty_row_seen = 0 + r_is_waste = r in self.game.sg.talonstacks + + for t in rows: + score, color = 0, None + if not self.shallMovePile(r, t, pile, rpile): + continue + + if r_is_waste: + score, color = self._getMoveWasteScore(score, color, r, t, pile, rpile) + else: + if not t.cards: + # DefaultHint skips whole-stack-to-empty; Crispy needs it for picture cards. + if lp == lr: + rank = pile[-1].rank + if rank in (JACK, QUEEN, KING): + dest_ids = PICTURE_DESTS[rank] + + # Crispy_RowStack.acceptsCards already enforces correct destinations, + # but we double-check for safety: + if t.id not in dest_ids: + continue + + # NEW: don't shuffle picture cards between correct picture slots + # (it doesn't change free spaces, it's just noise). + if r.id in dest_ids: + continue + + score = 90000 + else: + continue + else: + continue + + if empty_row_seen: + continue + empty_row_seen = 1 + else: + score = 80000 + + score, color = self._getMovePileScore(score, color, r, t, pile, rpile) + + self.addHint(score, lp, r, t, color) + + + class Crispy_Talon(MonteCarlo_Talon): def canDealCards(self): @@ -409,6 +468,7 @@ def acceptsCards(self, from_stack, cards): class Crispy(SimpleCarlo): Talon_Class = Crispy_Talon RowStack_Class = Crispy_RowStack + Hint_Class = Crispy_Hint FILL_STACKS_AFTER_DROP = False FILL_STACKS_BEFORE_SHIFT = True From 2a5e1534584bfb842460ce8e50d07e12067ec2f6 Mon Sep 17 00:00:00 2001 From: Dominika Plewinska Date: Thu, 15 Jan 2026 06:15:29 +0100 Subject: [PATCH 2/3] fix formatting --- pysollib/games/montecarlo.py | 96 +++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/pysollib/games/montecarlo.py b/pysollib/games/montecarlo.py index f62ed2374..1b65f4899 100644 --- a/pysollib/games/montecarlo.py +++ b/pysollib/games/montecarlo.py @@ -380,14 +380,15 @@ def isGameWon(self): # * Crispy # ************************************************************************ -class Crispy_Hint(MonteCarlo_Hint): +PICTURE_DESTS = { + KING: (1, 2, 13, 14), + QUEEN: (4, 7, 8, 11), + JACK: (0, 3, 12, 15), +} + +class Crispy_Hint(MonteCarlo_Hint): def step010_movePile(self, r, pile, rows): - PICTURE_DESTS = { - KING: (1, 2, 13, 14), - QUEEN: (4, 7, 8, 11), - JACK: (0, 3, 12, 15), - } lp = len(pile) lr = len(r.cards) assert 1 <= lp <= lr @@ -402,45 +403,55 @@ def step010_movePile(self, r, pile, rows): continue if r_is_waste: - score, color = self._getMoveWasteScore(score, color, r, t, pile, rpile) + score, color = self._getMoveWasteScore( + score, + color, + r, + t, + pile, + rpile, + ) else: if not t.cards: - # DefaultHint skips whole-stack-to-empty; Crispy needs it for picture cards. - if lp == lr: - rank = pile[-1].rank - if rank in (JACK, QUEEN, KING): - dest_ids = PICTURE_DESTS[rank] - - # Crispy_RowStack.acceptsCards already enforces correct destinations, - # but we double-check for safety: - if t.id not in dest_ids: - continue - - # NEW: don't shuffle picture cards between correct picture slots - # (it doesn't change free spaces, it's just noise). - if r.id in dest_ids: - continue - - score = 90000 - else: - continue - else: + # Crispy needs whole-stack-to-empty moves for picture cards. + if lp != lr: + continue + + rank = pile[-1].rank + if rank not in (JACK, QUEEN, KING): + continue + + dest_ids = PICTURE_DESTS[rank] + + # Enforce designated destinations (Crispy_RowStack does too). + if t.id not in dest_ids: + continue + + # Avoid shuffling picture cards between already-correct slots. + if r.id in dest_ids: continue if empty_row_seen: continue + + score = 90000 empty_row_seen = 1 else: score = 80000 - score, color = self._getMovePileScore(score, color, r, t, pile, rpile) + score, color = self._getMovePileScore( + score, + color, + r, + t, + pile, + rpile, + ) self.addHint(score, lp, r, t, color) - class Crispy_Talon(MonteCarlo_Talon): - def canDealCards(self): if len(self.cards) == 0: return False @@ -448,18 +459,17 @@ def canDealCards(self): class Crispy_RowStack(MonteCarlo_RowStack): - getBottomImage = BasicRowStack._getReserveBottomImage def acceptsCards(self, from_stack, cards): cr = cards[0].rank if len(self.cards) == 0: if cr == KING: - return self.id in (1, 2, 13, 14) + return self.id in PICTURE_DESTS[KING] if cr == QUEEN: - return self.id in (4, 7, 8, 11) + return self.id in PICTURE_DESTS[QUEEN] if cr == JACK: - return self.id in (0, 3, 12, 15) + return self.id in PICTURE_DESTS[JACK] if cr in (JACK, QUEEN, KING): return False return MonteCarlo_RowStack.acceptsCards(self, from_stack, cards) @@ -477,16 +487,22 @@ def createGame(self): def isGameWon(self): for i in (1, 2, 13, 14): - if len(self.s.rows[i].cards) != 0 and \ - self.s.rows[i].cards[0].rank != KING: + if ( + len(self.s.rows[i].cards) != 0 + and self.s.rows[i].cards[0].rank != KING + ): return False for i in (4, 7, 8, 11): - if len(self.s.rows[i].cards) != 0 and \ - self.s.rows[i].cards[0].rank != QUEEN: + if ( + len(self.s.rows[i].cards) != 0 + and self.s.rows[i].cards[0].rank != QUEEN + ): return False for i in (0, 3, 12, 15): - if len(self.s.rows[i].cards) != 0 and \ - self.s.rows[i].cards[0].rank != JACK: + if ( + len(self.s.rows[i].cards) != 0 + and self.s.rows[i].cards[0].rank != JACK + ): return False for i in (5, 6, 9, 10): if len(self.s.rows[i].cards) != 0: From e05f58187024f4ab924244ca75dadab3b9891708 Mon Sep 17 00:00:00 2001 From: Dominika Plewinska Date: Thu, 15 Jan 2026 21:55:41 +0100 Subject: [PATCH 3/3] fix formatting --- pysollib/games/montecarlo.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pysollib/games/montecarlo.py b/pysollib/games/montecarlo.py index 1b65f4899..cc8ecd8a3 100644 --- a/pysollib/games/montecarlo.py +++ b/pysollib/games/montecarlo.py @@ -413,7 +413,6 @@ def step010_movePile(self, r, pile, rows): ) else: if not t.cards: - # Crispy needs whole-stack-to-empty moves for picture cards. if lp != lr: continue @@ -423,11 +422,9 @@ def step010_movePile(self, r, pile, rows): dest_ids = PICTURE_DESTS[rank] - # Enforce designated destinations (Crispy_RowStack does too). if t.id not in dest_ids: continue - # Avoid shuffling picture cards between already-correct slots. if r.id in dest_ids: continue