Function Repository Resource:

BestPokerHand

Source Notebook

Find the strongest possible hole cards in a game of Texas hold 'em poker

Contributed by: Joseph Brennan

ResourceFunction["BestPokerHand"][cards]

computes the strongest possible hole cards in a game of poker, given a list of community cards.

ResourceFunction["BestPokerHand"][cards, n]

computes the n strongest hole cards in a game of poker, given a list of community cards.

Details and Options

BestPokerHand assumes a standard 52-card deck which comprises 13 ranks in each of the four suits.
BestPokerHand requires that cards is a list of (no more than 5) strings representing individual playing cards. For example, {"T♣", "Q♢", "7♡","A♠"} indicates {Ten of Clubs, Queen of Diamonds, Seven of Hearts, Ace of Spades}. Obtain the suit symbols using character names found here.
BestPokerHand returns lists containing two strings representing a player's hole card(s). If many different combinations of hole cards give the same hand strength, the lists are separated by Or (||) operators.
Rules for Texas Hold 'em can be found at this link: https://en.wikipedia.org/wiki/Texas_hold_ %27 em
Hands are ranked according to the following (from weakest to strongest): High Card, One Pair, Two Pairs, Three-of-a-kind, Straight, Flush, Full House, Four-of-a-kind and Straight Flush.
BestPokerHand does not take into account probabilities of 'making a hand', also known as 'outs'.

Examples

Basic Examples (4) 

When the first card on the flop is 4♢ the best hole cards are any other pair of 4s, which are treated as equally strong:

In[1]:=
ResourceFunction["BestPokerHand"][{"4\[DiamondSuit]"}]
Out[1]=

When no cards have yet been dealt, the best hole cards are 'Pocket Aces':

In[2]:=
ResourceFunction["BestPokerHand"][{}]
Out[2]=

Find the 10 best hole card combinations for a flop of K♡, 8♢, 5♠:

In[3]:=
ResourceFunction[
  "BestPokerHand"][{"K\[HeartSuit]", "8\[DiamondSuit]", "5\[SpadeSuit]"}, 10] // Column
Out[3]=

The many different full houses resulting from a 'wet board' (a board that can make many different strong hands) are ranked :

In[4]:=
ResourceFunction[
  "BestPokerHand"][{"Q\[ClubSuit]", "T\[HeartSuit]", "Q\[HeartSuit]", "8\[SpadeSuit]"}, 8] // Column
Out[4]=

The elusive royal flush:

In[5]:=
ResourceFunction[
 "BestPokerHand"][{"J\[DiamondSuit]", "Q\[DiamondSuit]", "A\[DiamondSuit]"}]
Out[5]=

Scope (3) 

If the community card list has two or fewer cards, then straights, flushes, or full houses cannot be constructed. Here, the top-ranked hole cards result in three-of-a-kind, followed by two-pair, followed by one-pair:

In[6]:=
ResourceFunction["BestPokerHand"][{"9\[DiamondSuit]", "3\[HeartSuit]"},
   20] // Column
Out[6]=

An Ace-to-5 straight (also known as the "wheel") is treated as weaker than a 2-to-6 straight, since Ace is 'low' here:

In[7]:=
ResourceFunction[
  "BestPokerHand"][{"4\[DiamondSuit]", "5\[SpadeSuit]", "2\[ClubSuit]"},
   15] // Column
Out[7]=

A straight flush beats an Ace-high flush:

In[8]:=
ResourceFunction[
  "BestPokerHand"][{"9\[HeartSuit]", "7\[HeartSuit]", "T\[HeartSuit]"},
   10] // Column
Out[8]=

Options (2) 

Setting the option "ShowGraphic" → True calls PlayingCardGraphic:

In[9]:=
ResourceFunction[
 "BestPokerHand"][{"7\[ClubSuit]", "5\[ClubSuit]", "J\[HeartSuit]", "T\[ClubSuit]", "9\[SpadeSuit]"}, "ShowGraphic" -> True]
Out[9]=

The graphics are returned in the same format as the lists:

In[10]:=
ResourceFunction[
 "BestPokerHand"][{"A\[HeartSuit]", "2\[HeartSuit]", "3\[HeartSuit]"}, 2, "ShowGraphic" -> True]
Out[10]=
In[11]:=
ResourceFunction[
  "BestPokerHand"][{"T\[DiamondSuit]", "9\[HeartSuit]", "2\[ClubSuit]"},
   4, "ShowGraphic" -> True] // Column
Out[11]=

Applications (2) 

