blackjack.py 6.02 KB
from random import randrange
import pickle

SUITS = (':clubs:', ':spades:', ':hearts:', ':diamonds:')
CARDS = ('A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K')
CARD_VALUES = {'A':11, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, 'T':10, 'J':10, 'Q':10, 'K':10}

class Hand:
    def __init__(self):
        self.cards = []

    def add_cards(self, cards):
        if isinstance(cards, list):
            for card in cards:
                self.cards.append(card)
        else:
            self.cards.append(cards)

    def remove_card(self, card):
        self.cards.remove(card)

    def get_cards(self):
        return self.cards

    def get_points(self):
        value = 0
        number_of_aces = 0
        for card in self.cards:
            value = value + CARD_VALUES[card[0]]
            if card[0] == 'A':
                number_of_aces = number_of_aces + 1
        
        while value > 21 and number_of_aces > 0:
            value = value - 10
            number_of_aces = number_of_aces - 1
        return value

    def is_blackjack(self):
        if self.get_points() == 21 and len(self.cards) == 2:
            return True
        else:
            return False


class Deck:
    def __init__(self, number_of_decks=1):
        self.shuffle(number_of_decks)

    def shuffle(self, number_of_decks):
        self.draw_pile = []
        for d in range(number_of_decks):
            for suit in SUITS:
                for card in CARDS:
                    self.draw_pile.append(card + suit)

    def draw(self, number_of_cards=1):
        drawn_cards = []
        for n in range(number_of_cards):
            #print("CARDS LEFT: {}".format(self.cards_left()))
            choice = randrange(0, len(self.draw_pile))
            drawn_cards.append(self.draw_pile.pop(choice))
        return drawn_cards

    def cards_left(self):
        return len(self.draw_pile)

class Blackjack:
    def __init__(self, bet=0, state=None):
        if state:
            self.deserialize(state)
        else:
            self.bet = int(bet)
            self.deck = Deck()
            self.player_hand = Hand()
            self.player_hand.add_cards(self.deck.draw(2))
            #print(player_hand.get_cards())
            self.player_points = self.player_hand.get_points()
            #print("Player: {}".format(player_points,))

            self.dealer_hand = Hand()
            self.dealer_hand.add_cards(self.deck.draw(2))
            #print(dealer_hand.get_cards())
            self.dealer_points = self.dealer_hand.get_points()
            #print("Dealer: {}".format(dealer_points,))

    def draw(self):
        self.player_hand.add_cards(self.deck.draw(1))

    def dealer_draw(self):
        while self.player_hand.get_points() <= 21 and (self.dealer_hand.get_points() < 17 or self.dealer_hand.get_points() < self.player_hand.get_points()):
            self.dealer_hand.add_cards(self.deck.draw(1))

    def is_busted(self):
        self.dealer_points = self.dealer_hand.get_points()
        self.player_points = self.player_hand.get_points()

        if self.player_points > 21:
            return 1
        elif self.dealer_points > 21:
            return 2
        else:
            return 0

    def is_win(self):
        if self.player_hand.is_blackjack() and not self.dealer_hand.is_blackjack():
            return (int(self.bet + self.bet * 1.5), 'Blackjack! You win: {}')
        # Resolve blackjack before dealer draws. 
        self.dealer_draw()
        self.dealer_points = self.dealer_hand.get_points()
        self.player_points = self.player_hand.get_points()

        # TODO: Check for blackjack Ace + 10 pt
        if self.player_points > 21:
            return (0, 'You Bust. Total Winnings: {}')
        elif self.dealer_points > 21:
            return (int(self.bet * 2), 'Dealer Busts. Total Winnings {}')
        elif self.dealer_hand.is_blackjack():
            return (0, 'You lose. Total Winnings: {}')
        elif self.player_points > self.dealer_points:
            return (int(self.bet * 2), 'You win! Total Winnings {}')
        elif self.player_points == self.dealer_points:
            return (self.bet, 'push your bet is returned: {}')
        else:
            return (0, 'You lose: {}')

    def print_hand(self, show_dealer=False):
        out_string = ""
        if show_dealer:
            dealers = ' '.join(self.dealer_hand.get_cards())
            out_string += "Dealer's Hand: {} showing for {} points\n".format(dealers, self.dealer_hand.get_points())
        else:
            dealers = ' '.join(self.dealer_hand.get_cards()[1:])
            out_string += "Dealer's Hand: {} showing\n".format(dealers)

        self.player_points = self.player_hand.get_points()
        out_string += "Player's Hand: {} for {} points".format(' '.join(self.player_hand.get_cards()), self.player_hand.get_points())
        return out_string

    def get_actions(self):
        points = self.player_hand.get_points()
        cards = self.player_hand.get_cards()
        actions = []
        if self.player_hand.is_blackjack():
            pass
        elif points < 21 and not self.is_busted() == 2:
            actions.append('!hit')
            actions.append('!stand')
            #actions.append('!double')
        elif len(cards) == 2:
            if cards[0][0] == cards[1][0]:
                actions.append('!split')
        return actions

    def serialize(self):
        return pickle.dumps(self)

    def deserialize(self, state):
        self = pickle.loads(state)

# bet = 10
# bj = Blackjack(bet)
# print(bj.print_hand())
# actions = bj.get_actions()
# done = False
# while len(actions) > 0:
#     action = raw_input('Please choose an option [{}]'.format(', '.join(actions)))
#     if action == 'stand':
#         break
#     elif action == 'hit':
#         bj.draw()
#         print(bj.print_hand())
#     elif action == 'serialize':
#         state = bj.serialize()
#         print(state)
#         bj.deserialize(state)
#     actions = bj.get_actions()

# win, response = bj.is_win()
# print('\n')
# print(bj.print_hand(show_dealer=True))
# print('\n')
# print(response.format(win,))