From 1b7c4d92aa0a3443e761e0ea6701823ed1983998 Mon Sep 17 00:00:00 2001 From: funman300 Date: Wed, 13 May 2026 21:30:42 -0700 Subject: [PATCH] fix(web): auto-complete now works with cards remaining in waste MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check_auto_complete no longer requires the waste pile to be empty — only the stock must be exhausted and all tableau cards face-up. next_auto_complete_move checks the waste top card before scanning tableau, and auto_complete_step falls back to draw() when no direct foundation move is available so the waste drains automatically. Fixes the end-game state where the player could see a clear win but the auto-complete interval never fired because the waste was non-empty. Co-Authored-By: Claude Sonnet 4.6 --- solitaire_core/src/game_state.rs | 84 ++++++++++-------- solitaire_server/web/pkg/solitaire_wasm.js | 7 +- .../web/pkg/solitaire_wasm_bg.wasm | Bin 195136 -> 195524 bytes solitaire_wasm/src/lib.rs | 19 ++-- 4 files changed, 65 insertions(+), 45 deletions(-) diff --git a/solitaire_core/src/game_state.rs b/solitaire_core/src/game_state.rs index 3d1aa0e..341a52a 100644 --- a/solitaire_core/src/game_state.rs +++ b/solitaire_core/src/game_state.rs @@ -426,12 +426,11 @@ impl GameState { /// Returns `true` when stock and waste are empty and all tableau cards are face-up. /// At that point the game can be completed without further player input. pub fn check_auto_complete(&self) -> bool { + // Stock must be empty; waste may still have cards (they are resolved + // by draw() calls inside next_auto_complete_move / auto_complete_step). if !self.piles[&PileType::Stock].cards.is_empty() { return false; } - if !self.piles[&PileType::Waste].cards.is_empty() { - return false; - } (0..7).all(|i| { self.piles[&PileType::Tableau(i)] .cards @@ -459,42 +458,53 @@ impl GameState { if !self.is_auto_completable || self.is_won { return None; } + // Check waste top first — when stock is exhausted the waste may still + // contain cards that can go directly to a foundation. + let waste = PileType::Waste; + if let Some((card, slot)) = self.piles[&waste].cards.last() + .and_then(|c| self.foundation_slot_for(c).map(|s| (c, s))) + { + let _ = card; // borrow ends here + return Some((waste, PileType::Foundation(slot))); + } for i in 0..7 { let tableau = PileType::Tableau(i); - if let Some(card) = self.piles[&tableau].cards.last() { - // Prefer the slot that already claims this card's suit so - // Aces don't sometimes land in slot 0 and then leave the - // matching suit-claimed slot empty. - let mut candidate: Option = None; - let mut empty_slot: Option = None; - for slot in 0..4_u8 { - let foundation = PileType::Foundation(slot); - let pile = &self.piles[&foundation]; - if pile.cards.is_empty() { - if empty_slot.is_none() { - empty_slot = Some(slot); - } - } else if pile.claimed_suit() == Some(card.suit) { - candidate = Some(slot); - break; - } - } - let target_slot = candidate.or_else(|| { - // Only fall back to an empty slot if the card is an Ace, - // which is the only rank that can claim an empty slot. - if card.rank.value() == 1 { empty_slot } else { None } - }); - if let Some(slot) = target_slot { - let foundation = PileType::Foundation(slot); - if can_place_on_foundation(card, &self.piles[&foundation]) { - return Some((tableau, foundation)); - } - } + if let Some(slot) = self.piles[&tableau].cards.last() + .and_then(|c| self.foundation_slot_for(c)) + { + return Some((tableau, PileType::Foundation(slot))); } } None } + /// Return the foundation slot index that `card` can legally move to, or + /// `None` if no such slot exists. + /// + /// Prefers the slot already claiming this card's suit so Aces always land + /// in a consistent column. Falls back to an empty slot only for Aces. + fn foundation_slot_for(&self, card: &crate::card::Card) -> Option { + let mut candidate: Option = None; + let mut empty_slot: Option = None; + for slot in 0..4_u8 { + let pile = &self.piles[&PileType::Foundation(slot)]; + if pile.cards.is_empty() { + if empty_slot.is_none() { + empty_slot = Some(slot); + } + } else if pile.claimed_suit() == Some(card.suit) { + candidate = Some(slot); + break; + } + } + let target = candidate.or_else(|| { + if card.rank.value() == 1 { empty_slot } else { None } + }); + target.filter(|&slot| { + can_place_on_foundation(card, &self.piles[&PileType::Foundation(slot)]) + }) + } + /// Time bonus added to score on win: `700_000 / elapsed_seconds` (0 if elapsed is 0). pub fn compute_time_bonus(&self) -> i32 { scoring_time_bonus(self.elapsed_seconds) @@ -1022,24 +1032,24 @@ mod tests { } #[test] - fn auto_complete_false_when_waste_not_empty() { + fn auto_complete_true_when_stock_empty_waste_has_cards() { + // Waste no longer blocks auto-complete — draw() drains it during + // auto-complete steps. Only stock-not-empty and face-down tableau + // cards block the flag. let mut g = new_game(); g.piles.get_mut(&PileType::Stock).unwrap().cards.clear(); - // Leave the waste pile untouched (it may be empty after clearing stock, - // so add a card explicitly to ensure the waste guard is exercised). g.piles.get_mut(&PileType::Waste).unwrap().cards.push(Card { id: 99, suit: Suit::Clubs, rank: Rank::Ace, face_up: true, }); - // Make all tableau cards face-up so only the waste guard is the blocker. for i in 0..7 { for c in g.piles.get_mut(&PileType::Tableau(i)).unwrap().cards.iter_mut() { c.face_up = true; } } - assert!(!g.check_auto_complete()); + assert!(g.check_auto_complete()); } #[test] diff --git a/solitaire_server/web/pkg/solitaire_wasm.js b/solitaire_server/web/pkg/solitaire_wasm.js index cbf30e5..a6fe4e9 100644 --- a/solitaire_server/web/pkg/solitaire_wasm.js +++ b/solitaire_server/web/pkg/solitaire_wasm.js @@ -1,3 +1,5 @@ +/* @ts-self-types="./solitaire_wasm.d.ts" */ + /** * Browser-side replay state machine. Owns a live `GameState` and the * replay's move list; each `step()` applies the next move. @@ -92,7 +94,10 @@ export class SolitaireGame { } /** * Apply one auto-complete move (only valid when `is_auto_completable`). - * Returns the post-move snapshot or `null` when auto-complete is unavailable. + * + * If no card can go directly to a foundation this step, advances the + * waste by calling `draw()` so the next step can try again. Returns the + * post-move snapshot, or `null` when no progress is possible. * @returns {any} */ auto_complete_step() { diff --git a/solitaire_server/web/pkg/solitaire_wasm_bg.wasm b/solitaire_server/web/pkg/solitaire_wasm_bg.wasm index 4a4ace66abfccdffd45c20edd83c709aacf734b0..771d9d3efd4cf737ad257d89f85d97bddea577d8 100644 GIT binary patch delta 20961 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 JsValue { if !self.game.is_auto_completable { return JsValue::NULL; } - match self.game.next_auto_complete_move() { - Some((from, to)) => { - let _ = self.game.move_cards(from, to, 1); - self.ok_js() - } - None => JsValue::NULL, + if let Some((from, to)) = self.game.next_auto_complete_move() { + let _ = self.game.move_cards(from, to, 1); + return self.ok_js(); + } + // No direct foundation move — advance through the waste. + match self.game.draw() { + Ok(()) => self.ok_js(), + Err(_) => JsValue::NULL, } } }