In this blog post, you will learn how to manually calculate and check poker odds.
The Game of Poker
A deck of cards has a total of 52 cards with four suits, which are hearts, diamonds, clubs, and spades. Each suit has 13 card values, which are the numbers 2-10, Jack, Queen, King, Ace. The ace card can act as a high or low value card.
In the game of poker, 5 cards make up a hand. The following diagram shows what type of hands you can get.

Getting a pair, two pair, three of a kind, and four of a kind are pretty straightforward.
A straight is a sequence of cards that are in increasing order, and the cards can be of different suits. The hand must contain each consecutively increasing card value. For example, the cards, 2,3,4,5,6 is a straight, but the cards 2,5,7,9,10 is not a straight.
A flush is a sequence of cards of the same suit. The cards do not need to be consecutively increasing like a straight. For example, the cards 5, 7, 8, 10, K would be a flush.
A full house is a hand with both three of a kind and a pair.
A straight flush is a hand that is both a flush and a straight at the same time.
A royal flush is a hand that contains the values, 10, J, Q, K, A where the ace counts as a high card.
The Odds of Getting a Pair
Let’s first go over the theory of receiving a hand with a pair in poker. To count the number of ways, we use a combination of combinatorics and the multiplication rule. The first thing we want to do is choose 1 card value of 13 values. Then choose 2 cards from two different suits. Afterwards, we want to choose 3 different card values from the remaining 12 values, and choose each of the three cards from four different suits. The total number of ways to get a pair is then the following:

This number is 1,098,240. To get the odds, we divide the previous number with the total number of ways to choose 5 cards from a deck of 52 cards. The odds turn out to be 42.2569% to get a pair.
The following is the code to simulate the odds of getting a pair:
import random
class Card():
def __init__(self, value, suit):
self._value = value
self._suit = suit
def value(self):
return self._value
def suit(self):
return self._suit
def __str__(self):
return "" + self._suit + str(self._value)
def create_deck():
deck = []
suit = ["H", "D", "S", "C"]
for i in range(13):
for j in range(4):
deck.append(Card(i, suit[j]))
return deck
def shuffle_deck(deck):
random.shuffle(deck)
def draw_hand(deck):
hand = []
for i in range(5):
c = deck.pop()
hand.append(c)
return hand
def print_hand(hand):
print("Hand:", end="")
for c in hand:
print(c, "", end="")
print("")
def has_pair(hand):
# This variable ensures there will be only one
# pair
meta_count = 0
for i in range(5):
# Count the number of cards with
# the same value as the i-th card.
count = 0
for j in range(i+1, 5):
if hand[i].value() == hand[j].value():
count += 1
continue
if count == 1:
meta_count += 1
elif count == 2:
return False
elif count == 3:
return False
return meta_count == 1
def main():
run_count = 100000
pair_count = 0
for x in range(run_count):
deck = create_deck()
shuffle_deck(deck)
hand = draw_hand(deck)
print_hand(hand)
if has_pair(hand):
pair_count += 1
print("Expected Probability: 42.2569%")
print("Simulated Probability: " + str(pair_count/ 100000.0))
if __name__ == "__main__":
main()
The Odds of Getting Three of a Kind
The theory for getting three of a kind is as follows:
From 13 different values, we want to choose one value, then of four suits we want to choose 3 from 4. Then, from 12 remaining values, we want to choose only two more cards and then choose one card from four suits twice.
The count turns out to be the following:

