WOO logo

On this page

My approach to analyzing video poker games

One frequent inquiry I receive is about how my video poker software can assess a pay table in under a minute. This page aims to clarify that process.

Initially, my program utilized a brute force method, examining all 2,598,960 starting hands and exploring all 32 potential discards, including analyzing all 1,533,939 replacement cards when discarding all five. This was around 1998, and back then, my computer indicated it would take over a year to complete. Nowadays, such a program would take roughly a month. However, with two simple shortcuts, you can reduce that timeframe from one month to just three seconds. Here’s how you can achieve it.

To minimize the execution time to just a few days, you can forgo analyzing duplicate hands during the deal. For instance, if the initial hand consists of four aces and a king, the suit of the king is irrelevant. It would be time-efficient to assign a random suit to the king and subsequently multiply the results by four. By applying this reasoning, the total varieties of starting hands can decrease from 2,598,960 to 134,459. The tables below illustrate the suit arrangements and their corresponding weights for each rank category.

Five Singletons

Perform a loop through all combin(13,5)=1,287 ways to select 5 distinct ranks from a total of 13. For each rank combination, assign suits (numbered 1 through 4) and weights accordingly. For example, the first row assigns a suit of 1 to each unique rank. Given four possible suits, instead of repeating this four times, calculate it just once and multiply the outcome by the weight of 4.

Five Unique Ranks

Sing. 1 Sing. 2 Sing. 3 Sing. 4 Sing. 5 Weight
1 1 1 1 1 4
2 1 1 1 1 12
1 2 1 1 1 12
1 1 2 1 1 12
1 1 1 2 1 12
1 1 1 1 2 12
2 2 1 1 1 12
2 1 2 1 1 12
2 1 1 2 1 12
2 1 1 1 2 12
1 2 2 1 1 12
1 2 1 2 1 12
1 2 1 1 2 12
1 1 2 2 1 12
1 1 2 1 2 12
1 1 1 2 2 12
2 3 1 1 1 24
2 1 3 1 1 24
2 1 1 3 1 24
2 1 1 1 3 24
1 2 3 1 1 24
1 2 1 3 1 24
1 2 1 1 3 24
1 1 2 3 1 24
1 1 2 1 3 24
1 1 1 2 3 24
1 1 2 2 3 24
1 2 1 2 3 24
1 2 2 1 3 24
1 1 2 3 2 24
1 2 1 3 2 24
1 2 2 3 1 24
1 1 3 2 2 24
1 2 3 1 2 24
1 2 3 2 1 24
1 3 1 2 2 24
1 3 2 1 2 24
1 3 2 2 1 24
3 1 1 2 2 24
3 1 2 1 2 24
3 1 2 2 1 24
4 4 1 2 3 24
4 1 4 2 3 24
4 2 3 4 1 24
4 1 2 3 4 24
1 4 4 2 3 24
1 4 2 4 3 24
1 4 2 3 4 24
2 3 4 4 1 24
2 3 4 1 4 24
1 2 3 4 4 24

Pair

Iterate through all combinations of ranks, looping through all 13×combin(12,3)=2,860 options for selecting a rank for the pair and three ranks from the remaining 12 for the singletons. For each rank combination, specify the suits (numbered 1 to 4) and the weights. For instance, in the initial row, both suits of the pair are assigned to 1 and 2, while all singletons are assigned suit 1. There are combin(4,2)=6 combinations for the suits of the pair, and for the singleton's suit, you will have 2 options matching one of the pair's suits, leading to a final weighting of 6×2=12.

Pair

Pair 1 Pair 2 Sing. 1 Sing. 2 Sing. 3 Weight
1 2 1 1 1 12
1 2 1 1 2 12
1 2 1 2 1 12
1 2 2 1 1 12
1 2 1 1 3 24
1 2 1 3 1 24
1 2 3 1 1 24
1 2 1 3 3 24
1 2 3 1 3 24
1 2 3 3 1 24
1 2 3 3 3 12
1 2 1 2 3 24
1 2 1 3 2 24
1 2 3 1 2 24
1 2 3 4 4 12
1 2 4 3 4 12
1 2 4 4 3 12
1 2 1 3 4 24
1 2 3 1 4 24
1 2 3 4 1 24

Two Pair

Cycle through all combin(13,2)×11=858 methods to select two ranks from 13 for the two pairs and pick one rank from the remaining 11 for the singleton. For each rank combination, establish the suits and weights as follows. The first row, for instance, assigns suits 1 and 2 to the first pair, suits 3 and 4 to the second pair, and suit 1 to the singleton. The first pair has combin(4,2)=6 suit selection options, while the second pair contains the remaining two suits, allowing just one option. For the singleton, it can adopt a suit from the first pair, giving rise to two choices. Hence, the weighting for this initial row stands at 6×1×2=12.

