class Card: def __init__(self, suit: str, rank: str) -> None: self.suit = suit self.rank = rank def __str__(self) -> str: return f"{self.rank} of {self.suit}" def __repr__(self) -> str: return f"Card(suit={self.suit}, rank={self.rank})" def __eq__(self, other): if not isinstance(other, Card): return NotImplemented return (self.suit, self.rank) == (other.suit, other.rank) class Deck: def __init__(self) -> None: self.cards = [] suits = ['Hearts', 'Diamonds', 'Clubs', 'Spades'] ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace'] for suit in suits: for rank in ranks: self.cards.append(Card(suit, rank)) def __str__(self) -> str: return ', '.join(str(card) for card in self.cards) def __repr__(self) -> str: return f"Deck(cards={self.cards})" def shuffle(self): import random random.shuffle(self.cards) def deal(self, num_cards: int) -> list[Card]: if num_cards > len(self.cards): raise ValueError("Not enough cards in the deck to deal.") dealt_cards = self.cards[:num_cards] self.cards = self.cards[num_cards:] return dealt_cards def remaining_cards(self) -> int: return len(self.cards) class Hand: def __init__(self, cards: list[Card]) -> None: self.cards = cards def __str__(self) -> str: return ', '.join(str(card) for card in self.cards) def __repr__(self) -> str: return f"Hand(cards={self.cards})" def add_card(self, card: Card): self.cards.append(card) def clear(self): self.cards.clear() # Example usage: if __name__ == "__main__": #print("Unshuffled deck of cards...") deck = Deck() #print(deck) deck.shuffle() #print("Shuffled deck:") #print(deck) dealt = deck.deal(5) player1_hand = Hand(dealt) print("Dealt cards:") for card in player1_hand.cards: print(card) print(f"Remaining cards in the deck: {deck.remaining_cards()}") player1_hand.add_card(Card('Hearts', 'Ace')) print("Player 1's hand after adding an Ace of Hearts:") for card in player1_hand.cards: print(card)