fabro(01KT9YT14FHDYA4VTV9DSFG0FY): impl_logic (succeeded)

Fabro-Run: 01KT9YT14FHDYA4VTV9DSFG0FY
Fabro-Completed: 9
Fabro-Checkpoint: 916c46b57a

⚒️ Generated with [Fabro](https://fabro.sh)
This commit is contained in:
Fabro 2026-06-04 18:53:21 +00:00
parent b287ce3a5f
commit 91953ef64d
2 changed files with 86 additions and 0 deletions

View file

@ -376,3 +376,51 @@ class GameState:
def check_win(self) -> bool:
"""Returns True if all 52 cards are in the Foundations."""
return all(len(self.foundations[suit]) == 13 for suit in Suit)
def check_loss(self) -> bool:
"""
Returns True if the game is lost (i.e. not won and no legal moves can be made).
"""
if self.check_win():
return False
# Check all possible moves from freecells
for i in range(4):
if self.freecells[i] is not None:
from_pos = Position(LocationType.FREECELL, i)
# To tableau
for j in range(8):
if self.validate_move(from_pos, Position(LocationType.TABLEAU, j), 1):
return False
# To other freecells
for j in range(4):
if i != j and self.validate_move(from_pos, Position(LocationType.FREECELL, j), 1):
return False
# To foundations
for j in range(4):
if self.validate_move(from_pos, Position(LocationType.FOUNDATION, j), 1):
return False
# Check all possible moves from tableaus
for i in range(8):
col_len = len(self.tableaus[i])
if col_len > 0:
from_pos = Position(LocationType.TABLEAU, i)
# Check different move counts
for count in range(1, col_len + 1):
# To other tableaus
for j in range(8):
if i != j and self.validate_move(from_pos, Position(LocationType.TABLEAU, j), count):
return False
# To freecells
if count == 1:
for j in range(4):
if self.validate_move(from_pos, Position(LocationType.FREECELL, j), 1):
return False
# To foundations
if count == 1:
for j in range(4):
if self.validate_move(from_pos, Position(LocationType.FOUNDATION, j), 1):
return False
return True

View file

@ -347,3 +347,41 @@ def test_win_detection():
# Remove one card
state.foundations[Suit.HEARTS].pop()
assert state.check_win() is False
def test_check_loss_not_lost():
# A standard freshly-dealt game should not be in a loss state (usually has legal moves)
state = GameState()
assert state.check_loss() is False
def test_check_loss_won():
# A won game is not lost
state = GameState()
for suit in Suit:
state.foundations[suit] = [Card(suit, rank) for rank in Rank]
assert state.check_loss() is False
def test_check_loss_is_lost():
state = GameState()
# Clear tableaus and freecells, and foundations
state.freecells = [None] * 4
state.tableaus = [[] for _ in range(8)]
state.foundations = {suit: [] for suit in Suit}
# Lock everything:
# Fill all 4 freecells with Kings of Diamonds
state.freecells = [Card(Suit.DIAMONDS, Rank.KING)] * 4
# Fill all 8 tableaus with at least one King of Diamonds
for i in range(8):
state.tableaus[i] = [Card(Suit.DIAMONDS, Rank.KING)]
# Now there are:
# - No empty tableaus
# - No empty freecells
# - No Aces on top of tableaus or in freecells (all are Kings of Diamonds)
# So:
# - Cannot move to freecells (all occupied)
# - Cannot move to foundations (only Kings, no Aces)
# - Cannot move to tableaus (all top cards are King of Diamonds, can't build King on King, and no empty columns)
# This state should be a lost/locked state!
assert state.check_loss() is True