1
\$\begingroup\$

After just learning a bit of Python, I tried coding something myself. I attempted to do a game of Blackjack, which is far from perfect, and still doesn't have some rules a real game has (in my game an ace is always 11 points, whereas in reality it can also be counted as 1 point).

There is however an issue that I'm having, simply because I don't understand it: I would like to pack some of my code in methods and call them, but I'm having an issue with some variables. I use j as a variable for the card that would be on top of the deck. By default it is set to 4, because after the starting hands have been dealt, the top card of the deck is the fourth one. Each time the player is dealt an additional card, j is increased by 1. When the user finishes playing and it's the dealers turn, I want to keep the current value of j and not revert to j being 4. How do I need to restructure my code in order to keep the changes that have been made to j in the while loop, if I put that loop into its own method? Is there a way I can "extract" a value of a variable from another method?

Additionally I want to develop good habits right from the start and tried using the best practices I know of, like using formatted Strings or using j += 1 instead of j = j + 1. Are there any bad practices in my code, where can I improve? Here's the game in its current state. It seems to be working correctly, as I haven't found a way to break it. (A minor flaw is that you have to press "Y" or "y" for another card, but instead of having to press "n" or "N" for no more cards you can press anything)

import random

# the player plays first
# dealer goes second
# dealer hits on 16 and stands on 17

deck_of_cards = ["Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King", "Ace"]
cards = {
    "Two": 2,
    "Three": 3,
    "Four": 4,
    "Five": 5,
    "Six": 6,
    "Seven": 7,
    "Eight": 8,
    "Nine": 9,
    "Ten": 10,
    "Jack": 10,
    "Queen": 10,
    "King": 10,
    "Ace": 11,
}


def drawing_a_card(card_num):
    i = card_num - 1
    drawn_card = deck_of_cards[i]
    return drawn_card


random.shuffle(deck_of_cards)
players_first_card = drawing_a_card(card_num=1)
players_second_card = drawing_a_card(card_num=3)

dealers_first_card = drawing_a_card(card_num=2)
players_total = cards[players_first_card] + cards[players_second_card]

print(f"Your first card: {players_first_card}")
print(f"Your second card: {players_second_card}")
print(f"Dealer's first card: {dealers_first_card}")
decision = input(f"You are standing at {players_total}, would you like another card? (Y/N) ")
if players_total == 21 :
    print(f"You hit 21! That's Blackjack, you win!")

j = 4
while decision.lower() == "y":
    if decision.lower() == "y":
        players_next_card = drawing_a_card(card_num=j)
        print(f"Your card: {players_next_card}")
        players_total += cards[players_next_card]
        j += 1
        if players_total > 21:
            print(f"That's a Bust! Your total was {players_total}")
            break
        elif players_total == 21:
            print(f"You hit 21! That's Blackjack, you win!")
            break
        else:
            decision = input(f"You are now standing at {players_total}, would you like another card? (Y/N) ")

k = j+1

if players_total < 21:
    print("The Dealer will now take his turn...")
    dealers_second_card = drawing_a_card(card_num=k)
    k += 1
    print(f"Dealer's cards are {dealers_first_card} and {dealers_second_card}")
    dealers_total = cards[dealers_first_card] + cards[dealers_second_card]
    if dealers_total == 21:
        print(f"The Dealer hit 21! That's Blackjack, the Dealer wins!")
    while dealers_total <= 16:
        print(f"Dealer's total is {dealers_total}, he'll take another card.")
        dealers_next_card = drawing_a_card(card_num=k)
        print(f"The Dealer's card: {dealers_next_card}")
        dealers_total += cards[dealers_next_card]
        k += 1
    if dealers_total == 21:
        print(f"The Dealer hit 21! That's Blackjack, the Dealer wins!")
    elif dealers_total > 21:
        print(f"The Dealers total is {dealers_total}, he has bust and you win!")
    if dealers_total >= 17:
        print(f"The Dealer stands at {dealers_total}")
        if dealers_total < players_total:
            print(f"Your total is {players_total}, which is higher than the Dealer's {dealers_total}, you win!")
        elif dealers_total == players_total:
            print(f"You and the Dealer are both standing at {dealers_total}, it's a draw!")
        elif dealers_total > players_total:
            print(f"The Dealer beats your {players_total} with his {dealers_total}, you lose!")

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Please use a descriptive title. Read How to ask to find out how to do that. \$\endgroup\$
    – S.S. Anne
    Commented Mar 28, 2020 at 14:54
  • 1
    \$\begingroup\$ A good title might be "A very simple Black Jack game in python". If the code is not working properly, you should try stackoverflow.com, code review is for code that is working as expected. Code review guide lines can be found at codereview.stackexchange.com/help/asking. Stackoverflow guidelines can be found at stackoverflow.com/help/asking. \$\endgroup\$
    – pacmaninbw
    Commented Mar 28, 2020 at 16:23

