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

1from dataclasses import dataclass, field 

2 

3from beaverbunch.core.card import Card 

4 

5 

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. 

9 

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 

16 

17 

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. 

21 

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) 

26 

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 

31 

32 def __getitem__(self, index: int) -> Card: 

33 self._check_index(index) 

34 return self.slots[index].card 

35 

36 def __iter__(self): 

37 return (slot.card for slot in self.slots) 

38 

39 def __len__(self) -> int: 

40 return len(self.slots) 

41 

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 

48 

49 def add_card(self, card: Card) -> None: 

50 """Adds a new card to the hand.""" 

51 self.slots.append(CardSlot(card=card)) 

52 

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