1
\$\begingroup\$

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
\$\endgroup\$
  • \$\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 Jul 30 '17 at 14:17
1
\$\begingroup\$

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).

\$\endgroup\$
1
\$\begingroup\$
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.

\$\endgroup\$
  • \$\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 Jul 29 '17 at 15:59
0
\$\begingroup\$

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()
\$\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.