To get the odds, we divide that number by the total number of ways to choose 5 cards from a deck of 52 cards. This turns out to be 2.11285%
The following is the code to simulate the odds of getting three of a kind:
import random
class Card():
def __init__(self, value, suit):
self._value = value
self._suit = suit
def value(self):
return self._value
def suit(self):
return self._suit
def __str__(self):
return "" + self._suit + str(self._value)
def create_deck():
deck = []
suit = ["H", "D", "S", "C"]
for i in range(13):
for j in range(4):
deck.append(Card(i, suit[j]))
return deck
def shuffle_deck(deck):
random.shuffle(deck)
def draw_hand(deck):
hand = []
for i in range(5):
c = deck.pop()
hand.append(c)
return hand
def print_hand(hand):
print("Hand:", end="")
for c in hand:
print(c, "", end="")
print("")
def has_pair(hand):
meta_count = 0
for i in range(5):
count = 0
for j in range(i+1, 5):
if hand[i].value() == hand[j].value():
count += 1
continue
if count == 1:
meta_count += 1
elif count == 2:
return False
elif count == 3:
return False
return meta_count == 1
def three_of_a_kind(hand):
count_map = {}
for c in hand:
if c.value() not in count_map:
count_map[c.value()] = 1
else:
count_map[c.value()] += 1
has_two_of_a_kind = False
has_three_of_a_kind = False
for k in count_map:
if count_map[k] == 2:
has_two_of_a_kind = True
elif count_map[k] == 3:
has_three_of_a_kind = True
return has_three_of_a_kind and not has_two_of_a_kind
def main():
run_count = 100000
three_of_a_kind_count = 0
for x in range(run_count):
deck = create_deck()
shuffle_deck(deck)
hand = draw_hand(deck)
print_hand(hand)
if three_of_a_kind(hand):
three_of_a_kind_count += 1
print("Simulation Probability: " + str(three_of_a_kind_count/ 100000.0))
if __name__ == "__main__":
main()
The Odds of Getting Four of a Kind
The theory for getting four of a kind is as follows:
First, we want to choose 1 card value from 13 possible card values. Second, choose all 4 from 4 different suits. Next we want to multiply that with choosing one card value from 12 remaining values, and then multiply that by choosing 1 suit from 4 suits. This turns out to be the following:

To get the odds, we divide 624 by the total number of ways to choose 5 cards from a 52 card deck. This turns out to be 0.024%
The code to simulate the odds of getting four of a kind is the following:
import random
class Card():
def __init__(self, value, suit):
self._value = value
self._suit = suit
def value(self):
return self._value
def suit(self):
return self._suit
def __str__(self):
return "" + self._suit + str(self._value)
def create_deck():
deck = []
suit = ["H", "D", "S", "C"]
for i in range(13):
for j in range(4):
deck.append(Card(i, suit[j]))
return deck
def shuffle_deck(deck):
random.shuffle(deck)
def draw_hand(deck):
hand = []
for i in range(5):
c = deck.pop()
hand.append(c)
return hand
def print_hand(hand):
print("Hand:", end="")
for c in hand:
print(c, "", end="")
print("")
def has_pair(hand):
meta_count = 0
for i in range(5):
count = 0
for j in range(i+1, 5):
if hand[i].value() == hand[j].value():
count += 1
continue
if count == 1:
meta_count += 1
elif count == 2:
return False
elif count == 3:
return False
return meta_count == 1
def three_of_a_kind(hand):
count_map = {}
for c in hand:
if c.value() not in count_map:
count_map[c.value()] = 1
else:
count_map[c.value()] += 1
has_two_of_a_kind = False
has_three_of_a_kind = False
for k in count_map:
if count_map[k] == 2:
has_two_of_a_kind = True
elif count_map[k] == 3:
has_three_of_a_kind = True
return has_three_of_a_kind and not has_two_of_a_kind
def four_of_a_kind(hand):
count_map = {}
for c in hand:
if c.value() not in count_map:
count_map[c.value()] = 1
else:
count_map[c.value()] += 1
has_four_of_a_kind = False
for k in count_map:
if count_map[k] == 4:
return True
return False
def main():
run_count = 100000
four_of_a_kind_count = 0
for x in range(run_count):
deck = create_deck()
shuffle_deck(deck)
hand = draw_hand(deck)
print_hand(hand)
if four_of_a_kind(hand):
four_of_a_kind_count += 1
print("Simulation Probability: " + str(four_of_a_kind_count/ 100000.0))
if __name__ == "__main__":
main()
The Odds of Getting Flushes, Straights, and Straight Flushes
The theory of getting the flush is the following. There are 13 values to choose from, and we want to choose 5 different values. Then, since all of the cards must be the same suit, it must be that we multiply it by 4 choose 1 since there are a total of four suits and pick one suit. Therefore, the total number of ways to get a flush is the following:

