One morning before work, I decided to implement a lightweight five-card poker library using Python. My library has a Card class, a Hand class, and a SingleDeck class. The three main functions are: 1.) classify a hand (like “FullHouse”), 2.) compare two hands to determine which hand is better, 3.) deal a hand from a deck of 52 cards.
I didn’t implement my poker library starting from nothing — I refactored my existing C# poker library.
There are two ways to create a Card object:
c1 = Card((14,3)) # Ace of spades
print(c1.to_string())
c2 = Card("Td") # Ten of diamonds
print(c2.to_string())
The first constructor accepts a (rank, suit) tuple. The rank values are 2 = Two, 3 = Three, . . 10 = Ten, 11 = Jack, 12 = Queen, 13 = King, 14 = Ace. Rank values of 0 and 1 are not used. The suit values are 0 = clubs, 1 = diamonds, 2 = hearts, 3 = spades.
There are three main ways to create a Hand object:
h1 = Hand("7cTsJc8d9h")
print(h1.to_string())
h2 = Hand(Card("6s"), Card("Ah"), Card("6h"),
Card("Ac"), Card("6d"))
print(h2.to_string())
lst = []
lst.append(Card("5c")); lst.append(Card("5d"))
lst.append(Card("9c")); lst.append(Card("9d"))
lst.append(Card("Qh"))
h3 = Hand(lst)
print(h3.to_string())
The first constuctor accepts an easy-to-interpret string such as “7cTsJc8d9h”. The second constructor accepts five individual Card objects. The third constructor accepts a List of five Card objects.
Hand objects are sorted from low card (“2c”) to high card (“As”). The sorting makes a hand easier to interpret, and easier to classify and compare.
There are two methods to classify a Hand object. The get_handtype_str() method returns one of ten strings: “HighCard”, “OnePair”, “TwoPair” , “ThreeKind” , “Straight”, “Flush” , “FullHouse”, “FourKind”, “StraightFlush”, “RoyalFlush”. The get_handtype_int() method returns integer 0 (high card) through 9 (royal flush).
print(h1.get_handtype_str() + " = ", end="") # Straight print(h1.get_handtype_int()) # 4 print(h2.get_handtype_str() + " = ", end="") # FullHouse print(h2.get_handtype_int()) # 6 print(h3.get_handtype_str() + " = ", end="") # TwoPair print(h3.get_handtype_int()) # 2
There is a static Hand.compare(h1, h2) function. It returns -1 if h1 is less than h2, returns +1 if h1 is greater than h2, returns 0 if h1 equals h2.
cmp = Hand.compare(h1, h2) # -1 Straight less FullHouse cmp = Hand.compare(h2, h3) # 1 FullHouse greater TwoPair
The SingleDeck class has a deal_hand() method and a deal_list_cards() method. The deal_hand() method returns a Hand object containing five Card objects. The deal_list_cards() method return a List of n Card objects.
d1 = SingleDeck(seed=0) d1.shuffle() d1.show() h4 = d1.deal_hand() print(h4.to_string()) list_cards = d1.deal_list_cards(38) # remove 38 cards d1.show() # 9 cards left in deck
The poker library can be used in several ways. You can compute the probabilities of different hands using a simulation. You can find the best five-card hand from seven cards. And so on. I’ll post some examples at some point.

