Game Over False Positive #2

Closed
opened 2026-05-05 17:59:49 +00:00 by Quaternions · 1 comment

This game showed the game over screen:

image.png

but stack 4 (6 of hearts) can be moved onto stack 2 (7 of spades) like so:

image.png
This game showed the game over screen: <img width="960" alt="image.png" src="attachments/e3415796-0c80-4e05-8b88-a47fa2f00a48"> but stack 4 (6 of hearts) can be moved onto stack 2 (7 of spades) like so: <img width="960" alt="image.png" src="attachments/92456bdf-be9d-478a-a8a8-30198ebbea00">
547 KiB
637 KiB
Owner

Fix Applied ✓

This response was written by Claude AI (claude-sonnet-4-6) on behalf of funman300.

Root cause: has_legal_moves() in game_plugin.rs only checked t.cards.last() — the top face-up card — of each tableau column as a potential move source. In Klondike any face-up card can anchor a movable run, so mid-column cards were invisible to the check. A position where the only legal move was a non-top face-up card would incorrectly be declared a softlock and trigger the game-over screen.

Two secondary issues were also present:

  • Stock cards (face-down) were included in the source set. Since can_place_on_foundation does not gate on face_up, this could produce false positives for unplayable cards.
  • All waste cards were included as sources; only the top waste card is reachable by the player.

Fix (commit 33fb962):

  • Tableau loop now iterates t.cards.iter().filter(|c| c.face_up) — all face-up cards, not just the top one.
  • Stock is excluded from the source set entirely.
  • Waste is narrowed to its top card only.

A new regression test has_legal_moves_detects_non_top_face_up_card_as_source is added: it builds a board where a non-top Queen is the only card that can legally move (onto a King), and asserts has_legal_moves returns true. The existing softlock test (has_legal_moves_returns_false_when_stock_only_holds_unplayable_cards) continues to pass.

## Fix Applied ✓ > *This response was written by Claude AI (claude-sonnet-4-6) on behalf of funman300.* **Root cause:** `has_legal_moves()` in `game_plugin.rs` only checked `t.cards.last()` — the top face-up card — of each tableau column as a potential move source. In Klondike any face-up card can anchor a movable run, so mid-column cards were invisible to the check. A position where the only legal move was a non-top face-up card would incorrectly be declared a softlock and trigger the game-over screen. Two secondary issues were also present: - **Stock cards** (face-down) were included in the source set. Since `can_place_on_foundation` does not gate on `face_up`, this could produce false positives for unplayable cards. - **All waste cards** were included as sources; only the top waste card is reachable by the player. **Fix (commit `33fb962`):** - Tableau loop now iterates `t.cards.iter().filter(|c| c.face_up)` — all face-up cards, not just the top one. - Stock is excluded from the source set entirely. - Waste is narrowed to its top card only. A new regression test `has_legal_moves_detects_non_top_face_up_card_as_source` is added: it builds a board where a non-top Queen is the only card that can legally move (onto a King), and asserts `has_legal_moves` returns `true`. The existing softlock test (`has_legal_moves_returns_false_when_stock_only_holds_unplayable_cards`) continues to pass.
Sign in to join this conversation.
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/Ferrous-Solitaire#2