Two Pair

Pair 1
Card 1
Pair 1
Card 2
Pair 2
Card 1
Pair 2
Card 2
Sing. 1 Weight
1 2 3 4 1 12
1 2 3 4 3 12
1 2 1 3 1 24
1 2 1 3 2 24
1 2 1 3 3 24
1 2 1 3 4 24
1 2 1 2 1 12
1 2 1 2 3 12

Three of a Kind

Browse through all 13×combin(12,2)=858 alternatives for selecting one rank out of 13 for three of a kind and 66 possibilities for selecting two singletons from the other 12 ranks. Assign suits and weights similar to previous examples. The first row will designate suits 1, 2, and 3 for the three of a kind and suits for singletons drawn from the suits utilized in the three of a kind. Here, combin(4,3)=4 the selections for the three of a kind's suits, 3 choices for the first singleton suit, and 2 for the second singleton suit contribute a total weighting of 4×3×2=24.

Three of a Kind

3 Kind
Card 1
3 Kind
Card 2
3 Kind
Card 3
Sing. 1 Sing. 2 Weight
1 2 3 1 2 24
1 2 3 1 4 12
1 2 3 4 1 12
1 2 3 1 1 12
1 2 3 4 4 4

Full House

Iterate through all 13×12=156 unique combinations selecting one rank for a three of a kind while choosing one pair rank among the remaining 12. Define suits and weights appropriately. The first row assigns suits 1 and 2 to the pair, and suits to the three of a kind are 1, 2, and 3. There are combin(4,2)=6 options for selecting suits for the pair, while the three of a kind utilizes both pair suits plus one from the remaining two, resulting in a weighting of 6×2×2=12.

Full House

Pair
Card 1
Pair
Card 2
3 Kind
Card 1
3 Kind
Card 2
3 Kind
Card 3
Weight
1 2 1 2 3 12
1 4 1 2 3 12

Four of a Kind

Loop through all 13×12=156 options for designating one rank out of 13 for four of a kind and a different rank for the singleton. Each time, assign suits and weights consistently. The first row could designate suits 1, 2, 3, and 4 for the four of a kind, while the singleton's suit equals 1. There’s only one method for selecting suits for the four of a kind, and four methods available for the singleton’s suit selection. Thus, the weighting in this instance would be 1×4×2=4.

Four of a Kind

4 Kind
Card 1
4 Kind
Card 2
4 Kind
Card 3
4 Kind
Card 4
Sing. 1 Weight
1 2 3 4 1 4

