Code below, very new to python, would love some constructive criticism, mainly in relation to what I could have improved on, if my use of aces (where I subtract 10) is smart, and my use of functions?
The way my code works is it starts by dealing 2 cards to both the dealer and the user, this is done randomly, it then asks the user if they want another card...if they say no, the dealer gets their cards dealt, if they type yes, then they get another card and asked the question again. Aces I had trouble with utilizing so I basically just subtracted 10 from everyone who went over 21 because it's basically how people play blackjack (no one opts for a 1 if they can opt for an 11 and stay equal to or under 21).
For those wondering about the rules: Blackjack (twenty-one) is a casino game played with cards. The goal of the game to draw cards that total as close to 21 points as possible without going over. All face cards count as 10 points, aces count as 1 or 11, and all other cards count their numeric value.
The game is played against a dealer. The player tries to get closer to 21 (without going over) than the dealer. If the dealer busts (goes over 21) the player automatically wins (provided the player had not already busted). The dealer must always take cards according to a fixed set of rules. The dealer takes cards until he or she achieves a total of at least 17. If the dealer's hand contains an ace, it will be counted as 11 when that results in a total between 17 and 21 inclusive; otherwise, the ace is counted as 1.
import random
deck =(2,3,4,5,6,7,8,9,10,10,10,10,11) # main deck tuple including aces (aces become 1 if user > 21)
dealer_hand = [] # dealer list to hold cars
user_hand = [] # user list to hold cards
def draw(): # function that will be called to draw a random card from the deck
new_card = random.choice(deck)
return new_card
def dealer_draw(user_total):
if user_total < 21:
while sum(dealer_hand) < 17:
dealer_hand.append(draw())
return dealer_hand
def blackjack(): # game fuction
for i in range(2): # for loop to draw 2 cards to both the user and dealer
user_hand.append(draw())
dealer_hand.append(draw())
print(f'User has: {user_hand}')
print(f'Dealer has: {dealer_hand}')
continue_game = True # will be used to terminate while loop
while continue_game == True and sum(user_hand) < 21:
drawing = input("Would you like to draw another card (y/n) : ").lower()
if drawing == 'y': # if users types y, it draws another card
user_hand.append(draw())
if 11 in user_hand and sum(user_hand) > 21: # aces (11's) get converted to 1's if > 21
user_hand.remove(11)
user_hand.append(1)
print(f'User now has has: {user_hand}')
print(f'Dealer has: {dealer_hand}')
else:
continue_game = False
dealer_draw(sum(user_hand)) # Function to draw card for dealer (if necessary)
print("~~~~~~~~~~~~~~~~~ Final results ~~~~~~~~~~~~~~~~~")
print(f"User has {user_hand} for a total of {sum(user_hand)}")
print(f"Dealer has {dealer_hand} for a total of {sum(dealer_hand)}")
if sum(user_hand) > 21: #if statements check for bust, then draws, then checks for values between user/dealer
print("User busts! Dealer wins")
elif sum(user_hand) == sum(dealer_hand):
print("Draw")
elif sum(dealer_hand) > sum(user_hand) and sum(dealer_hand) <= 21:
print("Dealer wins")
else:
print("User wins")
# Main Game
print('____________________________________________________________________')
print(" Welcome to Blackjack ")
print("Blackjack is a card game where the user goes against the dealer.")
print("Your Goal is to draw cards to get closest to 21 points,")
print("however you don't want to go above 21 points because you will lose!")
play_game = False
while play_game == False:
play = input(" Would you like to play? (y/n) : ").lower()
if play == "y":
blackjack()
play_game = True
elif play == "n":
print('_______________________________________________________________')
print("Goodbye")
play_game = True
else:
print("You did not enter either 'y' or 'n'.")
1 Answer 1
In regards to your question of your use of functions: I think you under utilize them. Note that I could remove a lot of your comments because it is clear from the code what the code does, just by extracting functions and naming them appropriately (i would recommend the chapter Naming Conventions from Uncle Bobs Clean Code). I think your solution with the aces is fine.
Oh and I also moved everything into a class so it's easier to restart the game by just initializing a new instance. This way the game can be played more than once without restarting the whole application.
import random
def draw_for(hand):
deck = (2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11) # main deck tuple including aces (aces become 1 if user > 21)
new_card = random.choice(deck)
hand.append(new_card)
class BlackJack:
def __init__(self):
self.user_hand = None # init so pycharm doesn't warn
self.dealer_hand = None
def play(self): # game function
self.reset()
self.draw_starter_cards()
self.print_hands()
self.main_action()
self.dealer_draw_to_limit()
self.print_final_hands()
self.print_winner()
def reset(self):
self.dealer_hand = []
self.user_hand = []
def main_action(self): # could use a better name
continue_game = True
while continue_game and not self.user_busted():
drawing = input("Would you like to draw another card (y/n) : ").lower()
if drawing == 'y':
self.user_draws()
self.print_hands()
else:
continue_game = False
def user_busted(self):
return sum(self.user_hand) > 21
def user_draws(self):
draw_for(self.user_hand)
if self.user_has_aces() and self.user_busted():
self.convert_aces()
def user_has_aces(self):
return 11 in self.user_hand
def convert_aces(self):
self.user_hand.remove(11)
self.user_hand.append(1)
def dealer_draw_to_limit(self):
if not self.user_busted():
while sum(self.dealer_hand) < 17:
draw_for(self.dealer_hand)
return self.dealer_hand
def print_winner(self):
if self.user_busted():
print("User busts! Dealer wins")
elif sum(self.user_hand) == sum(self.dealer_hand):
print("Draw")
elif sum(self.user_hand) < sum(self.dealer_hand) <= 21:
print("Dealer wins")
else:
print("User wins")
def print_final_hands(self):
print("~~~~~~~~~~~~~~~~~ Final results ~~~~~~~~~~~~~~~~~")
print(f"User has {self.user_hand} for a total of {sum(self.user_hand)}")
print(f"Dealer has {self.dealer_hand} for a total of {sum(self.dealer_hand)}")
def print_hands(self):
print(f'User has: {self.user_hand}')
print(f'Dealer has: {self.dealer_hand}')
def draw_starter_cards(self):
for i in range(2):
draw_for(self.user_hand)
draw_for(self.dealer_hand)
play_game
andwhile play_game == False:
- it's kinda confusing and could use a different name likevalid_option_chosen
. \$\endgroup\$