You are on page 1of 8

Matthew Burger

Professor Buckingham
MATH 3096 – Math of Games and Puzzles
5 October 2017

Project 1: Probability of Outcomes in Blackjack

The outcomes of a hand of blackjack are neither fully based on chance nor fully based on
strategy. Therefore, blackjack requires a firm understanding of both combinatorics and
algorithmic decision making in order to become a masterful player. Furthermore, the game was
heavily featured in the hit 2008 film 21, which quickly became a favorite film. Due to these
factors, the game of blackjack has always been an intriguing subject, both as a recreational
pursuit and an intellectual quandary. It was, therefore, an obvious choice for the topic of this
project.
Blackjack has many varying rulesets, but several key rules are universally common. The
ultimate objective of the game is to obtain as close to 21 points as possible without achieving a
sum greater than 21 (known as a bust). The cards two through ten are given their face value in
points. Secondly, face cards, jack through king, are given the value of ten. Lastly, the ace is
given a value of one or eleven, depending on whether or not the higher value will cause a player
to bust. The game begins with the dealing of two cards to each player and the dealer, with all
cards except one of the dealer’s facing upwards. For the sake of simplicity, only two players
(including the dealer) will be considered.
If the first two cards result in a sum of 21, the player is said to have a “blackjack.” If the
dealer has a blackjack, the hand is over and the other player loses immediately. Assuming this
event does not occur, the player is met with a decision: to hit or to stand (due to the brevity of
this investigation and project, the other traditional options such as surrendering, splitting, and
doubling down will not be considered). Hitting results in the dealing of another card whose
points are added to those of the previously dealt cards, whereas standing results in the player
becoming inactive until the dealer has finished his or her hitting and standing cycle. The clear
question is: for any given hand held by a player, what option should the player choose in order
minimize losses (i.e. busts)?
Because there are a finite number of possible card draws for a single standard deck of
playing cards, there are also a finite number of hands that result in a bust or a sum of 21.
Fundamental combinatorics may be used to determine these specific values for a given set of
hole cards (the cards that have been dealt). The division of the latter by the former will result in
the probability of busting or obtaining a 21 at any given fork in the decision tree. Because the
goal is to minimize losses to the house advantage, hitting will be considered the better decision
of the two if and only if the chance of obtaining a sum of 21 is non-zero and the chance of
busting is less than or equal to 0.5. In order to further limit the scope of this investigation, the
number of cases will be limited and strategies such as card-counting will not be considered.
Furthermore, a script written in the Python language will be used to validate the theoretical
probabilities through experimental simulation of a finite number of blackjack hands.
By simple examination of the fundamental rules of blackjack, it is apparent that hands
with a sum of eleven or less will never result in a bust if the player chooses to hit once. This
result is due to the very nature of the points system in blackjack. For example, if the player is
initially dealt a seven and a four (the card ranks do not matter in this case, only the sum), there
are four ranks of cards (ten, jack, queen, king) that will result in a sum of 21. Furthermore, if an
ace is dealt, it will default to a value of one in order to prevent a bust. If the dealer is not known
4
to have a card with a value of ten (ten, jack, queen, king), there are ( ) ways to choose a rank
1
4
that will result in 21 and ( ) possible card draws for each of those respective ranks. Since four
1
48
cards have already been dealt, there are ( ) ways to draw a single card. Therefore, the
1
(4)(4) 16 1
probability of summing to 21 points after a hit is 𝑃(21) = 1481 = = = 0.33 ̅̅̅̅̅̅. This
( ) 48 3
1
theoretical result is simulated in Python for 10,000 hands and the resulting probabilities (in the
form of a pie chart) are given in Figure 1.

Figure 1: Pie Chart - Player with 4-7, No Dealer Face Cards Shown

As shown in the figure, the experimental probability of obtaining a sum of 21 after a single hit
with an initial sum of eleven and no dealer face cards shown is 0.324. Using the relative error
|𝑉exp −𝑉theo |
equation, %𝐸𝑅 = ⋅ 100, the relative error is found to be 2.80%. This relatively small
𝑉theo
discrepancy may be explained by the relatively small sample size.
If the dealer is known to have a card with a value of ten (ten, jack, queen, king), there are
15
( ) ways to choose a rank that will result in 21 (15 out of the total 16 cards that have a value of
1
48
ten). Since four cards have already been dealt, there are ( ) ways to draw a single card.
1
(15) 15
Therefore, the probability of summing to 21 points after a hit is 𝑃(21) = 48 1 ̅̅̅̅̅̅̅̅̅.
= = 0.3125
( ) 48
1
This theoretical result is simulated in Python for 10,000 hands and the resulting probabilities (in
the form of a pie chart) are given in Figure 2.

