2
\$\begingroup\$

I created this blackjack program which I'm looking for feedback, both with the code and how the program itself works. I'm also looking to see if my code could be faster or cleaner before I compile it using Cython.

I've used three files: main.py, class_handler.py and account_handler.py. For clarity, I've seperated them into different code blocks.

I previously made a post here, but I didn't format it properly. Sorry about that...

Any and all criticism is appreciated!

# class_handler.py
import random

suit_list = ["Hearts", "Diamonds", "Spades", "Clubs"]
value_list = [2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K", "Ace"]


class Card:

    def __init__(self, suit, value):
        self.suit = suit
        self.value = value

    def __repr__(self):
        return f"{self.value} of {self.suit}"


class Deck:
    deck = []

    def __init__(self, nof_card_packs, shuffled):
        for pack in range(nof_card_packs):
            self.deck += [Card(suit, value) for value in value_list for suit in suit_list]

        if shuffled is True:
            random.shuffle(self.deck)

    def __str__(self):
        return f"{len(self.deck)} cards in deck."

    def show_entire_card_deck(self):
        for i in range(len(self.deck)):
            print(self.deck[i])


class Player:
    username = ""
    is_dealer = False
    total_score = 0
    ace_counter = 0
    blackjack_flag = False
    bust_flag = False

    account = 0
    hands_played = 0
    hands_won = 0

    def __init__(self, is_dealer):
        self.is_dealer = is_dealer
        self.hand = []
        self.draw_cards()

    def __str__(self):
        if self.is_dealer:
            return f"Dealer is showing the following card: {self.hand[0]}"
        else:
            return f"You have are showing the following cards:\n{self.hand}" \
                   f"\nYour total value is: {self.total_score}."

    def draw_cards(self):
        self.hand.append(Deck.deck[0])
        Deck.deck.pop(0)
        self.hand.append(Deck.deck[0])
        Deck.deck.pop(0)
        self.determine_card_values()

    def determine_card_values(self):
        self.total_score = 0
        for card in range(len(self.hand)):
            if self.hand[card].value == "Ace":
                self.ace_counter += 1
                self.total_score += 11
            elif self.hand[card].value in ["J", "Q", "K"]:
                self.total_score += 10
            else:
                self.total_score += int(self.hand[card].value)

            if self.total_score > 21:
                if self.ace_counter >= 1:
                    self.ace_counter -= 1
                    self.total_score -= 10
                else:
                    print("-----\nBust!\n-----")
                    self.bust_flag = True
                    break

    def deal_card(self):
        self.hand.append(Deck.deck[0])
        Deck.deck.pop(0)
        print(self.hand[len(self.hand) - 1])
        self.determine_card_values()

    def player_actions(self):
        if self.blackjack_flag:
            pass
        else:
            while True:
                if self.total_score == 21:
                    print("BLACKJACK!")
                    break
                print(self, "\n")
                console = str(input("Hit or stand?\n>"))
                console.lower()
                if console == "hit":
                    self.deal_card()
                    if self.bust_flag:
                        print(f"You've gone bust:\nHand:{self.hand}\nTotal value:{self.total_score}")
                        break
                elif console == "stand":
                    break

    def dealer_actions(self, player):
        print(self, "and", self.hand[1])
        while True:
            if not self.total_score > player.total_score:
                if self.bust_flag:
                    print(f"Dealer went bust:\nHand: {self.hand}\nTotal value: {self.total_score}")
                    break
                if self.total_score < 17:
                    self.deal_card()
                else:
                    print(f"Dealer stands on {self.total_score}")
                    break

            else:
                print(f"Dealer stands on {self.total_score}")
                break

    def determine_winner(self, dealer):
        print(f"""
---------------------------------------------------- GAME OVERVIEW -----------------------------------------------------
At the end of the game, you had a hand of {self.hand} and a total score of {self.total_score}.
The dealer had a hand of {dealer.hand} and a total score of {dealer.total_score}.""")
        if not self.bust_flag:
            if not dealer.bust_flag:
                if self.total_score == dealer.total_score:
                    print("Draw!")
                elif self.total_score > dealer.total_score:
                    print("You win!")
                else:
                    print("You lose!")
                    self.hands_won += 1
            else:
                print("You win!")
                self.hands_won += 1
        else:
            print("You lose!")
        self.hands_played += 1
        print("""
--------------------------------------------------------------------------------------------------
""")

    def show_stats(self):
        print(f"""
------------- BASIC INFO -------------
Username: {self.username}
Bank Account: {self.account}
---------- PLAYER STATISTICS ---------
Hands played: {self.hands_played}
Hands won: {self.hands_won}
--------------------------------------""")```

# --------------------------------------------------------------------------------

# account_handler.py
def create_account():
    """Creates a new account for the player, with 1500 chips."""
    username = str(input("Enter a username.\n>"))
    user_profile = open(username + ".txt", "w")
    user_profile.write(f"""
------------- BASIC INFO -------------
Username: {username}
Bank Account: 1500
---------- PLAYER STATISTICS ---------
Hands played: 0
Hands won: 0
--------------------------------------
{username},1500,0,0""")
    user_profile.close()
    print("Account created successfully!")


def write_account(profile):
    """Saves changes to the current account."""
    username = str(input("Enter a username.\n>"))
    user_profile = open(username + ".txt", "w")
    file_info = (f"""
------------- BASIC INFO -------------
Username: {username}
Bank Account: {profile.account}
---------- PLAYER STATISTICS ---------
Hands played: {profile.hands_played}
Hands won: {profile.hands_won}
--------------------------------------
{username},{profile.account},{profile.hands_played},{profile.hands_won}""")
    user_profile.write(file_info)
    user_profile.close()
    print("File written successfully!")


def load_account(profile):
    """Loads changes from account."""
    username = str(input("Enter a username.\n>"))
    user_profile = open(username + ".txt", "r")
    str_info = user_profile.readlines()[8]
    info = str_info.split(",")
    print(info)
    profile.username = info[0]
    profile.account = info[1]
    profile.hands_played = info[2]
    profile.hands_won = info[3]
    user_profile.close()
    print("File loaded successfully!")```
--------------------------------------------------------------------------------------------------
# main.py
from class_handler import *
from account_handler import *
import os


def setup_game():
    """Sets up the initial game."""
    Deck(shuffled=True, nof_card_packs=5)
    player_f = Player(False)
    dealer_f = Player(True)
    return player_f, dealer_f


def help_with_cmds(console_input):
    """Gets help with the current commands. Supports two words (e.g. 'help clear')"""
    if len(console_input) > 1:
        if console_input[1] == "close":
            print(close.__doc__)
        elif console_input[1] == "play":
            print(play.__doc__)
        elif console_input[1] == "createacc":
            print(create_account.__doc__)
        elif console_input[1] == "saveacc":
            print(write_account.__doc__)
        elif console_input[1] == "loadacc":
            print(load_accoutn.__doc__)
        elif console_input[1] == "clear":
            print(clear.__doc__)
        elif console_input[1] == "stats":
            print(stats.__doc__)
        elif console_input[1] == "help":
            print(help_with_cmds.__doc__)
        else:
            print("Unrecognised input, please try again.")
    else:
        print("""Available commands:
close
play
createacc
saveacc
loadacc
clear
stats""")


def clear():
    """Clears the screen. Your mileage may vary!"""
    if os.name == "nt":
        os.system("cls")
    else:
        os.system("clear")


def close():
    """Closes the program.
    Available inputs:
    Yes, yes, y: closes the program.
    Anything else: cancels the shutdown."""
    console1 = str(input("!!! ANY UNSAVED STATS WILL BE LOST !!\nAre you sure?\nCl>"))
    console1.lower()
    if console1 == "yes" or "y":
        quit()
    else:
        print("Cancelling shutdown.")


def play():
    """Plays the main blackjack game once."""
    player, dealer = setup_game()
    print(dealer, "\n")
    player.player_actions()
    if not player.bust_flag:
        dealer.dealer_actions(player)
    player.determine_winner(dealer=dealer)


def console():
    player, dealer = setup_game()
    console_input = str(input(">"))
    console_input.lower()
    if console_input.__contains__("help"):
        console_input_list = console_input.split()
        help_with_cmds(console_input_list)
    elif console_input == "close":
        close()
    elif console_input == "play":
        play()
    elif console_input == "createacc":
        create_account()
    elif console_input == "saveacc":
        write_account(player)
    elif console_input == "loadacc":
        load_account(player)
    elif console_input == "clear":
        clear()
    elif console_input == "stats":
        player.show_stats()
    else:
        print("Unrecognised command. Please try again.")


if __name__ == "__main__":
    print("Beginners Poker. Enter an option.")
    while True:
        console()```
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Some minor feedback:

  • I think multiline strings inside indented code make the surrounding code hard to read. I would suggest using indenting the strings then using textwrap.dedent() to make the code more readable.
  • It's probably a good idea to use all caps names for global variables such as suit_list and value_list.
  • .pop returns a value, so you can combine a couple of lines like this: self.hand.append(Deck.deck.pop(0))
  • Comparison to >=1 can likely be just if self.ace_counter: unless you are concerned about negative numbers, because 0 evaluates as False.
\$\endgroup\$
0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.