October 1, 2023

All technologies, only pure source code

Play blackjack with Python

In this new post, play blackjack with Python, I show how to create a simple application to play this popular game.

Python programming language - logo

In this new post, play blackjack with Python, I show how to create a simple application to play this popular game.

Blackjack, also known as 21, is a card game where players try to get as close to 21 points as possible without going over. This program uses images drawn with text characters, called ASCII art. American Standard Code for Information Interchange (ASCII) is a mapping of text characters to numeric codes that computers used before Unicode replaced it.

Start the code

First think to do is to import the module `sys` and `random`. I will use the `sys` to exit the `while` loop and `random` module to shuffle the desk of cards.

```import sys, random
```

Then, I have to setup the constants for the deck using the `chr` function and assign to a variable the correspondent character.

Set up the main function

Then, I define the new constants for the suits and use them later in the code.

```HEARTS = chr(9829) # Character 9829 is '♥'.
DIAMONDS = chr(9830) # Character 9830 is '♦'.
SPADES = chr(9824) # Character 9824 is '♠'.
CLUBS = chr(9827) # Character 9827 is '♣'.
BACKSIDE = 'backside'
```

Then, I’m going to define the main function printing same text and set up the money variable.

```def main():
print('''Blackjack

Rules:
Try to get as close to 21 without going over.
Kings, Queens, and Jacks are worth 10 points.
Aces are worth 1 or 11 points.
Cards 2 through 10 are worth their face value.

(H)it to take another card.
(S)tand to stop taking cards.

On your first play, you can (D)ouble down to increase your bet
but must hit exactly one more time before standing.

In case of a tie, the bet is returned to the player.
The dealer stops hitting at 17.''')

money = 5000
```

The application can start only if I call the `main` function. For this reason, I have to call the `main` function at the end of the application with this code

```if __name__ == '__main__':
main()
```

Shuffle the deck

After that, I want to create a function that returns the deck: from 2 to 10 values and the face and aces cards for each suit. The `"""` is the comment to the function that it will show if you call the `help` function for this function.

```def getDeck():
"""Return a list of cards from the deck."""
deck = []
for suit in (HEARTS, DIAMONDS, SPADES, CLUBS):
for rank in range(2, 11):
deck.append((str(rank), suit))
for rank in ('J', 'Q', 'K', 'A'):
# add the face and ace cards
deck.append((rank, suit))
random.shuffle(deck)
return deck
```

Getting the bet

So, the next step it to write a function that takes the bet from the player. If the player texts “QUIT” the application will terminate invoking `sys.exit()`. `input` is waiting for the user to type a value. Then, the application will check if the value is a valid bet. If it is, the function will print out an error and wait for another input. If the value is accepted, the function will return the value of the bet. I like to point out that I use the function `isdecimal` to check if the value is a decimal number. Also, in the `if` I like to syntax to verify if the value is a decimal number between 1 and the `maxBet`.

```def getBet(maxBet):
"""Ask the player how much money they want to bet for this round."""
while True:
# keep asking until they enter a valid amount
print('How much do you bet? (1-{}, or QUIT)'.format(maxBet))
bet = input('> ').upper().strip()
if bet == 'QUIT':
print('Thanks for playing!')
sys.exit()

if not bet.isdecimal():
# if the player didn't enter a number, ask again
continue

bet = int(bet)
if 1 <= bet <= maxBet:
# player entered a valid bet
return bet
```

Now, in the `main` function, I add the following code to read the bet from the user and then call the `getDeck()` to have the full deck of cards shuffled.

```while True:
# check if player has run out of money
if money <= 0:
print('You have run out of money.')
print('You lose.')
print('Thanks for playing.')
sys.exit()

# let the player enter their bet for this round
print('Money: ', money)
bet = getBet(money)

# give the dealer and player two cards from the deck each
deck = getDeck()
```

Values of the card for each player

Now, we have to create a function that returns the value of the cards for each player. Here you have the code.

```def getHandValue(cards):
"""Return the value of the cards. Face cards are worth 10, Ace cards are worth 11 or 1
(this function picks the most suitable ace value)"""
value = 0
numberOfAces = 0

# add the value for the non-ace cards
for card in cards:
# card is a tuple like (rank, suit)
rank = card[0]
if rank == 'A':
numberOfAces += 1
elif rank in ('K', 'Q', 'J'):
# face cards are worth 10 points
value += 10
else:
# numbered cards are woth their number
value += int(rank)

# add the value for the ace cards
value += numberOfAces
for i in range(numberOfAces):
# if another 10 can be added with busting, do so
if value + 10 <= 21:
value += 10

return value
```

