# Blackjack game - follow-up

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

def display_info(player, dealer, player_stands):
os.system('cls' if os.name == 'nt' else 'clear')
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()


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.