""" blackjack.py Implement a blackjack game with objects Card and Deck, from Zelle exercise 11 from chapter 10 and exercise 15 from chapter 11 A homework assignment for the Intro CS course. Based on Jim's card.py and deck.py at cs.bennington.college/courses/spring2021/introcs/code/objects/deck.py Jim Mahoney | cs.bennington.college | May 2021 | MIT License """ import random suits = ('c', 'd', 'h', 's') ranks = tuple(range(1, 14)) # (1, 2, 3, ...., 11, 12, 13) suitnames = {'c': 'Clubs', 'd': 'Diamonds', 'h': 'Hearts', 's': 'Spades'} ranknames = (None, 'Ace', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King') class Card: """ A playing card """ def __init__(self, rank=None, suit=None): if rank == None: rank = random.choice(ranks) if suit == None: suit = random.choice(suits) self.rank = rank self.suit = suit def __str__(self): return f"{ranknames[self.rank]} of {suitnames[self.suit]}" def blackjack_value(self): """ Return blackjack card value, i.e. 10 for Jack,Queen,King """ # An ace can be 1 or 11. But here we just treat it as 1, # and consider the 11 choice in class Hand, since it depends # on the other cards in the hand. if self.rank >= 10: return 10 else: return self.rank class Deck: """ A deck of 52 cards """ def __init__(self): self.cards = [] for suit in suits: for rank in ranks: self.cards.append(Card(rank, suit)) def deal_card(self): """ Return and remove the top card """ return self.cards.pop() def shuffle(self): """ shuffle cards in place """ random.shuffle(self.cards) def cards_left(self): """ Return number of cards remaining """ return len(self.cards) class Hand: """ A hand of BlackJack cards """ def __init__(self): self.cards = [] def __str__(self): card_strings = [] for card in self.cards: card_strings.append(str(card)) return ', '.join(card_strings) + ' : ' + str(self.value()) def hit_me(self, deck): """ Deal a card from the deck into this hand. """ self.cards.append(deck.deal_card()) def value(self): """ Return the blackjack value of this hand. """ # Note that an ace can be either 1 or 11. total = 0 # First add up all the values, treating the aces as 1. for card in self.cards: total = total + card.blackjack_value() # Now for each ace, add 10 to the score if that doesn't go over 21. for card in self.cards: if card.rank == 1: # Ace ? if total + 10 <= 21: # Can this ace be 11 without busting? total = total + 10 # Then make it so. return total def is_bust(self): """ Return True if the hand is over 21 """ return self.value() > 21 def is_blackjack(self): """ Return True if the had is exactly 21 """ return self.value() == 21 class Dealer(Hand): def another_card(self): """ Return True if the dealer wants a card. """ # Casino rules are that the dealer takes cards # until the hand is more than 17. return self.value() < 17 class Player(Hand): def another_card(self): """ Ask if the user wants a card; return True or False """ choice = input("Do you want another card? (yes or no) ") return choice.lower()[0] == 'y' class Game: """ A simplistic game of BlackJack with a dealer and player """ # No splits, no betting - just the basics. def __init__(self): self.deck = Deck() self.deck.shuffle() self.player = Player() self.dealer = Dealer() def play(self): print("** Blackjack **") # deal two cards to the player. self.player.hit_me(self.deck) self.player.hit_me(self.deck) # continue to deal cards to the player # until they win, lose, or don't want any more. while True: print("Your hand is ", str(self.player)) if self.player.is_bust(): print("Oops - busted. You lose.") return elif self.player.is_blackjack(): print("Blackjack - you win!") return elif self.player.another_card(): self.player.hit_me(self.deck) else: break # Now it's the dealer's turn. # Deal cards until they don't want anymore. while self.dealer.another_card(): self.dealer.hit_me(self.deck) # And see how it turned out. print("Dealer's hand is ", str(self.dealer)) if self.dealer.is_bust(): print("Dealer is over 21 ... you win.") elif self.player.value() > self.player.value(): print("Your hand is better than the dealer's : you win.") else: print("Your hand doesn't beat the dealer's : you lose.") def main(): Game().play() if __name__ == '__main__': main()