Figure 2: Pie Chart - Player with 4-7, Dealer Face Card Shown

As shown in the figure, the experimental probability of obtaining a sum of 21 after a single hit
with an initial sum of eleven with a dealer face card known is 0.315. Using the relative error
|𝑉exp −𝑉theo |
equation, %𝐸𝑅 = ⋅ 100, the relative error is found to be 0.80%. As before, this
𝑉theo
relatively small discrepancy may also be explained by the relatively small sample size. As the
sample size approaches infinity, the experimental probability will approach the theoretical value.
If the player were instead dealt a lower sum of cards initially (e.g. 2-7) and a single hit
brought the total up to a sum of eleven, a subsequent hit for a fourth card would result in higher
probabilities of a sum of 21, relative to their counterparts in the previous calculations. This is due
simply to the lower number of total card draws available after the first hit.
As the point value of the initial two cards increases above eleven, the probability of
busting increases to a non-zero value. For example, if the player is initially dealt a sum of 14
(e.g. five and nine), there is only rank of cards that will result in a sum of 21 upon a single hit
(seven). Therefore, the best-case probability of obtaining a sum of 21 if the dealer has no known
(4
1) 4 1
sevens is given by the expression 𝑃(21) = 48
̅̅̅̅. Furthermore, in the worst-
= 48 = 12 = 0.0833
( )
1
case scenario, the dealer does not have one of the player’s so-called bust cards (8, 9, 10, J, Q, K)
face up and is instead dealt a seven; the player is dealt two sevens. This results in a probability of
(6)(4) 24
1 1
bust for the player of 𝑃(bust) = 48 = 48 = 0.500 and a probability of 21 for the player of
( )
1
(1
1) 1
only 𝑃(21) = 48
̅̅̅̅. This result is simulated in Python for 10,000 hands and
= 48 = 0.020833
( )
1
the resulting pie chart is given in Figure 3.

Figure 3: Pie Chart - Player with 7-7, Dealer 7-X

The experimental probability of obtaining a 21 after a single hit with the aforementioned
circumstances is 2.0% and the probability of busting after a single hit is given as 49.4%. These
values represent relative errors of 3.99% and 1.2%, respectively. Once again, if the sample size
were to increase to near infinity, the experimental values of probability would approach the
theoretical values of probability.
As the sum of the initial dealt hand increases above 14, the probability of busting begins
to overtake the sum of the neutral and 21 probabilities. In the best-case scenario, the player is
dealt seven and eight, while the dealer is dealt one of the bust cards (7, 8, 9, 10, J, Q, K).
Because the only card that will provide a sum of 21 for this hand is six, the probability of
(4
1) 4 1
obtaining a 21 on the next hit is 𝑃(21) = 48
̅̅̅̅. Furthermore, there are a total
= 48 = 12 = 0.0833
( )
1
of 25 cards remaining in the deck which will result in a bust if dealt on the hit. This results in a
(25) 25
1
probability of busting of 𝑃(𝑏 cos 𝑓) = = 48 ≈ 0.5208.
(48)
1
This result is simulated in Python for 10,000 hands and the resulting pie chart is given in Figure
4.

Figure 4: Pie Chart - Player with 7-8, Dealer K-X

The experimental probability of obtaining a 21 after a single hit with the aforementioned
circumstances is 8.4% and the probability of busting after a single hit is given as 50.5%. These
values represent relative errors of 0.80% and 3.04%, respectively. As stated, if the sample size
were to increase to near infinity, the experimental values of probability would approach the
theoretical values of probability.
With the goal of reducing the occurrence of busts in mind, it is clear that there are three
main regions of probabilities, each with their associated risk level. The low-risk region occurs
where the sum of the player’s current cards is eleven or less. In this area, one should always hit
because the probability of busting is zero. The medium-risk zone occurs where the sum of the
player’s current cards is between 12 and 14, inclusive. In this area, one should generally hit
because the probability of busting is on the interval (0, 0.5]. The high-risk region occurs where
the sum of the player’s cards is above 14. In this area, one should generally stand because the
probability of busting is greater than 50%. Naturally, this general guideline will shift if the
constraints of gameplay are changed, such as playing with more than one deck or more than one
non-dealer player.
Appendix
Inspiration for the source code was given by Stack Exchange user Nolen Royalty. The source
code for the Python simulation is as follows:
import random
import matplotlib.pyplot as plt