The aforementioned step could decrease computation time by up to 95%, but it may still require several hours if you loop through the total of 1,533,939 possible replacements. The key to achieving a three-second program is to skip the looping at the draw stage entirely. Here's how to proceed:

  1. Initialize the following arrays:
    • Array 1: size 2,598,960
    • Array 2: size 270,725 by 16
    • Array 3: size 22100 by 16
    • Array 4: size 1326 by 16
    • Array 5: size 52 by 16
    • Array 6: size 16
    The number 16 signifies the upper limit of various paying hands during the draw phase. Feel free to adjust this number based on your observations, though I’ve never encountered a video poker game that features more than 16 components in its pay table.
  2. Proceed to examine all 2,598,960 combinations of 5 cards selected from a pool of 52. At this juncture, DO NOT utilize the 134,459 hand shortcut. For every hand dealt, fulfill the following tasks:
    • Score it according to its poker value.
    • Store the score in array0. Input the first hand into the first element of the array, incrementing by 1 for each subsequent hand.
    • For each of the 5 possibilities to select 4 out of the 5 dealt cards, convert the four selected cards into an indexed number ranging from 0 to 270,724 (I will provide an explanation for this process later), and increase the value of element [index number][hand score] in array1 by 1.
    • For every 10 ways to select 3 cards from the 5 cards dealt, convert these three cards into an indexed number from 0 to 22,099, incrementing element [index number][hand score] in array2 by 1.
    • For each of the 10 options of selecting 2 cards from the 5 dealt, convert the pair into an indexed number from 0 to 1,325, and raise element [index number][hand score] in array3 by 1.
    • For the 5 methods to select 1 card from the 5 cards dealt, convert this card to an indexed value from 0 to 51 and mark element [index number][hand score] in array4 by 1.
    • Increase the value of element [hand score] in array5 by 1.
    At this point, the arrays will reflect the potential outcomes of maintaining any set of cards dealt, excluding the penalty cards (discards). Array0 will indicate results for zero cards held, array1 for one card held, etc.
  3. Next, iterate through the 134,459 categories of hands previously defined.
  4. To assess the value of holding all five cards, convert the five cards to an indexed number, and reference their poker value from array0.
  5. For analyzing the worth of holding four cards, convert the four cards into an indexed number and check possible outcomes from the draw in the matching element of array1. However, this includes the card discarded from the deal. Therefore, you should deduct one from the value in the array corresponding to the poker value for the five cards held. For instance, if you hold J♣, Q♣, K♣, and A♣ while discarding2♥there will be one way to receive a royal, eight ways to achieve a flush, three options for a straight, twelve ways to get a pair of jacks or better, and twenty-three scenarios for losing. Yet, array1 will mistakenly suggest there are twenty-four ways of getting a losing hand, counting the2♥draw scenario. Hence, it’s essential to omit the outcome of executing the five-card hold from the potential outcomes when considering the 5 ways to hold 4 cards.
  6. Ensure you grasp the rationale behind the preceding step, as we will build on it further. For the ten combinations of holding any three cards, you will reference the outcomes in array2. Subsequently, subtract the possible outcomes from array1 for the three cards you are retaining in addition to each of the discarded cards. For instance, consider the valuations for keeping 2♣2♥2♠ and discarding4♥and J♠ begins with the values indicated in array2 for 2♣2♥2♠, then subtract the valuations for 2♣2♥2♠4♥and 2♣2♥2♠ J♠. Keep in mind this will double-count the combination where you hold all five cards. Thus, you must add back the value obtained from holding all five.
  7. Employing a similar reasoning for two held cards, initiate with figures from array3, deduct relevant card combinations from array2, reintegrate appropriate card sets from array1, and further eliminate the relevant values from array0 associated with holding all cards.
  8. For maintaining one card, begin by extracting the corresponding values from array4, deduct ill-suited values from array3, incorporate helpful values from array2, eliminate irrelevant values from array1, and finally add back the appropriate value from array0.
  9. For discarding all cards, start with values from array5, take off the relevant values linked to array4, bring back suitable values from array3, eliminate any unneeded values from array2, add necessary values from array1, and remove the corresponding value from array0.
  10. At this stage, you ought to have the combinations of all potential outcomes for all 32 ways to play the hand. Calculate the anticipated value of each one. For the scenario yielding the highest expected value, include those potential outcomes in an array tracking the game’s overall possibilities, ensuring to multiply by the associated weight for the hand played.
  11. Upon completing an iteration through all 134,459 types of starting hands, you should possess a count of the various ways to achieve each hand drawn. Utilize this array to calculate the total expected return of the game.

Below are four subroutines designed to translate between 2 to 5 cards (numbered 0 to 51) while providing an index value.

int HandIndex2(int c1, int c2) { int result; result = combin_array[52][2] - combin_array[52 - c1][2]; result += combin_array[51 - c1][1] - combin_array[52 - c2][1]; return result; } int HandIndex3(int c1, int c2, int c3) { int result; result = combin_array[52][3] - combin_array[52 - c1][3]; result += combin_array[51 - c1][2] - combin_array[52 - c2][2]; result += combin_array[51 - c2][1] - combin_array[52 - c3][1]; return result; } int HandIndex4(int c1, int c2, int c3, int c4) { int result; result = combin_array[52][4] - combin_array[52 - c1][4]; result += combin_array[51 - c1][3] - combin_array[52 - c2][3]; result += combin_array[51 - c2][2] - combin_array[52 - c3][2]; result += combin_array[51 - c3][1] - combin_array[52 - c4][1]; return result; } int HandIndex5(int CardIndex[]) { int result; result = combin_array[52][5] - combin_array[52 - CardIndex[0]][5]; result += combin_array[51 - CardIndex[0]][4] - combin_array[52 - CardIndex[1]][4]; result += combin_array[51 - CardIndex[1]][3] - combin_array[52 - CardIndex[2]][3]; result += combin_array[51 - CardIndex[2]][2] - combin_array[52 - CardIndex[3]][2]; result += combin_array[51 - CardIndex[3]][1] - combin_array[52 - CardIndex[4]][1]; return result; }

Links

This site describes the method the author used to significantly reduce the time taken by his video poker analyzer from one year down to just seven seconds.

VP Genius features an exceptional section dedicated to video poker programming techniques.