5
\$\begingroup\$

This is an updated version of my previously posted "Blackjack game made in Python 3". I think I did almost everything @Austin Hastings recommend me to do and I hope you like it.

from random import shuffle
import os


def shuffled_shoe():
    shoe = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'A', 'J', 'Q', 'K']*4
    shuffle(shoe)
    return shoe


def deal_card(shoe, person, number):
    for _ in range(number):
        person.append(shoe.pop())


def deal_hand(shoe, player, dealer):
    deal_card(shoe, player, 2)
    deal_card(shoe, dealer, 2)


def score(person):
    non_aces = [c for c in person if c != 'A']
    aces = [c for c in person if c == 'A']
    total = 0
    for card in non_aces:
        if card in 'JQK':
            total += 10
        else:
            total += int(card)
    for card in aces:
        if total <= 10:
            total += 11
        else:
            total += 1
    return total


def display_info(player, dealer, player_stands):
    os.system('cls' if os.name == 'nt' else 'clear')
    print("Your cards:   [{}] ({})".format("][".join(player), score(player)))
    if player_stands:
        print("Dealer cards: [{}] ({})".format("][".join(dealer), score(dealer)))
    else:
        print(f"Dealer cards: [{dealer[0]}][?]")


def hit_or_stand():
    while True:
        print("What do you choose?")
        print("[1] Hit")
        print("[2] Stand")
        ans = input("> ")
        if ans in '12':
            return ans


def player_play(shoe, player, dealer, player_plays, dealer_plays, player_stands):
    while not player_stands:
        if hit_or_stand() == '2':
            player_plays = False
            dealer_plays = True
            player_stands = True
            display_info(player, dealer, True)
        elif not player_stands:
            deal_card(shoe, player, 1)
            display_info(player, dealer, False)
            if score(player) >= 21:
                player_plays = False
                break
    return (player_plays, dealer_plays, player_stands)


def dealer_play(shoe, dealer, DEALER_MINIMUM_SCORE, player):
    while score(dealer) <= DEALER_MINIMUM_SCORE:
        deal_card(shoe, dealer, 1)
    display_info(player, dealer, True)
    return False


def results(player, dealer, player_stands, first_hand, still_playing):
    if score(player) == 21:
        print("Blackjack! You won")
        still_playing = False
    elif first_hand and score(dealer) == 21:
        print("Dealer got a blackjack. You lost!")
        still_playing = False
    elif score(player) > 21:
        print("Busted! You lost!")
        still_playing = False
    if player_stands:
        if score(dealer) > 21:
            print("Dealer busted! You won")
        elif score(player) > score(dealer):
            print("You beat the dealer! You won!")
        elif score(player) < score(dealer):
            print("Dealer has beaten you. You lost!")
        else:
            print("Push. Nobody wins or losses.")
        still_playing = False
    return still_playing


def main():
    shoe = shuffled_shoe()
    player = []
    dealer = []
    player_plays = True
    still_playing = True
    dealer_plays = False
    player_stands = False
    deal_hand(shoe, player, dealer)
    display_info(player, dealer, player_stands)
    still_playing = results(player, dealer, player_stands, True, still_playing)
    while still_playing:
        while player_plays:
            (player_plays, dealer_plays, player_stands) = player_play(shoe, player, dealer, player_plays, dealer_plays, player_stands)
        while dealer_plays:
            dealer_plays = dealer_play(shoe, dealer, 17, player)
        still_playing = results(player, dealer, player_stands, False, still_playing)


if __name__ == '__main__':
    main()
\$\endgroup\$
3
\$\begingroup\$

First; I agree with the points made by @Austin. I like it that your code is written such that it is easy to read (which I find important). However, I find the structure of the program a bit hard to follow. For example; there are two display functions (display_info and result). I would merge these or at the least group them together.

In Python there seem to be two schools: 1) put everything in a function (as a means of documentation), 2) create functions to aid "separation of concerns" and add comments for documentation. My guess is that @Austin is more a type-1 person and I am more a type-2 person. I would suggest to add comments (especially to document functions and function arguments).

These are some observations from my side:

  • a lot of functions take both the player as the dealer as argument, while their actions are similar. It could be benificial to create a more generic function for an action (stand/hit) and call that function separately. For example: create a function which asks the action of the dealer and a function asking the action of the player.
  • the dealer_play function always returns False. So I guess you can get rid of the return argument, as well as the 'while dealer_plays:' loop.
  • the results function seems overly complex to me. I would not call the function at all as long as the dealer or the player are still playing. This would remove the need to keep track of who is still playing. Print the intermediate scores separately and evaluate the winner after the game.
  • there is no need to provide a boolean for first_hand. Each player and dealer always start with two cards. So len(cards)==2 gives the same information. For readability it could be good to perform this action at the start of the function (first_hand = len(dealer) == 2), as this way there is no need to change the code too much and you remove the burden of keeping track of this variable from the function-caller.

There is one other point that caught my eye: you are mixing different string formatting methods (''.format() vs f-strings). I would choose one of the methods and stick with that.

All these comments might seem like I do not like your code. This is not the case, my aim is to point out some possible improvements.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.