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):
# add the numbered cards
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
print('Please enter a number.\n')
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)))
bet += additionalBet
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
print('Please enter a number.\n')
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):
# add the numbered cards
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:
- Bagels
- Bitmap message