Skip to content

Instantly share code, notes, and snippets.

# louisswarren/blackjack.py

Last active May 1, 2020
Blackjack
 from collections import namedtuple from enum import Enum import random compose = lambda f: lambda g: lambda *a, **k: f(g(*a, **k)) class Face(Enum): ACE = 'A' TWO = '2' THREE = '3' FOUR = '4' FIVE = '5' SIX = '6' SEVEN = '7' EIGHT = '8' NINE = '9' TEN = 'X' JACK = 'J' QUEEN = 'Q' KING = 'K' class Suit(Enum): SPADE = '♠' HEART = '♥' DIAMOND = '♦' CLUB = '♣' class Card(namedtuple('Card', 'face suit')): def __str__(self): return self.face.value + self.suit.value @property def score(self): if self.face == Face.ACE: return 11 elif self.face in (Face.TEN, Face.JACK, Face.QUEEN, Face.KING): return 10 else: return int(self.face.value) full_deck = {f.name.lower() + '_of_' + s.name.lower() + 's' : Card(f, s) for f in Face for s in Suit} class Move(Enum): HIT = 'hit' STAY = 'stay' class Result(Enum): BLACKJACK = 'blackjack' PUSH = 'push' BUST = 'bust' WIN = 'win' LOSE = 'lose' class Gamestate(namedtuple('Gamestate', 'dealer player')): @compose(''.join) def __str__(self): if self.dealer[0] is None: yield '-- ' yield ' '.join(str(card) for card in self.dealer[1:]) else: yield ' '.join(str(card) for card in self.dealer) yield ' ({})'.format(hand_score(self.dealer)) yield '\n' yield ' '.join(str(card) for card in self.player) yield ' ({})'.format(hand_score(self.player)) def deck_stream(num_decks=1): deck = list(full_deck.values()) * num_decks while True: random.shuffle(deck) yield from deck def hand_score(hand): have_ace = False total = 0 for card in hand: if card.face == Face.ACE: have_ace = True total += 1 else: total += card.score if have_ace and total <= 11: total += 10 return total def blackjack(deck): player = [next(deck), next(deck)] dealer = [next(deck), next(deck)] if hand_score(player) == 21: yield Gamestate(dealer, player), () if hand_score(dealer) == 21: return Result.PUSH else: return Result.BLACKJACK while hand_score(player) < 21: move = yield Gamestate((None, *dealer[1:]), player), tuple(Move) if move == Move.HIT: player.append(next(deck)) else: assert(move == Move.STAY) break if hand_score(player) > 21: yield Gamestate((None, *dealer[1:]), player), () return Result.BUST yield Gamestate(dealer, player), () if hand_score(dealer) == 21: return Result.LOSE while hand_score(dealer) < 17: dealer.append(next(deck)) yield Gamestate(dealer, player), () if hand_score(dealer) > 21: return Result.WIN if hand_score(player) > hand_score(dealer): return Result.WIN elif hand_score(player) < hand_score(dealer): return Result.LOSE else: return Result.PUSH # Move this move_keys = {Move.HIT: 'h', Move.STAY: 's'} key_binds = {v: k for k, v in move_keys.items()} key_binds[''] = Move.STAY def input_move(choices): prompt = ''.join('[{}] {:<8s}'.format(move_keys[choice], choice.value) for choice in choices) + '> ' while True: response = input(prompt) if response in key_binds: return key_binds[response] def play(num_decks=1): deck = deck_stream(num_decks) g = blackjack(deck) state, moves = next(g) try: while True: print() print(state) if moves: move = input_move(moves) assert(move in moves) else: move = None state, moves = g.send(move) except StopIteration as e: print(e) if __name__ == '__main__': try: while True: play() print() print('-' * 80) print() except EOFError: pass
to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.