Coverage for src / beaverbunch / core / deck.py: 100.0%

29 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-09 19:37 +0000

1from __future__ import annotations 

2 

3import random 

4from dataclasses import dataclass, field 

5 

6from beaverbunch.core.card import Card, Suit 

7 

8 

9@dataclass 

10class Deck: 

11 """Represents a deck of playing cards, which can be shuffled and drawn from. 

12 

13 Attributes: 

14 cards: A list of Card objects currently in the deck. The top of the deck is the end of the list (cards[-1]). 

15 """ 

16 cards: list[Card] = field(default_factory=list) 

17 

18 @classmethod 

19 def create_new(cls, include_jokers: bool = True) -> Deck: 

20 """Creates a standard 52-card deck.""" 

21 cards = [ 

22 Card(suit=suit, value=value) 

23 for suit in Suit 

24 for value in range(1, 14) 

25 ] 

26 if include_jokers: 

27 cards += [Card(suit=None, value=0), Card(suit=None, value=0)] 

28 return cls(cards=cards) 

29 

30 @classmethod 

31 def create_custom(cls, cards: list[Card]) -> "Deck": 

32 """Creates a deck from a custom list of cards.""" 

33 return cls(cards=cards) 

34 

35 def shuffle(self) -> Deck: 

36 """Shuffles the deck in place and returns self for chaining.""" 

37 random.shuffle(self.cards) 

38 return self 

39 

40 def draw(self) -> Card: 

41 """Draws a card from the top of the deck. Raises an error if the deck is empty.""" 

42 if not self.cards: 

43 raise IndexError("Cannot draw from an empty deck") 

44 return self.cards.pop() 

45 

46 def draw_n(self, n: int) -> list[Card]: 

47 """Draws n cards from the top of the deck. Raises an error if there are not enough cards.""" 

48 if len(self.cards) < n: 

49 raise IndexError(f"Cannot draw {n} cards from a deck with only {len(self.cards)} cards") 

50 return [self.cards.pop() for _ in range(n)] 

51 

52 def __len__(self) -> int: 

53 """Returns the number of cards left in the deck.""" 

54 return len(self.cards)