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
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-09 19:37 +0000
1from __future__ import annotations
3import random
4from dataclasses import dataclass, field
6from beaverbunch.core.card import Card, Suit
9@dataclass
10class Deck:
11 """Represents a deck of playing cards, which can be shuffled and drawn from.
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)
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)
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)
35 def shuffle(self) -> Deck:
36 """Shuffles the deck in place and returns self for chaining."""
37 random.shuffle(self.cards)
38 return self
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()
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)]
52 def __len__(self) -> int:
53 """Returns the number of cards left in the deck."""
54 return len(self.cards)