Skip to content

State

patiencepilot.state

Game state value objects.

StackCard dataclass

A card in a tableau stack with visibility metadata.

Source code in src/patiencepilot/state.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@dataclass(frozen=True, slots=True)
class StackCard:
    """A card in a tableau stack with visibility metadata."""

    card: Card
    face_up: bool

    @classmethod
    def visible(cls, card: Card) -> StackCard:
        """Return a face-up tableau card."""
        return cls(card=card, face_up=True)

    @classmethod
    def hidden(cls, card: Card) -> StackCard:
        """Return a face-down tableau card."""
        return cls(card=card, face_up=False)

    @property
    def known_card(self) -> Card:
        """Return the exact card identity."""
        return self.card

    @property
    def visible_card(self) -> Card | None:
        """Return the card when it is both known and face up."""
        if self.face_up:
            return self.card
        return None

known_card property

known_card: Card

Return the exact card identity.

visible_card property

visible_card: Card | None

Return the card when it is both known and face up.

visible classmethod

visible(card: Card) -> StackCard

Return a face-up tableau card.

Source code in src/patiencepilot/state.py
21
22
23
24
@classmethod
def visible(cls, card: Card) -> StackCard:
    """Return a face-up tableau card."""
    return cls(card=card, face_up=True)

hidden classmethod

hidden(card: Card) -> StackCard

Return a face-down tableau card.

Source code in src/patiencepilot/state.py
26
27
28
29
@classmethod
def hidden(cls, card: Card) -> StackCard:
    """Return a face-down tableau card."""
    return cls(card=card, face_up=False)

GameState dataclass

A complete immutable Solitaire game snapshot.

Source code in src/patiencepilot/state.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
@dataclass(frozen=True, slots=True)
class GameState:
    """A complete immutable Solitaire game snapshot."""

    foundations: tuple[tuple[Card, ...], ...]
    tableau: tuple[tuple[StackCard, ...], ...]
    stock: tuple[Card, ...]
    waste: tuple[Card, ...]
    variant: str = "klondike"
    draw_count: int = 1
    redeals_allowed: int | None = None
    redeals_used: int = 0

    @classmethod
    def empty(cls, *, variant: str = "klondike", draw_count: int = 1, redeals_allowed: int | None = None) -> GameState:
        """Return an empty state for constructing focused tests or fixtures."""
        return cls(
            foundations=empty_foundations(),
            tableau=empty_tableau(),
            stock=(),
            waste=(),
            variant=variant,
            draw_count=draw_count,
            redeals_allowed=redeals_allowed,
        )

    def foundation(self, suit: Suit) -> tuple[Card, ...]:
        """Return the foundation stack for ``suit``."""
        return self.foundations[SUIT_ORDER.index(suit)]

    @property
    def top_waste(self) -> Card | None:
        """Return the top waste card, if any."""
        if not self.waste:
            return None
        return self.waste[-1]

    def iter_known_cards(self) -> Iterator[Card]:
        """Yield every exact card identity present in the state."""
        for foundation in self.foundations:
            yield from foundation
        for column in self.tableau:
            for stack_card in column:
                yield stack_card.card
        yield from self.stock
        yield from self.waste

top_waste property

top_waste: Card | None

Return the top waste card, if any.

empty classmethod

empty(
    *,
    variant: str = "klondike",
    draw_count: int = 1,
    redeals_allowed: int | None = None,
) -> GameState

Return an empty state for constructing focused tests or fixtures.

Source code in src/patiencepilot/state.py
67
68
69
70
71
72
73
74
75
76
77
78
@classmethod
def empty(cls, *, variant: str = "klondike", draw_count: int = 1, redeals_allowed: int | None = None) -> GameState:
    """Return an empty state for constructing focused tests or fixtures."""
    return cls(
        foundations=empty_foundations(),
        tableau=empty_tableau(),
        stock=(),
        waste=(),
        variant=variant,
        draw_count=draw_count,
        redeals_allowed=redeals_allowed,
    )

foundation

foundation(suit: Suit) -> tuple[Card, ...]

Return the foundation stack for suit.

Source code in src/patiencepilot/state.py
80
81
82
def foundation(self, suit: Suit) -> tuple[Card, ...]:
    """Return the foundation stack for ``suit``."""
    return self.foundations[SUIT_ORDER.index(suit)]

iter_known_cards

iter_known_cards() -> Iterator[Card]

Yield every exact card identity present in the state.

Source code in src/patiencepilot/state.py
91
92
93
94
95
96
97
98
99
def iter_known_cards(self) -> Iterator[Card]:
    """Yield every exact card identity present in the state."""
    for foundation in self.foundations:
        yield from foundation
    for column in self.tableau:
        for stack_card in column:
            yield stack_card.card
    yield from self.stock
    yield from self.waste

empty_foundations

empty_foundations() -> tuple[tuple[Card, ...], ...]

Return empty foundation stacks in suit order.

Source code in src/patiencepilot/state.py
44
45
46
def empty_foundations() -> tuple[tuple[Card, ...], ...]:
    """Return empty foundation stacks in suit order."""
    return tuple(() for _ in SUIT_ORDER)

empty_tableau

empty_tableau() -> tuple[tuple[StackCard, ...], ...]

Return empty tableau columns.

Source code in src/patiencepilot/state.py
49
50
51
def empty_tableau() -> tuple[tuple[StackCard, ...], ...]:
    """Return empty tableau columns."""
    return tuple(() for _ in range(N_TABLEAU_COLUMNS))