""" generic_cards.py An example of objects for card games. Running it might look like this : $ python generic_cards.py The deck is Dealt the top card which is king of spades. The deck is now : Adding four cards to a hand ... The hand is now TODO: add doctests. TODO: add better __str__ methods. Jim Mahoney | cs.bennington.college | Oct 2020 | MIT License """ import random class Card: """ A playing card. """ # Note: This is class data, which you refer to later as e.g. Card.suits suits = ('clubs', 'diamonds', 'hearts', 'spades') ranks = ('ace', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'jack', 'queen', 'king') def __init__(self, rank=None, suit=None): # TODO : fill in a random value if one isn't supplied or is illegal self.rank = rank self.suit = suit def __str__(self): """ A card as a string, e.g. 'two of hearts' """ return "{} of {}".format(self.rank, self.suit) def __repr__(self): """ A card as displayed at the interactive prompt, e.g. "Card(rank='two', suit='spades') """ return "Card(rank='{}', suit='{}')".format(self.rank, self.suit) def value(self): """ Return value of this card """ # TODO : change this to match some specific game, # or override in a child class like BlackJackCard return 1 class Hand: """ some cards """ def __init__(self): self.cards = [] def value(self): """ Return the value of this hand """ # Here the value is just the sum of the card values. result = 0 for card in self.cards: result = result + card.value() return result def __str__(self): result = "" def add(self, card): """ add a card to this hand """ self.cards.append(card) class Deck: """ A deck of cards. """ def __init__(self): # TODO: add option to shuffle deck during initialization. # TODO: add in option to include jokers?? self.cards = [] for suit in Card.suits: for rank in Card.ranks: card = Card(rank, suit) self.cards.append(card) def __str__(self): return "".format(len(self.cards)) def shuffle(self): random.shuffle(self.cards) def add(self, card): """ add a card onto the top of the deck """ # Here the 'top' is the right end of the list, # in other words the highest index. self.cards.append(card) def deal(self, random=False): """ remove one card from the top of the deck (or from a random place in the deck) and return it. """ if random: index = random.randrange(len(self.cards)) else: index = -1 # i.e. the last, top card card = self.cards.pop(index) # If you haven't seen .pop() before for a list, # check out https://docs.python.org/3.8/tutorial/datastructures.html return card # TODO : add a deal_hand method that removes some # number of cards and returns a Hand object. class Game: """ Would you like to play a game? """ # TODO : expand this into a more typical card game. def __init__(self): self.deck = Deck() self.deck.shuffle() def play(self): print("The deck is {}".format(self.deck)) top_card = self.deck.deal() print("Dealt the top card which is {}.".format(top_card)) print("The deck is now : {}".format(self.deck)) print("Adding four cards to a hand ...") # TODO : make this next part into a method somewhere ... hand = Hand() for i in range(3): card = self.deck.deal() # Deal one card from the deck ... hand.add(card) # and put it into the hand. print("The hand is now") print(hand) # TODO : should we save this hand somewhere? # Let 'er rip : Game().play() ## ## (Quick quiz: why are there two empty parens in that last line?) ##