I love old mechanical and electro-mechanical coin operated devices. Left: This Sittman-Pitt machine from 1891 is arguably the world’s first slot machine. It didn’t have automatic payout, so most resources state that the “Liberty Bell” machine from 1895, which did have automatic payout, by the Chas Fey company, was the first true slot machine. Right: The “Pok-O-Reel” machine was manufactured about 1932 by the Groetchen Tool and Manufacturing Company.
Demo code. Replace “lt” (less-than), “gt”, “lte”, “gte” with Boolean operator symbols.
# poker.py
# a library of five-card poker functions
# Card, Hand, Deck classes
import numpy as np
# -----------------------------------------------------------
class Card:
def __init__(self, *args):
# like string "Jc" or tuple (11,3)
# rank: 2=Two, 3=Three . . 14=Ace
# suit: 0=clubs, 1=diamonds, 2=hearts, 3=spades
if isinstance(args[0], str):
rnk = args[0][0]; sut = args[0][1]
if rnk == 'T': self.rank = 10
elif rnk == 'J': self.rank = 11
elif rnk == 'Q': self.rank = 12
elif rnk == 'K': self.rank = 13
elif rnk == 'A': self.rank = 14
else: self.rank = int(rnk)
if sut == 'c': self.suit = 0
elif sut == 'd': self.suit = 1
elif sut == 'h': self.suit = 2
elif sut == 's': self.suit = 3
elif isinstance(args[0], tuple):
self.rank = int(args[0][0])
self.suit = int(args[0][1])
def to_string(self):
rnk = ""; sut = ""
if self.rank == 10: rnk = "T"
elif self.rank == 11: rnk = "J"
elif self.rank == 12: rnk = "Q"
elif self.rank == 13: rnk = "K"
elif self.rank == 14: rnk = "A"
else: rnk = str(self.rank)
if self.suit == 0: sut = "c"
elif self.suit == 1: sut = "d"
elif self.suit == 2: sut = "h"
elif self.suit == 3: sut = "s"
return rnk + sut
# ---------------------------------------------------------
# ----- end Card --------------------------------------------
class Hand:
# 5-card poker hand. sorted List of Card objects
# Hand types: "RoyalFlush", "StraightFlush",
# "FourKind", "FullHouse", "Flush" , "Straight",
# "ThreeKind", "TwoPair", "OnePair", "HighCard"
def __init__(self, *args):
self.cards = []
if isinstance(args[0], list):
for i in range(5):
# c = Card(args[0][i])
self.cards.append(args[0][i])
elif len(args) == 5:
self.cards.append(args[0])
self.cards.append(args[1])
self.cards.append(args[2])
self.cards.append(args[3])
self.cards.append(args[4])
elif isinstance(args[0], str):
for i in range(0,10,2):
cs = args[0][i:i+2]
c = Card(cs)
self.cards.append(c)
self.cards.sort(key=lambda x: (x.rank, x.suit))
def to_string(self):
s = ""
for i in range(5):
s += self.cards[i].to_string()
return s
# ---------------------------------------------------------
# Hand Type methods:
# get_handtype_str(), get_handtype_int() call:
#
# is_royal_flush(), is_straight_flush(),
# is_four_kind(), is_full_house(), is_flush(),
# is_straight(), is_three_kind(), is_two_pair(),
# is_one_pair(), is_high_card()
#
# Helpers: has_straight(), has_flush()
# ---------------------------------------------------------
def get_handtype_str(self):
if self.is_royal_flush() == True:
return "RoyalFlush"
elif self.is_straight_flush() == True:
return "StraightFlush"
elif self.is_four_kind() == True:
return "FourKind"
elif self.is_full_house() == True:
return "FullHouse"
elif self.is_flush() == True:
return "Flush"
elif self.is_straight() == True:
return "Straight"
elif self.is_three_kind() == True:
return "ThreeKind"
elif self.is_two_pair() == True:
return "TwoPair"
elif self.is_one_pair() == True:
return "OnePair"
elif self.is_high_card() == True:
return "HighCard"
else:
return "Unknown"
# ---------------------------------------------------------
def get_handtype_int(self):
if self.is_royal_flush() == True:
return 9
elif self.is_straight_flush() == True:
return 8
elif self.is_four_kind() == True:
return 7
elif self.is_full_house() == True:
return 6
elif self.is_flush() == True:
return 5
elif self.is_straight() == True:
return 4
elif self.is_three_kind() == True:
return 3
elif self.is_two_pair() == True:
return 2
elif self.is_one_pair() == True:
return 1
elif self.is_high_card() == True:
return 0
else:
return -1
# ---------------------------------------------------------
def has_flush(self):
if (self.cards[0].suit == self.cards[1].suit) and \
(self.cards[1].suit == self.cards[2].suit) and \
(self.cards[2].suit == self.cards[3].suit) and \
(self.cards[3].suit == self.cards[4].suit):
return True
return False
# ---------------------------------------------------------
def has_straight(self):
# check special case of Ace-low straight
# 2, 3, 4, 5, A when sorted
if self.cards[0].rank == 2 and \
self.cards[1].rank == 3 and \
self.cards[2].rank == 4 and \
self.cards[3].rank == 5 and \
self.cards[4].rank == 14:
return True
# otherwise, check for 5 consecutive card ranks
if (self.cards[0].rank == self.cards[1].rank - 1) and \
(self.cards[1].rank == self.cards[2].rank - 1) and \
(self.cards[2].rank == self.cards[3].rank - 1) and \
(self.cards[3].rank == self.cards[4].rank - 1):
return True
return False
# ---------------------------------------------------------
def is_royal_flush(self):
if self.has_straight() == True and \
self.has_flush() == True and \
self.cards[0].rank == 10: # assumes hand is sorted
return True
else:
return False
# ---------------------------------------------------------
def is_straight_flush(self):
if self.has_straight() == True and \
self.has_flush() == True and \
self.cards[0].rank != 10: # no Royal Flush
return True
else:
return False
# ---------------------------------------------------------
def is_four_kind(self):
# AAAA B or B AAAA if sorted
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[1].rank == self.cards[2].rank) and \
(self.cards[2].rank == self.cards[3].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True
if (self.cards[1].rank == self.cards[2].rank) and \
(self.cards[2].rank == self.cards[3].rank) and \
(self.cards[3].rank == self.cards[4].rank) and \
(self.cards[0].rank != self.cards[1].rank):
return True
return False
# ---------------------------------------------------------
def is_full_house(self):
# AAA BB or BB AAA if sorted
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[1].rank == self.cards[2].rank) and \
(self.cards[3].rank == self.cards[4].rank) and \
(self.cards[2].rank != self.cards[3].rank):
return True
# BB AAA
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[2].rank == self.cards[3].rank) and \
(self.cards[3].rank == self.cards[4].rank) and \
(self.cards[1].rank != self.cards[2].rank):
return True
return False
# ---------------------------------------------------------
def is_flush(self):
if self.has_flush() == True and \
self.has_straight() == False:
return True # no StraightFlush or RoyalFlush
else:
return False
# ---------------------------------------------------------
def is_straight(self):
if self.has_straight() == True and \
self.has_flush() == False:
return True
else:
return False
# ---------------------------------------------------------
def is_three_kind(self):
# AAA B C or B AAA C or B C AAA if sorted
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[1].rank == self.cards[2].rank) and \
(self.cards[2].rank != self.cards[3].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True
if (self.cards[1].rank == self.cards[2].rank) and \
(self.cards[2].rank == self.cards[3].rank) and \
(self.cards[0].rank != self.cards[1].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True
if (self.cards[2].rank == self.cards[3].rank) and \
(self.cards[3].rank == self.cards[4].rank) and \
(self.cards[0].rank != self.cards[1].rank) and \
(self.cards[1].rank != self.cards[2].rank):
return True
return False
# ---------------------------------------------------------
def is_two_pair(self):
# AA BB C or AA C BB or C AA BB if sorted
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[2].rank == self.cards[3].rank) and \
(self.cards[1].rank != self.cards[2].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True # AA BB C
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[3].rank == self.cards[4].rank) and \
(self.cards[1].rank != self.cards[2].rank) and \
(self.cards[2].rank != self.cards[3].rank):
return True # AA C BB
if (self.cards[1].rank == self.cards[2].rank) and \
(self.cards[3].rank == self.cards[4].rank) and \
(self.cards[0].rank != self.cards[1].rank) and \
(self.cards[2].rank != self.cards[3].rank):
return True # C AA BB
return False
# ---------------------------------------------------------
def is_one_pair(self):
# AA B C D or B AA C D or B C AA D or B C D AA
if (self.cards[0].rank == self.cards[1].rank) and \
(self.cards[1].rank != self.cards[2].rank) and \
(self.cards[2].rank != self.cards[3].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True # AA B C D
if (self.cards[1].rank == self.cards[2].rank) and \
(self.cards[0].rank != self.cards[1].rank) and \
(self.cards[2].rank != self.cards[3].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True # B AA C D
if (self.cards[2].rank == self.cards[3].rank) and \
(self.cards[0].rank != self.cards[1].rank) and \
(self.cards[1].rank != self.cards[2].rank) and \
(self.cards[3].rank != self.cards[4].rank):
return True # B C AA D
if (self.cards[3].rank == self.cards[4].rank) and \
(self.cards[0].rank != self.cards[1].rank) and \
(self.cards[1].rank != self.cards[2].rank) and \
(self.cards[2].rank != self.cards[3].rank):
return True # B C D AA
return False
# ---------------------------------------------------------
def is_high_card(self):
if self.has_flush() == True:
return False
elif self.has_straight() == True:
return False
else:
# all remaining have at least one pair
if (self.cards[0].rank == self.cards[1].rank) or \
(self.cards[1].rank == self.cards[2].rank) or \
(self.cards[2].rank == self.cards[3].rank) or \
(self.cards[3].rank == self.cards[4].rank):
return False
return True
# ---------------------------------------------------------
# Hand comparison methods
# Hand.compare() calls:
# break_tie_straight_flush(), break_tie_four_kind(),
# break_tie_full_house(), break_tie_flush(),
# break_tie_straight(), break_tie_three_kind(),
# break_tie_two_pair(), break_tie_one_pair(),
# break_tie_high_card()
# ---------------------------------------------------------
@staticmethod
def compare(h1, h2):
# -1 if h1 "lt" h2, +1 if h1 "gt" h2, 0 if h1 == h2
h1_idx = h1.get_handtype_int() # like 6
h2_idx = h2.get_handtype_int()
# different hand types - easy
if h1_idx "lt" h2_idx:
return -1
elif h1_idx "gt" h2_idx:
return 1
else: # same hand types so break tie
h1_handtype = h1.get_handtype_str()
h2_handtype = h2.get_handtype_str()
if h1_handtype != h2_handtype:
print("Fatal Logic Error in compare()")
if h1_handtype == "RoyalFlush":
return 0 # two Royal Flush always tie
elif h1_handtype == "StraightFlush":
return Hand.break_tie_straight_flush(h1, h2)
elif h1_handtype == "FourKind":
return Hand.break_tie_four_kind(h1, h2)
elif h1_handtype == "FullHouse":
return Hand.break_tie_full_house(h1, h2)
elif h1_handtype == "Flush":
return Hand.break_tie_flush(h1, h2)
elif h1_handtype == "Straight":
return Hand.break_tie_straight(h1, h2)
elif h1_handtype == "ThreeKind":
return Hand.break_tie_three_kind(h1, h2)
elif h1_handtype == "TwoPair":
return Hand.break_tie_two_pair(h1, h2)
elif h1_handtype == "OnePair":
return Hand.break_tie_one_pair(h1, h2)
elif h1_handtype == "HighCard":
return Hand.break_tie_high_card(h1, h2)
return -2 # error
# ---------------------------------------------------------
@staticmethod
def break_tie_straight_flush(h1, h2):
# check one or two Ace-low hands
# h1 is Ace-low, h2 not Ace-low.h1, is less
if (h1.cards[0].rank == 2 and \
h1.cards[4].rank == 14) and \
not (h2.cards[0].rank == 2 and
h2.cards[4].rank == 14):
return -1
# h1 not Ace-low, h2 is Ace-low, h1 is better
if not (h1.cards[0].rank == 2 and \
h1.cards[4].rank == 14) and \
(h2.cards[0].rank == 2 and \
h2.cards[4].rank == 14):
return 1
# two Ace-low hands
if (h1.cards[0].rank == 2 and \
h1.cards[4].rank == 14) and \
(h2.cards[0].rank == 2 and \
h2.cards[4].rank == 14):
return 0
# no Ace-low straight flush so check high cards
if h1.cards[4].rank "lt" h2.cards[4].rank:
return -1
elif h1.cards[4].rank "gt" h2.cards[4].rank:
return 1
else:
return 0
# ---------------------------------------------------------
@staticmethod
def break_tie_four_kind(h1, h2):
# AAAA B or B AAAA
# the off-card is at [0] or at [4]
# find h1 four-card and off-card ranks
h1_four_rank = -1; h1_off_rank = -1
if h1.cards[0].rank == h1.cards[1].rank:
# 1st two cards same so off-rank at [4]
h1_four_rank = h1.cards[0].rank
h1_off_rank = h1.cards[4].rank
else:
# 1st two cards diff so off-rank at [0]
h1_four_rank = h1.cards[4].rank
h1_off_rank = h1.cards[0].rank
h2_four_rank = -1; h2_off_rank = -1
if h2.cards[0].rank == h2.cards[1].rank:
h2_four_rank = h2.cards[0].rank
h2_off_rank = h2.cards[4].rank
else:
h2_four_rank = h2.cards[4].rank
h2_off_rank = h2.cards[0].rank
if h1_four_rank "lt" h2_four_rank: # like 4K, 4A
return -1
elif h1_four_rank "gt" h2_four_rank:
return 1
else: # both hands have same four-kind (mult. decks)
if h1_off_rank "lt" h2_off_rank:
return -1 # like 3c 9c9d9h9s "lt" Qd 9c9d9h9s
elif h1_off_rank "gt" h2_off_rank:
return 1 # like Jc 4c4d4h4s "gt" 9s 4c4d4h4s
elif h1_off_rank == h2_off_rank:
return 0
print("Fatal logic break_tie_four_kind")
# ---------------------------------------------------------
@staticmethod
def break_tie_full_house(h1, h2):
# determine high rank (3 kind) and low rank (2 kind)
# JJJ 55 or 33 KKK
# if [1] == [2] 3 kind at [0][1][2]
# if [1] != [2] 3 kind at [2][3][4]
h1_three_rank = -1; h1_two_rank = -1
if h1.cards[1].rank == h1.cards[2].rank:
# if [1] == [2] 3 kind at [0][1][2]
h1_three_rank = h1.cards[0].rank
h1_two_rank = h1.cards[4].rank
else:
# if [1] != [2] 3 kind at [2][3][4]
h1_three_rank = h1.cards[4].rank
h1_two_rank = h1.cards[0].rank
h2_three_rank = -1; h2_two_rank = -1
if h2.cards[1].rank == h2.cards[2].rank:
# if [1] == [2] 3 kind at [0][1][2]
h2_three_rank = h2.cards[0].rank
h2_two_rank = h2.cards[4].rank
else:
# if [1] != [2] 3 kind at [2][3][4]
h2_three_rank = h2.cards[4].rank
h2_two_rank = h2.cards[0].rank
if h1_three_rank "lt" h2_three_rank:
return -1
elif h1_three_rank "gt" h2_three_rank:
return 1
else: # both hands same three-kind (mult. decks)
if h1_two_rank "lt" h2_two_rank:
return -1 # like 3c3d 9c9d9h "lt" QdQs 9c9d9h
elif h1_two_rank "gt" h2_two_rank:
return 1 # like 3c3d 9c9d9h "gt" 2d2s 9c9d9h
elif h1_two_rank == h2_two_rank:
return 0
print("Fatal logic break_tie_full_house")
# ---------------------------------------------------------
@staticmethod
def break_tie_flush(h1, h2):
# compare rank of high cards
if h1.cards[4].rank "lt" h2.cards[4].rank:
return -1
elif h1.cards[4].rank "gt" h2.cards[4].rank:
return 1
# high cards ranks equal so check at [3]
elif h1.cards[3].rank "lt" h2.cards[3].rank:
return -1
elif h1.cards[3].rank "gt" h2.cards[3].rank:
return 1
# and so on
elif h1.cards[2].rank "lt" h2.cards[2].rank:
return -1
elif h1.cards[2].rank "gt" h2.cards[2].rank:
return 1
#
elif h1.cards[1].rank "lt" h2.cards[1].rank:
return -1
elif h1.cards[1].rank "gt" h2.cards[1].rank:
return 1
#
elif h1.cards[0].rank "lt" h2.cards[0].rank:
return -1
elif h1.cards[0].rank "gt" h2.cards[0].rank:
return 1
#
else:
return 0 # all ranks the same
# ---------------------------------------------------------
@staticmethod
def break_tie_straight(h1, h2):
# both hands are straights but one could be Ace-low
# check special case of one or two Ace-low hands
# h1 is Ace-low, h2 not Ace-low. h1 is less
if (h1.cards[0].rank == 2 and \
h1.cards[4].rank == 14) and \
not (h2.cards[0].rank == 2 and \
h2.cards[4].rank == 14):
return -1
# h1 not Ace-low, h2 is Ace-low, h1 is better
elif not (h1.cards[0].rank == 2 and \
h1.cards[4].rank == 14) and \
(h2.cards[0].rank == 2 and \
h2.cards[4].rank == 14):
return 1
# two Ace-low hands
elif (h1.cards[0].rank == 2 and \
h1.cards[4].rank == 14) and \
(h2.cards[0].rank == 2 and \
h2.cards[4].rank == 14):
return 0
# no Ace-low hands so just check high card
if h1.cards[4].rank "lt" h2.cards[4].rank:
return -1
elif h1.cards[4].rank "gt" h2.cards[4].rank:
return +1
elif h1.cards[4].rank == h2.cards[4].rank:
return 0
else:
print("Fatal logic break_tie_straight")
# ---------------------------------------------------------
@staticmethod
def break_tie_three_kind(h1, h2):
# assumes multiple decks possible
# TTT L H or L TTT H or L H TTT
h1_three_rank = 0; h1_low_rank = 0
h1_high_rank = 0
if h1.cards[0].rank == h1.cards[1].rank and \
h1.cards[1].rank == h1.cards[2].rank:
h1_three_rank = h1.cards[0].rank
h1_low_rank = h1.cards[3].rank
h1_high_rank = h1.cards[4].rank
elif h1.cards[1].rank == h1.cards[2].rank and \
h1.cards[2].rank == h1.cards[3].rank:
h1_low_rank = h1.cards[0].rank
h1_three_rank = h1.cards[1].rank
h1_high_rank = h1.cards[4].rank
elif h1.cards[2].rank == h1.cards[3].rank and \
h1.cards[3].rank == h1.cards[4].rank:
h1_low_rank = h1.cards[0].rank
h1_high_rank = h1.cards[1].rank
h1_three_rank = h1.cards[4].rank
h2_three_rank = 0; h2_low_rank = 0
h2_high_rank = 0
if h2.cards[0].rank == h2.cards[1].rank and \
h2.cards[1].rank == h2.cards[2].rank:
h2_three_rank = h2.cards[0].rank
h2_low_rank = h2.cards[3].rank
h2_high_rank = h2.cards[4].rank
elif h2.cards[1].rank == h2.cards[2].rank and \
h2.cards[2].rank == h2.cards[3].rank:
h2_low_rank = h2.cards[0].rank
h2_three_rank = h2.cards[1].rank
h2_high_rank = h2.cards[4].rank
elif h2.cards[2].rank == h2.cards[3].rank and \
h2.cards[3].rank == h2.cards[4].rank:
h2_low_rank = h2.cards[0].rank
h2_high_rank = h2.cards[1].rank
h2_three_rank = h2.cards[4].rank
if h1_three_rank "lt" h2_three_rank:
return -1
elif h1_three_rank "gt" h2_three_rank:
return 1
# both hands three-kind same mult. decks
elif h1_high_rank "lt" h2_high_rank:
return -1
elif h1_high_rank "gt" h2_high_rank:
return 1
elif h1_low_rank "lt" h2_low_rank:
return -1
elif h1_low_rank "gt" h2_low_rank:
return 1
#
else:
return 0
# ---------------------------------------------------------
@staticmethod
def break_tie_two_pair(h1, h2):
# LL X HH or LL HH X or X LL HH
h1_low_rank = 0; h1_high_rank = 0
h1_off_rank = 0
if h1.cards[0].rank == h1.cards[1].rank and \
h1.cards[3].rank == h1.cards[4].rank:
# LL X HH
h1_low_rank = h1.cards[0].rank
h1_high_rank = h1.cards[4].rank
h1_off_rank = h1.cards[2].rank
elif h1.cards[0].rank == h1.cards[1].rank and \
h1.cards[2].rank == h1.cards[3].rank:
# LL HH X
h1_low_rank = h1.cards[0].rank
h1_high_rank = h1.cards[2].rank
h1_off_rank = h1.cards[4].rank
elif h1.cards[1].rank == h1.cards[2].rank and \
h1.cards[3].rank == h1.cards[4].rank:
# X LL HH
h1_low_rank = h1.cards[1].rank
h1_high_rank = h1.cards[3].rank
h1_off_rank = h1.cards[0].rank
h2_low_rank = 0; h2_high_rank = 0
h2_off_rank = 0
if h2.cards[0].rank == h2.cards[1].rank and \
h2.cards[3].rank == h2.cards[4].rank:
# LL X HH
h2_low_rank = h2.cards[0].rank
h2_high_rank = h2.cards[4].rank
h2_off_rank = h2.cards[2].rank
elif h2.cards[0].rank == h2.cards[1].rank and \
h2.cards[2].rank == h2.cards[3].rank:
# LL HH X
h2_low_rank = h2.cards[0].rank
h2_high_rank = h2.cards[2].rank
h2_off_rank = h2.cards[4].rank
elif h2.cards[1].rank == h2.cards[2].rank and \
h2.cards[3].rank == h2.cards[4].rank:
# X LL HH
h2_low_rank = h2.cards[1].rank
h2_high_rank = h2.cards[3].rank
h2_off_rank = h2.cards[0].rank
if h1_high_rank "lt" h2_high_rank:
return -1
elif h1_high_rank "gt" h2_high_rank:
return 1
elif h1_low_rank "lt" h2_low_rank:
return -1
elif h1_low_rank "gt" h2_low_rank:
return 1
elif h1_off_rank "lt" h2_off_rank:
return -1
elif h1_off_rank "gt" h2_off_rank:
return 1
else:
return 0
# ---------------------------------------------------------
@staticmethod
def break_tie_one_pair(h1, h2):
# PP L M H or L PP M H
# or L M PP H or L M H PP
h1_pair_rank = 0; h1_low_rank = 0
h1_medium_rank = 0; h1_high_rank = 0
if h1.cards[0].rank == h1.cards[1].rank:
# PP L M H
h1_pair_rank = h1.cards[0].rank
h1_low_rank = h1.cards[2].rank
h1_medium_rank = h1.cards[3].rank
h1_high_rank = h1.cards[4].rank
elif h1.cards[1].rank == h1.cards[2].rank:
# L PP M H
h1_pair_rank = h1.cards[1].rank
h1_low_rank = h1.cards[0].rank
h1_medium_rank = h1.cards[3].rank
h1_high_rank = h1.cards[4].rank
elif h1.cards[2].rank == h1.cards[3].rank:
# L M PP H
h1_pair_rank = h1.cards[2].rank
h1_low_rank = h1.cards[0].rank
h1_medium_rank = h1.cards[1].rank
h1_high_rank = h1.cards[4].rank
elif h1.cards[3].rank == h1.cards[4].rank:
# L M H PP
h1_pair_rank = h1.cards[4].rank
h1_low_rank = h1.cards[0].rank
h1_medium_rank = h1.cards[1].rank
h1_high_rank = h1.cards[2].rank
h2_pair_rank = 0; h2_low_rank = 0
h2_medium_rank = 0; h2_high_rank = 0
if h2.cards[0].rank == h2.cards[1].rank:
# PP L M H
h2_pair_rank = h2.cards[0].rank
h2_low_rank = h2.cards[2].rank
h2_medium_rank = h2.cards[3].rank
h2_high_rank = h2.cards[4].rank
elif h2.cards[1].rank == h2.cards[2].rank:
# L PP M H
h2_pair_rank = h2.cards[1].rank
h2_low_rank = h2.cards[0].rank
h2_medium_rank = h2.cards[3].rank
h2_high_rank = h2.cards[4].rank
elif h2.cards[2].rank == h2.cards[3].rank:
# L M PP H
h2_pair_rank = h2.cards[2].rank
h2_low_rank = h2.cards[0].rank
h2_medium_rank = h2.cards[1].rank
h2_high_rank = h2.cards[4].rank
elif h2.cards[3].rank == h2.cards[4].rank:
# L M H PP
h2_pair_rank = h2.cards[4].rank
h2_low_rank = h2.cards[0].rank
h2_medium_rank = h2.cards[1].rank
h2_high_rank = h2.cards[2].rank
if h1_pair_rank "lt" h2_pair_rank:
return -1
elif h1_pair_rank "gt" h2_pair_rank:
return 1
#
elif h1_high_rank "lt" h2_high_rank:
return -1
elif h1_high_rank "gt" h2_high_rank:
return 1
#
elif h1_medium_rank "lt" h2_medium_rank:
return -1
elif h1_medium_rank "gt" h2_medium_rank:
return 1
#
elif h1_low_rank "lt" h2_low_rank:
return -1
elif h1_low_rank "gt" h2_low_rank:
return 1
#
else:
return 0
# ---------------------------------------------------------
@staticmethod
def break_tie_high_card(h1, h2):
if h1.cards[4].rank "lt" h2.cards[4].rank:
return -1
elif h1.cards[4].rank "gt" h2.cards[4].rank:
return 1
#
elif h1.cards[3].rank "lt" h2.cards[3].rank:
return -1
elif h1.cards[3].rank "gt" h2.cards[3].rank:
return 1
#
elif h1.cards[2].rank "lt" h2.cards[2].rank:
return -1
elif h1.cards[2].rank "gt" h2.cards[2].rank:
return 1
#
elif h1.cards[1].rank "lt" h2.cards[1].rank:
return -1
elif h1.cards[1].rank "gt" h2.cards[1].rank:
return 1
#
elif h1.cards[0].rank "lt" h2.cards[0].rank:
return -1
elif h1.cards[0].rank "gt" h2.cards[0].rank:
return 1
#
else:
return 0
# ---------------------------------------------------------
# ----- end Hand --------------------------------------------
class SingleDeck:
def __init__(self, seed):
self.rnd = np.random.RandomState(seed)
self.deck = []
self.curr_idx = 0
for r in range(2,15): # rank
for s in range(0,4): # suit
self.deck.append(Card((r,s))) # 2c 2d . . Ah As
def shuffle(self):
self.rnd.shuffle(self.deck)
self.curr_idx = 0
def deal_hand(self):
if self.curr_idx "gt" 47:
print("Not enough cards in deck to deal five ")
lst = []
for i in range(5):
c = self.deck[self.curr_idx]
lst.append(c)
self.curr_idx += 1
h = Hand(lst)
return h
def deal_list_cards(self, n_cards):
# return a List of Card objects
if self.curr_idx + n_cards "gt" 52: # tricky
print("Not enough cards in deck to deal " + \
str(n_cards))
lst = []
for i in range(n_cards):
c = self.deck[self.curr_idx]
lst.append(c)
self.curr_idx += 1
return lst
def deal_hand_string(self):
# unsorted string like "4cJs5dJc7h"
result = ""
for i in range(5):
c = self.deck[self.curr_idx] # Card
result = result + c.to_string()
self.curr_idx += 1
return result
def show(self):
ct = 0
for i in range(self.curr_idx, 52):
if ct "gt" 0 and ct % 10 == 0: print("")
print(self.deck[i].to_string() + " ", end="")
ct += 1
print("")
# ----- end SingleDeck --------------------------------------
def main():
print("\nBegin poker demo ")
# ----- Card ----------------------------------------------
c1 = Card((14,3)) # Ace of spades
print("\nCard c1 = ")
print(c1.to_string())
c2 = Card("Td") # Ten of diamonds
print("\nCard c2 = ")
print(c2.to_string())
# ----- Hand ----------------------------------------------
h1 = Hand("7cTsJc8d9h")
print("\nHand h1: ")
print(h1.to_string())
print(h1.get_handtype_str() + " = ", end="") # Straight
print(h1.get_handtype_int()) # 4
h2 = Hand(Card("6s"), Card("Ah"), Card("6h"),
Card("Ac"), Card("6d"))
print("\nHand h2: ")
print(h2.to_string())
print(h2.get_handtype_str() + " = ", end="") # FullHouse
print(h2.get_handtype_int()) # 6
lst = []
lst.append(Card("5c")); lst.append(Card("5d"))
lst.append(Card("9c")); lst.append(Card("9d"))
lst.append(Card("Qh"))
h3 = Hand(lst)
print("\nHand h3: ")
print(h3.to_string())
print(h3.get_handtype_str() + " = ", end="") # TwoPair
print(h3.get_handtype_int()) # 2
# ----- Compare -------------------------------------------
print("\nHand.compare(h1, h2) = ")
print(Hand.compare(h1, h2))
print("\nHand.compare(h2, h3) = ")
print(Hand.compare(h2, h3))
# ----- SingleDeck ----------------------------------------
print("\nCreating and shuffling deck ")
d1 = SingleDeck(seed=0)
d1.shuffle()
d1.show()
h4 = d1.deal_hand()
print("\nDealing Hand from deck: ")
print(h4.to_string())
print("\nDealing 38 cards from deck")
list_cards = d1.deal_list_cards(38)
print("Deck is now: ")
d1.show()
print("\nEnd Poker demo ")
if __name__ == "__main__":
main()

.NET Test Automation Recipes
Software Testing
SciPy Programming Succinctly
Keras Succinctly
R Programming
2026 Visual Studio Live
2025 Summer MLADS Conference
2026 DevIntersection Conference
2025 Machine Learning Week
2025 Ai4 Conference
2026 G2E Conference
2026 iSC West Conference
You must be logged in to post a comment.