Display the cards

So, this is a console application and we don’t have any graphics but we can create, in an old style manner, the cards. Simple but efficient.

```def displayCards(cards):
"""Display all the cards in the cards list."""
rows = ['', '', '', '', '']  # The text to display on each row.

for i, card in enumerate(cards):
rows[0] += ' ___  '  # Print the top line of the card.
if card == BACKSIDE:
# Print a card's back:
rows[1] += '|## | '
rows[2] += '|###| '
rows[3] += '|_##| '
else:
# Print the card's front:
rank, suit = card  # The card is a tuple data structure.
rows[1] += '|{} | '.format(rank.ljust(2))
rows[2] += '| {} | '.format(suit)
rows[3] += '|_{}| '.format(rank.rjust(2, '_'))

# Print each row on the screen:
for row in rows:
print(row)
```

Next move

Now, the last function has to check the options for the next move for the player.

```def getMove(playerHand, money):
"""Asks the player for their move and returns'H' fir hit, 'S' stand, or 'D' double down."""

# keep asking until they enter 'H' or 'S' or 'D'
while True:
# determine the player's move
moves = ['(H)it', '(S)tand']

# the player can double down on their first move, which we can
# tell because they will be exactly teo cards
if len(playerHand) == 2 and money > 0:
moves.append('(D)ouble down')

# get the player's move
movePrompt = ', '.join(moves) + ' > '
move = input(movePrompt).upper()
if move in ('H', 'S'):
# player has entered a valid move
return move
if move == 'D' and '(D)ouble down' in moves:
# player has entered a valid move
return move
```

Full code

Last part is to implement the `main` function with all the functionalities to play the game.

