Source code for pyscoundrel.models.deck

"""Deck implementation for PyScoundrel."""

import random
from typing import TYPE_CHECKING, List, Optional

from .card import Card

if TYPE_CHECKING:
    from ..dungeon import Dungeon


[docs] class Deck: """ The Dungeon deck for Scoundrel. Built from a dungeon configuration via card definitions. """ def __init__(self, dungeon: "Dungeon", shuffle: bool = True, seed: Optional[int] = None): """ Initialize a deck from a dungeon configuration. Args: dungeon: Dungeon card pool configuration shuffle: Whether to shuffle the deck on creation seed: Random seed for reproducible shuffling """ self._cards: List[Card] = [] self._seed = seed for card_def in dungeon.card_definitions: for _ in range(card_def.count): self._cards.append( Card.from_dungeon_card( card_id=card_def.id, name=card_def.name, card_type=card_def.card_type, value=card_def.value, ) ) if shuffle: self.shuffle()
[docs] def shuffle(self) -> None: """Shuffle the deck.""" if self._seed is not None: random.seed(self._seed) random.shuffle(self._cards)
[docs] def draw(self) -> Optional[Card]: """ Draw a card from the top of the deck. Returns: The drawn card, or None if deck is empty """ if not self._cards: return None return self._cards.pop(0)
[docs] def draw_multiple(self, count: int) -> List[Card]: """ Draw multiple cards from the deck. Args: count: Number of cards to draw Returns: List of drawn cards (may be fewer than requested if deck runs out) """ drawn = [] for _ in range(count): card = self.draw() if card is None: break drawn.append(card) return drawn
[docs] def add_to_bottom(self, cards: List[Card]) -> None: """ Add cards to the bottom of the deck (used when avoiding a room). Args: cards: Cards to add to bottom of deck """ self._cards.extend(cards)
[docs] def peek(self, count: int = 1) -> List[Card]: """ Peek at the top cards without drawing them. Args: count: Number of cards to peek at Returns: List of cards at the top of the deck """ return self._cards[:count].copy()
@property def remaining(self) -> int: """Get the number of cards remaining in the deck.""" return len(self._cards) @property def is_empty(self) -> bool: """Check if the deck is empty.""" return len(self._cards) == 0 @property def cards(self) -> List[Card]: """Get a copy of all remaining cards in the deck.""" return self._cards.copy() def __len__(self) -> int: return len(self._cards) def __str__(self) -> str: return f"{self.remaining} cards remaining" def __repr__(self) -> str: return f"Deck(remaining={self.remaining})"