First Post
Tags: python, blackjack
Published: 2024-07-01 18:41:21

I just wrote a script for a terminal based blackjack script. It is not perfect believe me, but I have the functionality for a full game of blackjack.

import random

class Player:
    def __init__(self, name, balance):
        self.name = name
        self.balance = balance
        self.hand = []

    def place_bet(self, amount):
        if amount > self.balance:
            raise ValueError("Bet amount cannot exceed current balance.")
        self.balance -= amount
        return amount

    def receive_card(self, card):
        self.hand.append(card)

    def clear_hand(self):
        self.hand = []

    def calculate_score(self):
        score = sum(BlackjackGame.card_values[card] for card in self.hand)
        aces = self.hand.count('A')
        while score > 21 and aces:
            score -= 10
            aces -= 1
        return score

    def display_hand(self):
        print(f"{self.name}'s hand: {' '.join(self.hand)} (Score: {self.calculate_score()})")

class Dealer:
    def __init__(self):
        self.hand = []

    def receive_card(self, card):
        self.hand.append(card)

    def clear_hand(self):
        self.hand = []

    def calculate_score(self):
        score = sum(BlackjackGame.card_values[card] for card in self.hand)
        aces = self.hand.count('A')
        while score > 21 and aces:
            score -= 10
            aces -= 1
        return score

    def display_hand(self, show_all=False):
        if show_all:
            print(f"Dealer's hand: {' '.join(self.hand)} (Score: {self.calculate_score()})")
        else:
            print(f"Dealer's hand: {self.hand[0]} ?")

class BlackjackGame:
    card_values = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10, 'J': 10, 'Q': 10, 'K': 10, 'A': 11}

    def __init__(self, player_name, initial_balance=1000):
        self.player = Player(player_name, initial_balance)
        self.dealer = Dealer()
        self.deck = self.create_deck()
        random.shuffle(self.deck)
        self.player_hand_visible = False

    def create_deck(self):
        return ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'] * 4

    def deal_card(self):
        if not self.deck:
            self.deck = self.create_deck()
            random.shuffle(self.deck)
        return self.deck.pop()

    def play_hand(self, hand, bet):
        self.player.display_hand()
        first_action = True
        while self.player.calculate_score() < 21:
            if first_action and len(hand) == 2:
                action = input("Do you want to [h]it, [s]tand, [d]ouble down, or [sp]lit? ").lower()
            else:
                action = input("Do you want to [h]it or [s]tand? ").lower()

            if action == 'h':
                self.player.receive_card(self.deal_card())
                self.player.display_hand()
                first_action = False
            elif action == 'd' and first_action:
                if bet * 2 <= self.player.balance:
                    bet *= 2
                    self.player.receive_card(self.deal_card())
                    self.player.display_hand()
                    break
                else:
                    print("You can only double down if you have enough balance.")
            elif action == 'sp' and first_action and self.player.hand[0] == self.player.hand[1]:
                if bet * 2 <= self.player.balance:
                    return 'split'
                else:
                    print("You can only split if you have enough balance.")
            else:
                break

        return self.player.hand, bet

    def play(self):
        print("Welcome to Blackjack!")

        while self.player.balance > 0:
            print(f"Your current balance is: ${self.player.balance}")
            try:
                bet = self.player.place_bet(int(input("Place your bet: ")))
            except ValueError as e:
                print(e)
                continue

            # Clear hands and deal initial cards
            self.player.clear_hand()
            self.dealer.clear_hand()

            self.player.receive_card(self.deal_card())
            self.player.receive_card(self.deal_card())
            self.dealer.receive_card(self.deal_card())
            self.dealer.receive_card(self.deal_card())

            self.player.display_hand()
            self.dealer.display_hand()

            if self.player.hand[0] == self.player.hand[1]:
                hand_result = self.play_hand(self.player.hand, bet)
                if hand_result == 'split':
                    split_hand1 = [self.player.hand[0], self.deal_card()]
                    split_hand2 = [self.player.hand[1], self.deal_card()]

                    print("Playing first split hand:")
                    self.player.hand = split_hand1
                    result1, bet1 = self.play_hand(self.player.hand, bet)

                    print("Playing second split hand:")
                    self.player.hand = split_hand2
                    result2, bet2 = self.play_hand(self.player.hand, bet)

                    self.player.balance -= bet  # Deduct additional bet for split
                    player_hands = [result1, result2]
                    bets = [bet, bet]  # Each split hand has the same initial bet
                else:
                    player_hands = [hand_result[0]]
                    bets = [hand_result[1]]
                    self.player_hand_visible = True
            else:
                hand_result = self.play_hand(self.player.hand, bet)
                player_hands = [hand_result[0]]
                bets = [hand_result[1]]
                self.player_hand_visible = True

            # Dealer turn
            while self.dealer.calculate_score() < 17:
                self.dealer.receive_card(self.deal_card())

            self.dealer.display_hand(show_all=True)

            # Determine the winner for each hand
            dealer_score = self.dealer.calculate_score()

            for idx, (hand, bet) in enumerate(zip(player_hands, bets)):
                print(f"Evaluating hand {idx + 1}:")
                player_score = self.player.calculate_score()

                if player_score > 21:
                    print("Player busts! Dealer wins.")
                    self.player.balance -= bet
                elif dealer_score > 21:
                    print("Dealer busts! Player wins.")
                    self.player.balance += bet
                elif player_score > dealer_score:
                    print("Player wins!")
                    self.player.balance += bet
                elif dealer_score > player_score:
                    print("Dealer wins!")
                    self.player.balance -= bet
                else:
                    print("It's a tie!")

            if self.player.balance <= 0:
                print("You have run out of money. Game over.")
                break

            play_again = input("Do you want to play another round? (y/n): ").lower()
            if play_again != 'y':
                break

            self.player_hand_visible = False  # Reset player hand visibility for the next round

        print(f"Game over! Your final balance is: ${self.player.balance}")

if __name__ == "__main__":
    player_name = input("Enter your name: ")
    game = BlackjackGame(player_name)
    game.play()