""" blackjack.py An implementation of black jack illustrating the use of objects (i.e. classes) in python. See programming exercise 15 in chapter 11 of Zelle's "Python Programming" book. Tested with python 3.5.2. $ python blackjack.py --- hands with 2 to four cards -- --- looking for 2 card blackjack -- 14'th hand: 58'th hand: 70'th hand: 97'th hand: 108'th hand: 113'th hand: 125'th hand: 142'th hand: 158'th hand: 180'th hand: 185'th hand: 189'th hand: 198'th hand: 216'th hand: 255'th hand: 257'th hand: 292'th hand: --- hit me --- ... ... ... Jim Mahoney | cs.marlboro.college | Nov 2018 | MIT License """ import random class Card: """ A playing card with a rank and suit. >>> d2 = Card('two', 'diamonds') >>> print(d2) two of diamonds """ # This is a "class variable" - full name is Card.suits suits = ('clubs', 'diamonds', 'hearts', 'spades') # And another "class variable - full name is Card.ranks ranks = ('ace', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'jack', 'queen', 'king') def __init__(self, rank=None, suit=None): if rank not in Card.ranks: rank = random.choice(Card.ranks) if suit not in Card.suits: rank = random.choice(Card.suits) self.rank = rank self.suit = suit def __str__(self): return "{} of {}".format(self.rank, self.suit) def is_ace(self): """ Return True if this is an ace """ return self.rank == 'ace' class BlackjackCard(Card): """ A playing card with a value() function that gives its blackjack value. >>> two_diamonds = BlackjackCard('two', 'diamonds') >>> two_diamonds.value() 2 >>> print(two_diamonds) two of diamonds """ # BlackjackCard.values values = { 'ace': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10, 'jack': 10, 'queen': 10, 'king': 10 } def value(self): return BlackjackCard.values[self.rank] class Deck: """ A deck of 52 Cards. >>> deck = Deck() >>> print(deck) >>> print(deck.pull()) king of spades >>> print(deck.pull()) queen of spades >>> print(deck) """ def __init__(self, cardclass=Card): self.cardclass = cardclass self.cards = [] for suit in Card.suits: for rank in Card.ranks: self.cards.append(cardclass(rank, suit)) def __str__(self): return "".format(len(self), (self.cardclass.__name__+'s').lower()) def __len__(self): return len(self.cards) def pull(self, rand=False): """ Pull a card from the top of the deck or from a random place. Return it. """ # Here the "top" is the last one in the self.cards list. if rand: which = random.randrange(len(self)) return self.cards.pop(which) else: return self.cards.pop() def push(self, card): """ Append a card to top of deck """ self.cards.append(card) def shuffle(self): """ Put the deck into a random order """ # random has a shuffle method ... but here I'm also repeatedly choosing # a card at random and moving it to the front, (Because of the way # pseudo randoms work, random.shuffle misses most permutations of a 52 # card deck.) random.shuffle(self.cards) for i in range(len(self)**2): self.push(self.pull(rand=True)) class Hand(Deck): """ A hand of playing cards >>> fulldeck = Deck() >>> h = Hand(fulldeck, 3) >>> print(h) """ def __init__(self, deck=None, n=1): """ Make a hand by pulling n cards from a given deck. """ self.cards = [] if deck: for i in range(n): self.push(deck.pull()) def __str__(self): result = "' def cards_string(self): """ return string of card descriptions """ if self.cards: result = '' for card in self.cards: result = result + str(card) + ', ' return result[:-2] else: return '' class BlackjackHand(Hand): """ a blackjack hand and its value (treating ace as 1 or 11) """ def value(self): """ Return blackjack value of this hand """ result = 0 for card in self.cards: result = result + card.value() if result == 11 and self.has_ace(): result = 21 return result def __str__(self): return ("").format( self.value(), len(self.cards)) def has_ace(self): """ Return true if one of the cards is an ace """ for card in self.cards: if card.is_ace(): return True return False def is_ok(self): """ return true if this had is 21 or less """ return self.value() <= 21 def is_blackjack(self): return self.value() == 21 def main(): print("--- hands with 2 to four cards --") deck = Deck(cardclass=BlackjackCard) deck.shuffle() while len(deck) > 4: n = random.randint(2, 4) bj = BlackjackHand(deck, n) print(bj) print("--- looking for 2 card blackjack --") counter = 0 while counter < 300: deck = Deck(cardclass=BlackjackCard) deck.shuffle() counter = counter + 1 bj = BlackjackHand(deck, 2) if bj.is_blackjack(): print("{}'th hand: {}".format(counter, bj)) print("--- hit me ---") deck = Deck(cardclass=BlackjackCard) deck.shuffle() for i in range(3): bj = BlackjackHand() while bj.is_ok(): bj.push(deck.pull()) print(bj) print("...") if __name__ == '__main__': import doctest doctest.testmod() main()