games = 10000 # Number of simulations desired

pCount21 = 0
pCountBusts = 0
pCountN = 0

deCount21 = 0
deCountBusts = 0
deCountN = 0

class Card(object):
ranks = {1: "Ace", 2: "Two", 3: "Three", 4: "Four", 5: "Five", 6: "Six", 7:
"Seven",
8: "Eight", 9: "Nine", 10: "Ten", 11: "Jack", 12: "Queen", 13: "King"}

def __init__(self, key, suit):


self.name = self.ranks[key]
self.suit = suit
self.title = "%s of %s" % (self.name, self.suit)
self.score = min(key, 10) # Ensures the highest score is 10 for face cards

def __repr__(self):
return self.title

class Hand(object):
def __init__(self, cards):
self.hand = cards

def get_scores(self):
aces = sum(card.name == "Ace" for card in self.hand) # Counts number of aces
in hand
score = sum(card.score for card in self.hand)
return [score + i*10 for i in range(aces + 1)]

def possible_scores(self):
return [score for score in self.get_scores() if score <= 21]

def __repr__(self):
return str(self.hand)

class Deck(object):
newDeck = [Card(card, suit) for card in range(1, 14) for suit in ["Clubs",
"Diamonds", "Hearts", "Spades"]]

def __init__(self, num_decks=1):


self.deck = self.newDeck * num_decks
random.shuffle(self.deck)

def deal_card(self, specify=["", ""]):


if specify == ["", ""]:
return self.deck.pop()
else:
return self.deck.pop([i for i in range(len(self.deck)) if
(self.deck[i].name == specify[0] and self.deck[i].suit == specify[1])][0])

def deal_hand(self, dictateCard1=["", ""], dictateCard2=["", ""]): # Allows for


random and dictated hands
if dictateCard1 == ["", ""] and dictateCard2 == ["", ""]:
return Hand([self.deal_card(), self.deal_card()])
elif dictateCard2 == ["", ""]:
return Hand([self.deal_card(dictateCard1), self.deal_card()])
else:
return Hand([self.deal_card(dictateCard1), self.deal_card(dictateCard2)])

class Player(object):
def __init__(self, name="Player"):
self.name = name
self.count21 = 0
self.countBusts = 0
self.countNeutral = 0

def new_hand(self, hand):


self.hand = hand

def hit(self, card):


self.hand.hand.append(card)

def has_21(self):
return 21 in self.hand.possible_scores()

def has_busted(self):
return len(self.hand.possible_scores()) == 0

def scores(self):
return self.hand.get_scores() if self.has_busted() else
self.hand.possible_scores()

def __repr__(self):
if self.has_21():
player_str = self.name + " has 21."

elif self.has_busted():
player_str = self.name + " has busted."
else:
player_str = self.name
return "Player: {}\nCards: {}\nScore: {}".format(player_str, self.hand,
self.scores())

if __name__ == "__main__":

for g in range(games):
d = Deck()
p = Player()
p.new_hand(d.deal_hand(dictateCard1=["Seven", "Spades"],
dictateCard2=["Seven", "Clubs"]))
# p.hit(d.deal_card(["Six", "Clubs"]))
de = Player("Dealer")
de.new_hand(d.deal_hand(dictateCard1=["Seven", "Diamonds"]))

p.hit(d.deal_card())

# p.hit(d.deal_card(["Two"]))

# p.hit(d.deal_card(specify=["Two", "Hearts"]))
pScore = int(max(p.scores()))
deScore = int(max(de.scores()))

if pScore < 21:


pCountN += 1
elif pScore == 21:
pCount21 += 1
else:
pCountBusts += 1

labels = "21", "Bust", "Neutral"


pCounts = [pCount21, pCountBusts, pCountN]
print(pCounts)
colors = ['green', 'red', 'blue']
explode = (0.1, 0, 0)

plt.pie(pCounts, explode=explode, labels=labels, colors=colors,


autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')
plt.title("Probability of Outcomes for Player with 7-7, Dealer with 7-X")

plt.show()

You might also like