Build a Blackjack Command Line Game
Tags: tutorial, python, beginners, oop
Published: 2019-07-23 16:16:21

In this tutorial, we'll cover how to build a command line game for playing Blackjack using Python! You'll get to build the game from start to finish, and when you're done, you'll have a fully functioning game to play from the command line.

While building the game, we'll explore a few handy Python concepts, such as object-oriented programming using classes and how to manage a game loop. This tutorial is also extracted from an entire course on building a Blackjack game using a graphical user environment (GUI), which you can check out [here](https://c.next.tech/30VhCRH) if you're interested.

Sound fun? Let's do it!

![](https://thepracticaldev.s3.amazonaws.com/i/dvf094oqfnunrb0cho5w.gif)


# What is Blackjack?

Blackjack is a gambling game that requires only a deck of cards. The goal of the game is to get as close as possible to a hand worth 21 points as the dealer flips over your cards – but go over and you're out!

In Blackjack, numbered cards (2 through 10) are worth their face value, picture cards (jack, queen, and king) are worth 10, and an ace is worth either 1 or 11 depending on your other cards. To start a hand, players place their bets and are dealt two cards face up. They can choose to "hit" (receive another card) or "stick" (stay with their current hand) as they attempt to get as close as possible to 21. If they chose to hit and go over 21, they "bust" and lose the hand (and the money they bet!).

Players face off against the dealer, who starts with one card face down and one face up. When all players have chosen to stick or have busted, the dealer then flips over their hidden card and either hits or sticks, their goal being to get a higher hand than any of the players.

If the dealer busts, they pay out the value of each player's wager to that player, provided that the player hasn't already busted. They also need to pay out if they don't get a higher hand than a player.

There are a lot of other rules (of course!) that you can [read up on](https://bicyclecards.com/how-to-play/blackjack/) if you're interested, but the above is everything you need to know to build this game.

Okay, let's get started with some coding!

# Installing Python

If you don't already have Python installed on your computer, you'll need to do so based on the instructions [here](https://realpython.com/installing-python/). If you'd rather avoid that, you can grab an online coding sandbox with Python and other necessary libraries pre-installed [here](https://nt.dev/python) (sign in required).

# Defining Classes

Before we begin coding our blackjack game, it's important we cover how we'll use object-oriented programming, since we will need to utilize classes for our game.

We will begin by defining the classes that will be used in order to separate out different aspects of the game of blackjack. We will model three of the components of the game:

- `Card`: A basic playing card. The card belongs to a suit (hearts ♥, diamonds ♦, spades ♠, or clubs ♣) and is worth a certain value.
- `Deck`: A collection of cards. The deck shrinks as cards are drawn and contains 52 unique cards.
- `Hand`: Each player's assigned cards. A hand is what defines each player's score and thus who wins.

Let's begin with the simplest concept: the `Card`.

# The `Card` class

The `Card` class will be the first class we define, as both of our other classes will need to use it. Create a Python file called *blackjack.py*, then add the following code:

```python
import random

class Card:
    def __init__(self, suit, value):
        self.suit = suit
        self.value = value

    def __repr__(self):
        return " of ".join((self.value, self.suit))
```

The only import we will need for our game is the `random` module. This will allow us to shuffle our virtual deck of cards at the beginning of every game.

Our first class will be one representing the playing cards. Each card will have a suit (hearts, diamonds, spades, and clubs) and a value (ace through king). We define the `__repr__` function in order to change how the card is displayed when we call `print` on it. Our function will return the value and the suit, for example, `King of Spades`. That's all we need to do for a `Card`!

Next up, we need to create a `Deck` of these `Card` classes.

# The `Deck` class

The `Deck` will need to contain 52 unique cards and must be able to shuffle itself. It will also need to be able to deal cards and decrease in size as cards are removed. Create the `Deck` class in the *blackjack.py* file using the below code:

```python
class Deck:
    def __init__(self):
        self.cards = [Card(s, v) for s in ["Spades", "Clubs", "Hearts",
                      "Diamonds"] for v in ["A", "2", "3", "4", "5", "6", 
                      "7", "8", "9", "10", "J", "Q", "K"]]

    def shuffle(self):
        if len(self.cards) > 1:
            random.shuffle(self.cards)

    def deal(self):
        if len(self.cards) > 1:
            return self.cards.pop(0)
```

When creating an instance of the `Deck`, we simply need to have a collection of every possible card. We achieve this by using a list comprehension containing lists of every suit and value. We pass each combination over to the initialization for our `Card` class to create 52 unique `Card` instances.

Our `Deck` will need to be able to be shuffled so that every game is different. We use the `shuffle` function in the `random` library to do this for us (how fitting). To avoid any potential errors, we will only shuffle a deck which still has two or more cards in it, since shuffling one or zero cards is pointless.

After shuffling, we will need to deal cards too. We utilize the `pop` function of a list (which is the data structure holding our cards) to return the top card and remove it from the deck so that it cannot be dealt again.

That's it for the `Deck` class! The final utility class to be created for our game to work is the `Hand`. All players have a hand of cards, and each hand is worth a numerical value based on the cards it contains.

# The `Hand` class

A `Hand` class will need to contain cards just like the `Deck` class does. It will also be assigned a value by the rules of the game based on which cards it contains. Since the dealer's hand should only display one card, we also keep track of whether the `Hand` belongs to the dealer to accommodate this rule.

Start with the below to create the `Hand` class in the *blackjack.py* file:

```python
class Hand:
    def __init__(self, dealer=False):
        self.dealer = dealer
        self.cards = []
        self.value = 0

    def add_card(self, card):
        self.cards.append(card)
```

Much like the `Deck`, a `Hand` will hold its cards as a list of `Card` instances. When adding a card to the hand, we simply add the `Card` instance to our `cards` list.

Within the `Hand` class, calculating the currently held `cards` value is where the rules of the game come into play the most:

```python
    def calculate_value(self):
        self.value = 0
        has_ace = False
        for card in self.cards:
            if card.value.isnumeric():
                self.value += int(card.value)
            else:
                if card.value == "A":
                    has_ace = True
                    self.value += 11
                else:
                    self.value += 10

        if has_ace and self.value > 21:
            self.value -= 10

    def get_value(self):
        self.calculate_value()
        return self.value
```

> You may note that the above code is already indented. This is intentional and done below too! This way, you don't need to perform the indents yourself and can focus on reading the instructions and code instead of chasing down whitespace errors.

In this code, we first initialize the value of the hand to `0` and assume the player does not have an ace (since this is a special case).

Then, we loop through the `Card` instances and try to add their value as a number to the player's total, using the following logic:

1. If the card's value is numerical, we add its value to the value of this hand (`self.value`).
2. If it is not numerical, we check to see whether the card is an ace. If it is, we add `11` to the hand's value and set the `has_ace` flag to `True`.
3. If it is not an ace, we simply add `10` to the value of the hand.

Once this is done, we check to see if there was an ace and the increase of `11` points brought the hand's value over `21`. If so, we make the ace worth `1` point instead by subtracting `10` from the hand's value.

Now, we need some way for the game to display each hand's cards, so we use a simple function to print each card in the hand, and the value of the player's hand too. The dealer's first card is face down, so we print `hidden` instead:

```python
    def display(self):
        if self.dealer:
            print("hidden")
            print(self.cards[1])
        else:
            for card in self.cards:
                print(card)
            print("Value:", self.get_value())
```

Now that we have all of our underlying data structures written, it's time for the main game loop!

# The Game Loop

We will define the game's main loop within its `play` method, so that to start a game, you will simply need to create an instance of the `Game` class and call `.play()` on it:

```python
class Game:
    def __init__(self):
        pass

    def play(self):
        playing = True
        
        while playing:
            self.deck = Deck()
            self.deck.shuffle()

            self.player_hand = Hand()
            self.dealer_hand = Hand(dealer=True)

            for i in range(2):
                self.player_hand.add_card(self.deck.deal())
                self.dealer_hand.add_card(self.deck.deal())

            print("Your hand is:")
            self.player_hand.display()
            print()
            print("Dealer's hand is:")
            self.dealer_hand.display()
```

The above code is pretty lengthy, so let's break it down:

* We start off our loop with a Boolean (`playing`) which will be used to track whether or not we are still playing the game.
* If we are, we need a shuffled `Deck` and two `Hand` instances—one for the dealer and one for the player. 
* We use the `range` function to deal two cards each to the player and the dealer. Our `deal` method will return a `Card` instance, which is passed to the `add_card` method of our `Hand` instances.
* Finally, we display the hands to our player. We can use the `display` method on our `Hand` instances to print this to the screen.

This marks the end of the code that needs to run at the beginning of every new game. Now, we enter a loop that will run until a winner is decided. We again control this with a Boolean (`game_over`):

```python
            game_over = False

            while not game_over:
                player_has_blackjack, dealer_has_blackjack = self.check_for_blackjack()
```

Before continuing, we first need to check for blackjack. If either player has been dealt an ace and a picture card, their hand will total `21`, so they automatically win. Let's create the method to do this (under the `play` method):

```python
    def check_for_blackjack(self):
        player = False
        dealer = False
        if self.player_hand.get_value() == 21:
            player = True
        if self.dealer_hand.get_value() == 21:
            dealer = True

        return player, dealer
```

We need to keep track of which player may have blackjack, so we will keep a Boolean for the player (`player`) and the dealer (`dealer`).

Next, go back to the `while not game_over` loop inside the `play()` method. We need to check whether either hand totals `21`, which we will do using two `if` statements. If either has a hand value of `21`, their Boolean is changed to `True`.

If either of the Booleans are `True`, then we have a winner, and will print the winner to the screen and `continue`, thus breaking us out of the game loop. To accomplish this, add the below directly underneath the `player_has_blackjack, dealer_has_blackjack = self.check_for_blackjack()` line of code:

```python
                if player_has_blackjack or dealer_has_blackjack:
                    game_over = True
                    self.show_blackjack_results(
                        player_has_blackjack, dealer_has_blackjack)
                    continue
```

We must once again pause to create the method `show_blackjack_results()`, which will print the winner to the screen. We do this by adding the code below underneath the `check_for_blackjack` method:

```python
    def show_blackjack_results(self, player_has_blackjack, dealer_has_blackjack):
        if player_has_blackjack and dealer_has_blackjack:
            print("Both players have blackjack! Draw!")

        elif player_has_blackjack:
            print("You have blackjack! You win!")

        elif dealer_has_blackjack:
            print("Dealer has blackjack! Dealer wins!")
```

If neither player had blackjack, the game loop will continue.

The player can now make a choice—whether or not to add more cards to their hand (hit) or submit their current hand (stick). To do this, add the below to the `play` method:

```python
                choice = input("Please choose [Hit / Stick] ").lower()
                while choice not in ["h", "s", "hit", "stick"]:
                    choice = input("Please enter 'hit' or 'stick' (or H/S) ").lower()
```

We use the `input` function to collect a choice from the user. This will always return us a string containing the text the user typed into the command line.

Since we have a string, we can cast the user's input to lowercase using the `lower` function to avoid having to check combinations of upper case and lower case when parsing their reply.

If their input is not recognized, we will simply keep asking for it again until it is:

```python
                if choice in ['hit', 'h']:
                    self.player_hand.add_card(self.deck.deal())
                    self.player_hand.display()
```

Should the player choose to hit, they will need to add an extra card to their hand. This is done in the same way as before with the `deal()` and `add_card()` methods.

Since their total has changed, we will now need to check whether they are over the allowed limit of `21`. Let's define a method that does this now:

```python
	def player_is_over(self):
	    return self.player_hand.get_value() > 21
```

This method simply checks whether the player's hand value is over `21` and returns the information as a Boolean.

Now, back in the `play` method, add the following inside the `if choice in ['hit', 'h']` block:

```python
                    if self.player_is_over():
                        print("You have lost!")
                        game_over = True
```

If the player’s hand has a value over `21`, they have lost, so the game loop needs to break and we set `game_over` to `True` (indicating that the dealer has won).

Okay, now let's handle when the player decides to stick with their hand. If they do this, it's time for their score to be compared with the dealer's. To do this, add the below aligned with the `if choice in ['hit', 'h']` statement:

```python
                else:
                    player_hand_value = self.player_hand.get_value()
                    dealer_hand_value = self.dealer_hand.get_value()

                    print("Final Results")
                    print("Your hand:", player_hand_value)
                    print("Dealer's hand:", dealer_hand_value)

                    if player_hand_value > dealer_hand_value:
                        print("You Win!")
                    elif player_hand_value == dealer_hand_value:
                        print("Tie!")
                    else:
                        print("Dealer Wins!")
                    game_over = True
```

We use the `else` statement here because we have already established that the user's answer was either hit or stick, and we have just checked hit. This means we will only get into this block when the user wants to stick.

The value of both the player's and the dealer's hand are printed to the screen to give the final results. We then compare the values of each hand to see which is higher.

If the player's hand is a higher value than the dealer's, we print `You Win!`. If the scores are equal, then we have a tie, so we print `Tie!`. Otherwise, the dealer must have a higher hand than the player, so we show `Dealer wins!`.

That completes the logic required for a user to play a single game. Now, let's make it possible for them to play another game by adding the following at the end of the `play` method, outside of the `while` loop:

```python
            again = input("Play Again? [Y/N] ")
            while again.lower() not in ["y", "n"]:
                again = input("Please enter Y or N ")
            if again.lower() == "n":
                print("Thanks for playing!")
                playing = False
            else:
                game_over = False
```

We once again use the combination of `lower` and a `while` loop to ensure our answer is a `y` or `n`. If the player answers with `n`, we thank them for playing and set our `playing` Boolean to `False`, thus breaking us out of the main game loop and ending the program. If not, they must have answered `y`, so we set `game_over` to `False` and let our main loop run again. This will take us right back to the top at `self.deck = Deck()` to set up a brand new game.

# Running the Game

We've completed the game! Now, it's time to run this code. To do this, we simply create an instance of the `Game` class at the end of the file and call the `play()` method:

```python
if __name__ == "__main__":
    game = Game()
    game.play()
```

Now we have a game, give it a play. You can start the game by typing `python3 blackjack.py` into your command line (or pressing the blue "Run" button, if you're using the sandbox mentioned earlier).

You should see something like the following printed onto your screen:

```
workspace $ python3 blackjack.py
Your hand is:
A of Diamonds
5 of Clubs
Value: 16

Dealer's hand is:
hidden
A of Clubs
Please choose [Hit / Stick] H
A of Diamonds
5 of Clubs
10 of Hearts
Value: 16
Please choose [Hit / Stick] H
A of Diamonds
5 of Clubs
10 of Hearts
2 of Clubs
Value: 18
Please choose [Hit / Stick] S
Final Results
Your hand: 18
Dealer's hand: 16
You Win!
Play Again? [Y/N] N
Thanks for playing!
```

# Wrapping Up

Congrats on working your way through this tutorial! In it, we covered how to build handy concepts like object-oriented programming, game flow design, and even the basics of Blackjack.

If you got stuck, the complete solution for this project can be found [here](https://gist.github.com/saulcosta/13909e2e51f94ff7b37700c74b885ab6). You can also launch an online coding sandbox with it preloaded [here](https://next.tech/projects/94217701d98d/share?ref=ce315f8c
).

Two limitations of this game are that the dealer will never hit and there is no concept of betting. Feel free to add these features yourself if you'd like! Because a dealer is required to hit or stick at certain hand values, you can develop a program that mimic the dealer exactly.

You can also check out the [full course](https://c.next.tech/30VhCRH) behind this tutorial, if you'd like!