3 Answers 3

2
\$\begingroup\$

Is there a way I can "extract" a value of a variable from another method?

A method can return a value, so you can assign the variable you need the value of to the call of this method. You just need to think about what j actually represents and what the action that is iterating j meaningfully is. In this case it's pretty clear; you are having player A draw a set of cards from the deck and then player B draw a set of cards from the deck. So you could have a method like PlayHand() where you have a player A play their hand according to the logic you have articulated while returning the value you need for player B. Think about what "PlayHand" says in actual language and then what of your code accomplishes that task.

There is more to say but I will have to get to it later. Hope this helps!

\$\endgroup\$
1
  • \$\begingroup\$ I meant it like this: Let's say I make a method called UsersTurn where the User takes his turn and j represents the number of cards that have already been drawn/the number of the card that is on top so j=4 means the fourth card is on top. Lets say I return players_total or which card was drawn or something else. Is there a way to get to j if I return something else? \$\endgroup\$
    – GyroGoober
    Commented Mar 29, 2020 at 20:19
2
\$\begingroup\$

Usage

You made it easy to run the code, and following the input prompts is simple. It is very convenient for the user that you accept upper-case or lower-case "y" for input.

Simplify

There is no need for the following if statement because it is guaranteed to be true. You can delete it:

while decision.lower() == "y":
    if decision.lower() == "y":

In the drawing_a_card function, there no need for the extra variables. It can be simplified as:

def drawing_a_card(card_num):
    return deck_of_cards[card_num - 1]

The code would be simpler if you did not prompt the user for a decision if the player's first 2 cards add up to 21.

There are 3 variables for the player's card, but it would be simpler to just have a single variable named players_card:

players_card  = drawing_a_card(card_num=1)
players_total = cards[players_card]
print(f"Your first card : {players_card}")
players_card = drawing_a_card(card_num=3)
players_total += cards[players_card]
print(f"Your second card: {players_card}")

The following code is repeated twice:

if dealers_total == 21:
    print(f"The Dealer hit 21! That's Blackjack, the Dealer wins!")

I'm pretty sure you can re-work your logic to eliminate one of them.

The 2nd if statement in the following code would more clearly convey the intent if it were an elif:

if dealers_total == 21:
    print(f"The Dealer hit 21! That's Blackjack, the Dealer wins!")
elif dealers_total > 21:
    print(f"The Dealers total is {dealers_total}, he has bust and you win!")
if dealers_total >= 17:

Use:

elif dealers_total >= 17:
\$\endgroup\$
1
\$\begingroup\$

Probably best to just call it a deck and the function draw. We use verbs for functions.


The index i is not necessary, nor is the intermediate draw_card necessary. Moreover, I'd just create a function and actually remove cards from the deck instead of keeping an index.

So then we simply get:

def draw():
    return deck.pop()

You can then create a simple function skip() to make clear what you are doing when you currently perform a + 1 to perform the skip.

def skip()
    deck.pop()

or you can decide to simply draw and then ignore the return value.

This makes the code more like what actually happens with a deck. In general you'd want your code to reflect (an abstract version of) reality as much as possible. The worst applications to debug are those that do not make sense for the domain they are programmed for.

The other advantage is that it immediately solves the problem you have with j as it isn't necessary anymore. Instead, the deck keeps its own state.


Maybe rename cards to card_values or something like it. The value of a card is often dependent on the game that is played, so you might want to create a function for determining the possible values of the cards. As it is you can then use card_values to implement the function.


If you do keep using an index then I'd use a zero-based index everywhere in the code. Only convert to one-based when performing UI, otherwise you're setting yourself up for an off-by-one error. Yes, I know it takes some getting used to, but believe me that it is best.

In this case should use one card_index, which gets increased after every card drawn. That's better on the eyes as using literals 1, 2 and 3 and then j then k to keep the index.


There are some weird decisions with order. One of this is where you take card 1 and 3 and then give the dealer card 2. I'd just take them from the stack in order. Note that this doesn't influence the printing.

Similarly, I'd say that asking to draw another card and then check for blackjack makes little sense; the player has already won after all.


Related, you really want to think about when and how you end the game. Currently you'd break from the while loop, for instance, but then you still let the dealer continue.


if dealers_total >= 17:

This makes no sense. You already know that the dealers total is higher than that as you continued drawing cards until the <= 16 didn't hold anymore. So by definition the dealer has 17 or higher. This if statement doesn't do anything and should be removed.


I'd also introduce some constants such as BLACK_JACK = 21 and DEALER_MINIMUM = 17.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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