If four cards are already on the table, we technically only need to use one of our hole cards to make a complete five-card hand. The 14th strongest entry (A♣/♡/♠) represents this. This is usually referred to as "Ace-X". Weaker hole card combinations such as {A♣/♡/♠, 8♣/♢/♡/♠} are included since swapping the 9♣ for 8♣/♡/♠ actively makes the hand 'weaker'. It is also worth noting that for this example, {Q♣/♢/♡/♠, J♣/♢/♡/♠} makes two distinct straights: T-to-A and 9-to-K. However, only the strongest-performing instance of a given hole card combination is used in the final ranking, so {Q♣/♢/♡/♠, J♣/♢/♡/♠} appears at the first position rather than both the first and second position:

In[12]:=
ResourceFunction[
  "BestPokerHand"][{"9\[ClubSuit]", "T\[ClubSuit]", "A\[DiamondSuit]",
    "K\[DiamondSuit]"}, 15] // Column
Out[12]=

If all five cards have been dealt, all possible combinations of using zero, one, or both hole cards are checked and ranked. Therefore, it takes a couple of minutes to run. The 29th strongest entry here includes an empty list, representing not using hole cards at all! This means that the five community cards alone would beat any hands made using hole cards below 29th position. This is clear if one looks at the hands below 29th position and recognizes that they represent swapping Q♣ on the board with a lower-ranked card:

In[13]:=
ResourceFunction[
  "BestPokerHand"][{"Q\[ClubSuit]", "K\[HeartSuit]", "A\[ClubSuit]", "K\[DiamondSuit]", "A\[SpadeSuit]"}, 32] // Column
Out[13]=

Properties and Relations (2) 

Use a Take-like specification to find the 4th-9th strongest hole cards:

In[14]:=
ResourceFunction[
  "BestPokerHand"][{"4\[DiamondSuit]", "5\[SpadeSuit]", "3\[HeartSuit]"}, {4, 9}] // Column
Out[14]=

Alternatively, find the weakest possible hole cards:

In[15]:=
ResourceFunction[
 "BestPokerHand"][{"4\[DiamondSuit]", "5\[SpadeSuit]", "3\[HeartSuit]"}, -1, "ShowGraphic" -> True]
Out[15]=

Possible Issues (3) 

The number of cards in the input must not exceed five:

In[16]:=
ResourceFunction[
 "BestPokerHand"][{"3\[ClubSuit]", "3\[DiamondSuit]", "4\[ClubSuit]", "4\[DiamondSuit]", "5\[ClubSuit]", "5\[DiamondSuit]"}]

If there are repeated instances of a given card, it is flagged as invalid since a poker game typically uses a single deck:

In[17]:=
ResourceFunction[
 "BestPokerHand"][{"9\[SpadeSuit]", "9\[HeartSuit]", "5\[HeartSuit]", "5\[HeartSuit]"}, 5]

An error is flagged for invalid ranks or suits:

In[18]:=
ResourceFunction[
 "BestPokerHand"][{"J\[HeartSuit]", "Kx", "3\[SpadeSuit]"}]
In[19]:=
ResourceFunction[
 "BestPokerHand"][{"J\[HeartSuit]", "K\[ClubSuit]", "0\[SpadeSuit]"}]

Neat Examples (5) 

In the 2006 film Casino Royale, there is a now famous Texas hold 'em poker scene in which four players miraculously have very strong hands, resulting in a $115 million pot. We can use this function to explore their relative strength.
First, we note the hole cards that each player held:

In[20]:=
players = <|"Fukutu" -> {"K\[SpadeSuit]", "Q\[SpadeSuit]"}, "Infante" -> {"8\[ClubSuit]", "8\[HeartSuit]"}, "LeChiffre" -> {"A\[ClubSuit]", "6\[HeartSuit]"}, "Bond" -> {"7\[SpadeSuit]", "5\[SpadeSuit]"}|>;

We also need the five cards that were on the table:

In[21]:=
tableCards = {"A\[HeartSuit]", "8\[SpadeSuit]", "6\[SpadeSuit]", "4\[SpadeSuit]", "A\[SpadeSuit]"};

It would be difficult to know exactly how many unique rankings there are, so we can use Span (;;):

In[22]:=
allHoleCardsRanked = ResourceFunction["BestPokerHand"][tableCards, 1 ;;];

Finally, we find the position within this ranked list of our players' hands:

In[23]:=
Sort[
 AssociationMap[Position[allHoleCardsRanked, players[#]][[1, 1]] &, Keys[players]]
 ]
Out[23]=

We can now find the number of unique rankings:

In[24]:=
Length[allHoleCardsRanked]
Out[24]=

Publisher

Joseph Brennan

Requirements

Wolfram Language 13.1 (June 2022) or above

Version History

  • 1.0.0 – 01 August 2025

Source Metadata

Related Resources

Author Notes

Possible improvements include adding support for other poker games such as Omaha.

License Information