Like the title says, I made a very simple game of Blackjack using Python version 2.6.9. I am relatively new to python and programming so I would really appreciate some constructive criticism to help me improve.
from random import shuffle #this imports shuffle which shuffles the deck
deck = list('234567890JQKA'*4)
for shu in range(0,3):
shuffle(deck)
value = {'2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8,
'9':9, '0':10, 'J':10, 'Q':10, 'K':10, 'A':1} # Creates the shuffled deck
player = [deck.pop() for _ in range(2)]
AI = [deck.pop() for _ in range(2)] # Deals the cards to the players
stay = False
def player_game():
global stay
print "Your hand: %s" % player
hit = raw_input("Hit or Stay? ")
if hit == "Hit":
player.append(deck.pop())
elif hit == "Stay":
stay = True
return stay
else:
print "I'm sorry. you need to input 'Hit or Stay'."
while 1:
player_game()
total = sum(map(value.get, player, AI))
if total > 21:
print "Hand: %s" % player
print "You busted with a score of: %s" % total
break
elif total == 21:
print player
print "You win!"
break
if stay == True:
print "You stayed."
print "Final score: %s" % total
break
-
\$\begingroup\$ Why do you use such an old Python version? I think we're at a point where no beginner should start with something else than the most recent version (3.6) or if you really want to learn Python 2 then use at least Python 2.7.13. \$\endgroup\$skrx– skrx2017年07月30日 14:17:25 +00:00Commented Jul 30, 2017 at 14:17
3 Answers 3
It is common practice to shorten statements like
if stay == True:
down to
if stay:
This'll make your code easier to read (more English-like).
from random import shuffle #this imports shuffle which shuffles the deck
The comment isn't really necessary. I wouldn't worry too often about explain imports upfront. I would explain the functions when you use them. In this case, however:
shuffle(deck)
Is fairly self explanitory.
for shu in range(0,3):
As you never use shu
, by convention you would use _
instead. More importantly, I'm not exactly sure what you hope to get out of shuffling the deck three times. I think once is probably enough.
Using global
is usually bad practice. You can use the return value of play_game
to get around this. (I'll leave that as an exercise.)
I would change while 1:
to while True:
. Although they do the same thing True
is considered better style in at least Python.
-
\$\begingroup\$ Would you mind explaining more of how I can use the return value of 'player_game'? I have tried playing around with it and can't seem to fix the problem without using 'global'. \$\endgroup\$Matt Turner– Matt Turner2017年07月29日 15:59:43 +00:00Commented Jul 29, 2017 at 15:59
The program looks pretty good, but the main thing that should be changed is the global variable stay
. Global variables should mostly be avoided, since they make code harder to understand and maintain. I'd only get the input in the player_game
function and return True
or False
if the user wants to stay or hit, and then assign this returned value to the stay
variable.
Then there's a big problem with your total = sum(map(value.get, player, ai))
line. You're passing the ai
cards as default values to value.get
. That means if the player has a invalid card that doesn't exist in the value
dict, it adds the ai card instead. I think it's not possible to have invalid cards, so you can just change the line to total = sum(VALUE[card] for card in player)
(that's a generator expression that we pass to sum
. It's similar to a list comprehension, but is evaluated lazily).
Regarding string formatting, in your simple cases you don't need it: print("Your hand:", player)
, but I also recommend to take a look at the new style string formatting "Your hand: {}".format(player)
and if you switch to Python 3.6 the new f-strings f"Your hand: {player}"
.
I've made some changes to the program and added comments.
# This allows you to use Python 3's print function in
# Python 2, so that the program is more compatible.
from __future__ import print_function
from random import shuffle
# Maps the card strings to integer values. This dict should stay
# constant (won't get changed), therefore we use a uppercase name.
# That just tells other programmers that they shouldn't modify this dict.
VALUE = {'2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8,
'9':9, '0':10, 'J':10, 'Q':10, 'K':10, 'A':1}
def player_input():
"""Return True for stay and False for hit."""
# A while loop is needed here, if the user inputs something invalid.
while True:
# Convert input to lower case to be more user friendly.
hit = raw_input("(H)it or (s)tay? ").lower()
# We can also allow `h` or `s` as input.
if hit in ("hit", "h"):
return False # Assign this to the `stay` variable in `main`.
elif hit in ("stay", "s"):
return True # Assign this to the `stay` variable in `main`.
else:
print("I'm sorry. you need to input '(h)it or (s)tay'.")
# Put everything into a main function except the global constants.
def main():
deck = list('234567890JQKA'*4)
# If the variable isn't needed we usually use `_` as
# a throwaway variable. `range(3)` is the same as `range(0, 3)`.
# for _ in range(3): # Shuffling 3 times is pointless.
shuffle(deck)
# Deals the cards to the players.
player = [deck.pop() for _ in range(2)]
# Uppercase names are for constants.
ai = [deck.pop() for _ in range(2)]
while True: # `while 1:` is outdated.
print("Your hand:", player)
stay = player_input()
if not stay:
player.append(deck.pop())
total = sum(VALUE[card] for card in player)
if total > 21:
print("Hand:", player)
print("You busted with a score of:", total)
break
elif total == 21:
print("Hand:", player)
print("You win!")
break
elif stay: # == True: isn't needed.
print("You stayed.")
print("Final score:", total)
break
# This makes sure that the program doesn't run
# if it gets imported.
if __name__ == '__main__':
main()
Explore related questions
See similar questions with these tags.