Coverage for src / beaverbunch / core / hand.py: 100.0%
27 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-05 20:45 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-05 20:45 +0000
1from dataclasses import dataclass, field
3from beaverbunch.core.card import Card
6@dataclass
7class CardSlot:
8 """Represents a slot in a player's hand that holds a card and tracks whether the card is known to the player.
10 Attributes:
11 card: The Card object in this slot.
12 known: Whether the card is known (face-up) to the player.
13 """
14 card: Card
15 known: bool = False
18@dataclass
19class Hand:
20 """Represents a player's hand of cards. Each card is stored in a CardSlot, which tracks whether the card is known to the player.
22 Attributes:
23 slots: A list of CardSlot objects representing the cards in the player's hand.
24 """
25 slots: list[CardSlot] = field(default_factory=list)
27 def _check_index(self, index: int) -> None:
28 """Checks if the given index is valid for the hand."""
29 if index < 0 or index >= len(self.slots):
30 raise IndexError(f"Card index {index} out of range (hand size: {len(self.slots)})") # pragma: no cover
32 def __getitem__(self, index: int) -> Card:
33 self._check_index(index)
34 return self.slots[index].card
36 def __iter__(self):
37 return (slot.card for slot in self.slots)
39 def __len__(self) -> int:
40 return len(self.slots)
42 def replace_card(self, index: int, new_card: Card) -> Card:
43 """Replaces the card at the specified index with a new card, and returns the old card."""
44 self._check_index(index)
45 old_card = self.slots[index].card
46 self.slots[index] = CardSlot(card=new_card, known=False)
47 return old_card
49 def add_card(self, card: Card) -> None:
50 """Adds a new card to the hand."""
51 self.slots.append(CardSlot(card=card))
53 def remove_card(self, index: int) -> Card:
54 """Removes and returns the card at the specified index from the hand."""
55 self._check_index(index)
56 return self.slots.pop(index).card