The odds of getting a straight is the following. There are 10 ways to get a sequence (let T stand for 10). A2345, 23456,34567,45678,56789,6789T, 789TJ, 89TJQ, 9TJQK,TJQKA. Next, there are 4 ways to choose the card 5 times each. Therefore, total straight count is the following:

Next, we have to count the number of straight flushes so that we can subtract the count from both of the previous numbers that have been computed. The number of straight flushes will be to multiply 10 (the number of sequences) by four (the total number of suits.)
Therefore, the total number of straights will be 10,240-40 =10,200. The total number of flushes will be 5148-40=5,108. To get the odds divide each number by the total ways to choose 5 cards from a 52 card deck.
The code to simulate each are the following:
import random
class Card():
def __init__(self, value, suit):
self._value = value
self._suit = suit
def value(self):
return self._value
def suit(self):
return self._suit
def __str__(self):
return "" + self._suit + str(self._value)
def create_deck():
deck = []
suit = ["H", "D", "S", "C"]
for i in range(13):
for j in range(4):
deck.append(Card(i, suit[j]))
return deck
def shuffle_deck(deck):
random.shuffle(deck)
def draw_hand(deck):
hand = []
for i in range(5):
c = deck.pop()
hand.append(c)
return hand
def print_hand(hand):
print("Hand:", end="")
for c in hand:
print(c, "", end="")
print("")
def has_pair(hand):
meta_count = 0
for i in range(5):
count = 0
for j in range(i+1, 5):
if hand[i].value() == hand[j].value():
count += 1
continue
if count == 1:
meta_count += 1
elif count == 2:
return False
elif count == 3:
return False
return meta_count == 1
def three_of_a_kind(hand):
count_map = {}
for c in hand:
if c.value() not in count_map:
count_map[c.value()] = 1
else:
count_map[c.value()] += 1
has_two_of_a_kind = False
has_three_of_a_kind = False
for k in count_map:
if count_map[k] == 2:
has_two_of_a_kind = True
elif count_map[k] == 3:
has_three_of_a_kind = True
return has_three_of_a_kind and not has_two_of_a_kind
def four_of_a_kind(hand):
count_map = {}
for c in hand:
if c.value() not in count_map:
count_map[c.value()] = 1
else:
count_map[c.value()] += 1
has_four_of_a_kind = False
for k in count_map:
if count_map[k] == 4:
return True
return False
def has_straight(hand):
# Get the values and sort them
values = sorted([c.value() for c in hand])
# Check for Ace-High straight explicitly: [0, 9, 10, 11, 12]
# (Assuming 0 is Ace, 9 is 10, 10 is J, 11 is Q, 12 is K)
if values == [0, 9, 10, 11, 12]:
return True
if len(set(values)) == 5 and (values[-1] - values[0] == 4):
return True
return False
def flush(hand):
s = hand[0].suit()
for i in range(1, 5):
if s != hand[i].suit():
return False
return True
def main():
run_count = 100000
straight_count = 0
flush_count = 0
straight_flush_count = 0
for x in range(run_count):
deck = create_deck()
shuffle_deck(deck)
hand = draw_hand(deck)
print_hand(hand)
if flush(hand):
flush_count += 1
if has_straight(hand):
straight_count += 1
if flush(hand) and has_straight(hand):
straight_flush_count += 1
print("Simulation Probability Flush: " + str((flush_count - straight_flush_count)/ 100000.0))
print("Simulation Probability Straight: " + str((straight_count - straight_flush_count)/ 100000.0))
print("Simulation Probability Straight Flush: " + str((straight_flush_count)/ 100000.0))
if __name__ == "__main__":
main()
Final Thoughts
The remaining hands are left as exercises for you to compute the probability by hand, and then simulate in python. In this blog post, you learned how to compute the odds of getting certain hands and simulating the odds in Python.
References
Miller, S. J. (2017). The probability Lifesaver: All the tools you need to understand chance. Princeton University Press.