```import random, sys

# Set up constants
HEARTS   = chr(9829) # Character 9829 is '♥'.
DIAMONDS = chr(9830) # Character 9830 is '♦'.
SPADES   = chr(9824) # Character 9824 is '♠'.
CLUBS    = chr(9827) # Character 9827 is '♣'.
BACKSIDE = 'backside'

def main():
print('''Blackjack

Rules:
Try to get as close to 21 without going over.
Kings, Queens, and Jacks are worth 10 points.
Aces are worth 1 or 11 points.
Cards 2 through 10 are worth their face value.

(H)it to take another card.
(S)tand to stop taking cards.

On your first play, you can (D)ouble down to increase your bet
but must hit exactly one more time before standing.

In case of a tie, the bet is returned to the player.
The dealer stops hitting at 17.''')

money = 5000

# main game loop
while True:
# check if player has run out of money
if money <= 0:
print('You have run out of money.')
print('You lose.')
print('Thanks for playing.')
sys.exit()

# let the player enter their bet for this round
print('Money: ', money)
bet = getBet(money)

# give the dealer and player two cards from the deck each
deck = getDeck()
print(deck)
dealerHand = [deck.pop(), deck.pop()]
playerHand = [deck.pop(), deck.pop()]

# handle player actions
print('Bet: ', bet)
while True:
# keep looping until player stands or busts
displayHands(playerHand, dealerHand, False)
print()

# check if the player has bust
if getHandValue(playerHand) > 21:
break

# get the player's move, either H, S or D
move = getMove(playerHand, money - bet)

# handle player actions
if move == 'D':
# player is doubled down, they can increase their bet
additionalBet = getBet(min(bet, (money - bet)))
print('Bet increased to {}.'.format(bet))
print('Bet: ', bet)

if move in ('H', 'D'):
# hit/doubling down takes another card
newCard = deck.pop()
rank, suit = newCard
print('You drew a {} of {}.'.format(rank, suit))
playerHand.append(newCard)

if getHandValue(playerHand) > 21:
# the player has busted
continue

if move in ('S', 'D'):
# stand/doubling down stops the player's turn
break

# handle the dealer's actions
if getHandValue(playerHand) <= 21:
while getHandValue(dealerHand) < 17:
# the dealer hits
print('Dealer hits...')
dealerHand.append(deck.pop())
displayHands(playerHand, dealerHand, False)

if getHandValue(playerHand) > 21:
# the dealer has busted
break

input('Press Enter to continue...')
print('\n\n')

# show the final hands
displayHands(playerHand, dealerHand, True)

playerValue = getHandValue(playerHand)
dealerValue = getHandValue(dealerHand)

# handle wheter the player won, lost or tied
if dealerValue > 21:
print('Dealer busts! You win £{}!'.format(bet))
money += bet
elif (playerValue > 21) or (playerValue < dealerValue):
print('You lost!')
money -= bet
elif playerValue > dealerValue:
print('You won £{}!'.format(bet))
money += bet
elif playerValue == dealerValue:
print('It\'s a tie, the bet is returned to you')

input('Press Enter to continue...')
print('\n\n')

def getBet(maxBet):
"""Ask the player how much money they want to bet for this round."""
while True:
# keep asking until they enter a valid amount
print('How much do you bet? (1-{}, or QUIT)'.format(maxBet))
bet = input('> ').upper().strip()
if bet == 'QUIT':
print('Thanks for playing!')
sys.exit()

if not bet.isdecimal():
# if the player didn't enter a number, ask again
continue

bet = int(bet)
if 1 <= bet <= maxBet:
# player entered a valid bet
return bet

def getDeck():
"""Return a list of cards from the deck."""
deck = []
for suit in (HEARTS, DIAMONDS, SPADES, CLUBS):
for rank in range(2, 11):
deck.append((str(rank), suit))
for rank in ('J', 'Q', 'K', 'A'):
# add the face and ace cards
deck.append((rank, suit))
random.shuffle(deck)
return deck

def displayHands(playerHand, dealerHand, showDealerHand):
"""Show the player's hand and the dealer's cards. Hide the dealer's first card if showDealerHand is False."""
print()
if showDealerHand:
print('DEALER:', getHandValue(dealerHand))
displayCards(dealerHand)
else:
print('DEALER: ???')
# Hide the dealer's first card
displayCards([BACKSIDE] + dealerHand[1:])

# show the player's hand
print('PLAYER:', getHandValue(playerHand))
displayCards(playerHand)

def getHandValue(cards):
"""Return the value of the cards. Face cards are worth 10, Ace cards are worth 11 or 1
(this function picks the most suitable ace value)"""
value = 0
numberOfAces = 0

# add the value for the non-ace cards
for card in cards:
# card is a tuple like (rank, suit)
rank = card[0]
if rank == 'A':
numberOfAces += 1
elif rank in ('K', 'Q', 'J'):
# face cards are worth 10 points
value += 10
else:
# numbered cards are woth their number
value += int(rank)

# add the value for the ace cards
value += numberOfAces
for i in range(numberOfAces):
# if another 10 can be added with busting, do so
if value + 10 <= 21:
value += 10

return value

def displayCards(cards):
"""Display all the cards in the cards list."""
rows = ['', '', '', '', '']  # The text to display on each row.

for i, card in enumerate(cards):
rows[0] += ' ___  '  # Print the top line of the card.
if card == BACKSIDE:
# Print a card's back:
rows[1] += '|## | '
rows[2] += '|###| '
rows[3] += '|_##| '
else:
# Print the card's front:
rank, suit = card  # The card is a tuple data structure.
rows[1] += '|{} | '.format(rank.ljust(2))
rows[2] += '| {} | '.format(suit)
rows[3] += '|_{}| '.format(rank.rjust(2, '_'))

# Print each row on the screen:
for row in rows:
print(row)

def getMove(playerHand, money):
"""Asks the player for their move and returns'H' fir hit, 'S' stand, or 'D' double down."""

# keep asking until they enter 'H' or 'S' or 'D'
while True:
# determine the player's move
moves = ['(H)it', '(S)tand']

# the player can double down on their first move, which we can
# tell because they will be exactly teo cards
if len(playerHand) == 2 and money > 0:
moves.append('(D)ouble down')

# get the player's move
movePrompt = ', '.join(moves) + ' > '
move = input(movePrompt).upper()
if move in ('H', 'S'):
# player has entered a valid move
return move
if move == 'D' and '(D)ouble down' in moves:
# player has entered a valid move
return move

# if the program is run (instead of imported), run the game
if __name__ == '__main__':
main()
```

Wrap up

For other examples in Python, here the links:

This site uses Akismet to reduce spam. Learn how your comment data is processed.