konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 25th, 2017 at 10:34:44 AM permalink
Hi all,
I am totally addict in the analysis of video poker this week though I tried long time ago but never succeed. Recently, I find some posts by ThatDonGuy a year ago that give me some clue on how to start this work again. From his code, I can get the 134459 unique hands but I can't get back to total 2598960 hands by adding all the weights. There must be something wrong. Later, I found this article https://wizardofodds.com/games/video-poker/methodology/, it mentioned several tables of 4 of a kind, full house and etc. of generic suit representation. I then try to fill in the possible face value into the generic suits pattern that gives me total 134459 unique hands and I can get 2598960 hands back by adding all the weights. So far so. I know what to do next is to start from the 134459 hands, loop each of them, get a 5-card hand from a time, on that 5-card hand, try to discard 0, 1, 2, 3, 4, 5 cards and get replacement one at a time (total 32 ways), find the pay for each replacement and estimate the expectation value from there. However, it is quite slow to go that way. So in above article, the author suggestion to use lookup table to help speed up the process. I am not fully understand the article but I try to read it very carefully and here is what I mean the author means (point out my mistakes if any please)

He assumes all cards are indexed 0 to 51 (inclusive). He creates 5 arrays, array0[][16] use to hold all 2598960 hands with 16 pay entries.
array1[][16] is holding 4 hold cards and 1 discard card combination with next column is pay table
array2[][16] is holding 3 hold cards and 2 discard cards combination with next column is pay table
array3[][16] is holding 2 hold cards and 3 discard cards combination with next column is pay table
array4[][16] is holding 1 hold cards and 4 discard cards combination with next column is pay table
array5[][16] is holding 0 hold card and 5 discard cards combination with next column is pay table

The author said the index of array1[index], array2[index], is calculated in a given formula by using the face value of the holding cards. Once those array's established. We could start to use the 134459 hands, I am trying to add a code illustrating the idea


for (i=0; i<134459; i++) {
hand = HANDS134456;
hold all cards: hand => index
C0=array[index][RF] + array[index][SF] + array[index][FOAK] + ... + array[index][JACKSBETTER];
EV0=(array[index][RF]*PAY[RF] +array[index][SF]*PAY[SF] + ... + )/C

// now consider to discard 1 card
C1=0
EV1=0
for (int i=0; i<5; i++) { // 5 ways
hand -> hand1
compute 4-card index from hand1 => index
C1=array1[index][RF] + array1[index][SF] + array1[index][FOAK] + ... + array1[index][JACKSBETTER];
EV1+=(array1[index][RF]*PAY[RF] +array1[index][SF]*PAY[SF] + ... + )/C1
}


repeat the similar procedure for array2, array3, array4 and array5 to get EV2, EV3, EV4, EV5 and find the maximum, which will tell you the optimal contribution to the hand just dispatch from 134456 hands. Do the same thing until all hands done, adding the weight back will give the overall RTP.

Let me know if I make mistakes so far. Now come to a question that confusing me. The author just mention how to compute the index with 2 cards, 3 cards, 4 cards etc. but he didn't mention that if the card order is important or not. I found that I am using his big picture but my way to deal with card deal and hand order is pretty much different, for each hand dealt from 2598960 hands, all cards are sorted based on their face value and suit so A A[H] 5[H] 5[C] 5 [D] is one example. But obviously the suit patterns mentioned in his article doesn't have any requirement on order (and I tested it, I can generate the 134459 hands at any order which could map back to the 2598960 hands, so I guess order doesn't matter, isn't it?) Ok, so if order really doesn't matter, then each hand I obtain from the 2598960 hands is sorted, I pick any 4 cards out of 5, index them by using the author's formula and use the result as an index for the array1[index] until each of 2598960 hands have been handled the same way, however, I found that array1 does not give exact same number of row as mentioned in the author if my hand is sorted (don't know) why. But if I get the sorted 5-card hand, pick 4 of them, sort the 4-card hand same way, then compute the index by using a 64-base coding, I can get the correct number of rows in array1[index]. Can anyone help to tell me if my way is also work? Why his method doesn't work for sorted hand? I have been struggling for this code for a week, I know I am almost there. But at the last step, I would like some help to point out the correct way to finalize it.

Note: in author's article, he said each card indexed 0 to 51 (inclusive) but for some reason, I have to make it 1 to 52, so before using his formula I subtract my card by 1. I think that's won't affect the reason, will it?

Thanks.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 26th, 2017 at 7:47:47 AM permalink
I figure out the ranking and ordering myself. It is a bit more clear to me with the instruction of how to count the number of hands when dropping 0,1,2,3,4,5 cards now.
I am trying to verify my code by analyzing the case of holding 4 cards. In the instruction, it said

To determine the value of holding any four cards, translate the four cards to an index number, and look up the possible outcomes on
the draw in the corresponding element of array1. This, however, will include getting the card you discarded on the deal. So you
should subtract one from the element in the array associated with the poker value of holding all five cards.


So here is what I did, I deal a 5-card hand from 134459 unique hands deck, create an index for the dealt hand, look up the index from array0 and find the pay (called pay0).
Try to drop one card from that hand at a time (5 ways), each time dropping 1 card, create an index from the rest 4 cards, looking
that index from array1 for a pay and count, if that pay is same as pay0, deduct 1 from the count.


hand0 = ...; //dealt from 134459 unique hands deck
index0 = ...; //compute index for hand0
pay0 = array0[index0];
payIdx0 = ...; // get the pay index (ranged from 0 to 15) from pay0, e.g. for royal flush, the pay is 800, pay index is 0
maxEV = 0;
for (int i=1 to 5) {// 1 to 5 ways of dropping a card
totalPay = 0;
totalCount = 0;
EV = 0;
index1 = ...; // index for 4-card hand (after dropping one card from hand0 at a time)
if (array1[index1][payIdx0]>0) {
array1[index1][payIdx0]--;
}
for (int j=0; j<16; j++) {// assume at max 16 type of pay
totalPay += pay_table
*array1[index1]
; // add up all pays
totalCount += array1[index1]
;
}
EV = totalPay/totalCount;
if (EV>maxEV) {
maxEV = EV;
}
}

This will return the maximum EV with all 5 possible ways to replace one card. I compare 20 random initial hands and confirm
the results with that given in https://wizardofodds.com/games/video-poker/hand-analyzer/

But the next question is doing that for holding 3 cards is not clear to me. The instruction from that site is

For the 10 ways of holding any 3 cards you will look up the possible outcomes in array2. Then subtract the possible outcomes
from array1 for the 3 cards you are holding, and each of the cards you are discarding. However, this will double-subtract
holding all five cards. So you need to add back in what you get by holding all 5.


I am not sure my understanding "subtract the possible outcomes from array1". My best guess is the 3-holding-card hands may be from
a 4-card hand with 3 of them duplicated, and thus if the 4-card hand paid already, we don't count that in 3-card case. But what happen if
the 4-card case paid but the 3-card case doesn't? For example, 3-card hand is 2S 2H 3C but the 4-card hand may be 2S 2H 3C 3D so 4-card hand
pays 2 pairs but there is no 2 pair pay for that 3-card hand in array2? Should I just ignore the count deduction in this case? I have my code
written as below


hand0 = ...; // dealt from 134459 unique hands deck
index0 = ...; // compute index for hand0
pay0 = array0[index0];
payIdx0 = ...; // get the pay index (ranged from 0 to 15) from pay0, e.g. for royal flush, the pay is 800, pay index is 0

maxEV = 0;
for (int i=1 to 10) {// 1 to 10 ways of dropping 2 cards
totalPay = 0;
totalCount = 0;
EV = 0;
index1 = ...; // index for 3-card hand (after dropping two card from hand0 at a time)
index11 = ...; // 4-card hand, 3 cards from 3-card hand plus the first dropped card
payIdx11 = ...;// pay index for index11
index12 = ...; // 4-card hand, 3 cards from 3-card hand plus the second dropped card
payIdx12 = ...; // pay index for index12

if (array2[index1][payIdx11]>0) { // only deduct the 4-card count by ONE if there exists the same pay for the 3-card hand
array2[index1][payIdx11]--;
}
if (array2[index1][payIdx12]>0) { // only deduct the 4-card count by ONE if there exists the same pay for the 3-card hand
array2[index1][payIdx12]--;
}
if (array2[index1][payIdx0]) { // add one count back for double deduction for 5-card case
array2[index1][payIdx0]++;
}
for (int j=0; j<16; j++) {// assume at max 16 type of pay
totalPay += pay_table
*array2[index1]
; // add up all pays
totalCount += array2[index1]
;
}
EV = totalPay/totalCount;
if (EV>maxEV) {
maxEV = EV;
}
}
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 26th, 2017 at 10:35:30 AM permalink
I may found the reason why above example won't match and my code won't work. Here is how I index a hand.

First my poker is numbered from 1 to 52 (inclusive) with 1 to 13 refer to A, 2, 3 to Q, K of suit spade,
14 to 26 for A, 2, 3 to Q K of suit heart; and so on. Taking 5-card hand as example, I sort the hand in
ascending order (ACE first if available; e.g. JS 2H 4S 2S 2C will be sorted to 2S 2H 2C 4S JS). I compute the
hand index by placing them into a 64-base representation, i.e.

handindex0 = V(2S)*64^4 + V(2H)*64^3 + V(2C)*64^2 + V(4S)*64 + V(JS) = 37594491

here V() will return the raw card value, V(2S)=2, V(2H)=15, V(2C)=28, V(4S)=4, V(JS)=11

if I drop the last two cards, the 3-card hand will give index as
handindex1 (drop RS, JS) = V(2S)*64^4 + V(2H)*64^3 + V(2C)*64^2 + 0 + 0 = 37594244

However, if I drop one card, 4S or JS so to get two 4-card hand, I get two index similarly

handindex2 (drop JS) = V(2S)*64^4 + V(2H)*64^3 + V(2C)*64^2 + V(4S)*64 + 0 = 37594480
handindex3 (drop 4S) = V(2S)*64^4 + V(2H)*64^3 + V(2C)*64^2 + V(JS)*64 + 0 = 37594928


// array2 second column is the pay for each hand, 3 credits for 3 of a kind, 9 credits for full house and 25 credits for 4 of a kind
// the RHS is the count for that 4-card hand that contains a 3-card making index1, so the counts tell how many ways that you could start from a 3-card hand and get 1 more card to get to the 4-card hand that will give certain pay
from my array2[handindex1][3] = 1056
array2[handindex1][9] = 72
array2[handindex1][25] = 48

// array holding 4 cards
from my array1[handindex2][3] = 44
array1[handindex2][9] = 3
array1[handindex2][25] = 1
array1[handindex3][3] = 0
array1[handindex3][9] = 0
array1[handindex3][25] = 0

// array holding all 5 cards
from my array0[handindex0][3] = 3
array0[handindex0][9] = 0
array0[handindex0][25] = 0


From above array, I can tell, for the pay [3], 3-card hand gives 1056 count, both 4-card and 5-card has pay for [3], so I should deduct 1056 by 1 to get 1055
For [9] pay, deduct 72 by 1 getting from 4-card hand => 71
Fro [25] pay, seems nothing to deduct so I get 48

But the theory said, by holding the first 3 cards and drop the last two, I should get
46 ways to get a 4 of a kind
66 ways to get a full house
969 ways to get a 3 of a kind

with that I should get EV about 2.30; however from my number, I only get 2.12; Something wrong!

I am trying to read carefully on the the reference page, the author use combination in calculating the index or
4-card hand 3-card hand and so. For example, to hold 4 cards labelled c1, c2, c3, c4, what the author did is


int HandIndex4(int c1, int c2, int c3, int c4)
{
int r;
r=combin_array[52][4]-combin_array[52-c1][4];
r+=combin_array[51-c1][3]-combin_array[52-c2][3];
r+=combin_array[51-c2][2]-combin_array[52-c3][2];
r+=combin_array[51-c3][1]-combin_array[52-c4][1];
return r;
}


This is pretty confusing to me because no information about the order of the cards. Should I put in them in any order? Also,
I try my 4 hand 2S 2H 2C 4S and the last formula give negative though the total sum is still positive. I am totally don't understand
what's those HandIndex and formula are. What information the index of 2S 2H 2C 4S and 2S 2H 2C JS should tell reading table searching?

I am totally stuck here, please help.
ThatDonGuy
ThatDonGuy 
  • Threads: 122
  • Posts: 6679
Joined: Jun 22, 2011
September 26th, 2017 at 12:22:46 PM permalink
Quote: konglify

// array holding 4 cards
from my array1[handindex2][3] = 44
array1[handindex2][9] = 3
array1[handindex2][25] = 1
array1[handindex3][3] = 0
array1[handindex3][9] = 0
array1[handindex3][25] = 0

The three values with handindex3 should match the ones with handindex2. array1[handindex3][3] = 0 says that there are no three of a kinds with three deuces and a jack.

Quote: konglify

From above array, I can tell, for the pay [3], 3-card hand gives 1056 count, both 4-card and 5-card has pay for [3], so I should deduct 1056 by 1 to get 1055
For [9] pay, deduct 72 by 1 getting from 4-card hand => 71
Fro [25] pay, seems nothing to deduct so I get 48

I think you read the instruction wrong.
What you want to do is, for each paytable level (e.g. [3]), take the array2 value, subtract the two array1 values, and then add the array0 value

Also, where are you getting array0[handindex0][3] = 3 ? Shouldn't that be 1? There is only one three of a kind in that 5-card hand, and not three.

When you correct the array1[handindex3] values to:
array1[handindex3][3] = 44
array1[handindex3][9] = 3
array1[handindex3][25] = 1
and array0[handindex0][3] = 1
then you get:
array2[handindex1][3] - array1[handindex2][3] - array1[handindex3][3] + array0[handindex0][3] = 1056 - 44 - 44 + 1 = 969
array2[handindex1][9] - array1[handindex2][9] - array1[handindex3][9] + array0[handindex0][9] = 72 - 3 - 3 + 0 = 66
array2[handindex1][25] - array1[handindex2][25] - array1[handindex3][25] + array0[handindex0][25] = 48 - 1 - 1 + 0 = 46



Quote: konglify

I am trying to read carefully on the the reference page, the author use combination in calculating the index or
4-card hand 3-card hand and so. For example, to hold 4 cards labelled c1, c2, c3, c4, what the author did is


int HandIndex4(int c1, int c2, int c3, int c4)
{
int r;
r=combin_array[52][4]-combin_array[52-c1][4];
r+=combin_array[51-c1][3]-combin_array[52-c2][3];
r+=combin_array[51-c2][2]-combin_array[52-c3][2];
r+=combin_array[51-c3][1]-combin_array[52-c4][1];
return r;
}


This is pretty confusing to me because no information about the order of the cards. Should I put in them in any order?

Yes. c1 < c2 < c3 < c4. Also note that each of those values is 0-51, not 1-52.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
October 5th, 2017 at 3:57:30 AM permalink
Quote: ThatDonGuy

Quote: konglify

// array holding 4 cards
from my array1[handindex2][3] = 44
array1[handindex2][9] = 3
array1[handindex2][25] = 1
array1[handindex3][3] = 0
array1[handindex3][9] = 0
array1[handindex3][25] = 0

The three values with handindex3 should match the ones with handindex2. array1[handindex3][3] = 0 says that there are no three of a kinds with three deuces and a jack.

Quote: konglify

From above array, I can tell, for the pay [3], 3-card hand gives 1056 count, both 4-card and 5-card has pay for [3], so I should deduct 1056 by 1 to get 1055
For [9] pay, deduct 72 by 1 getting from 4-card hand => 71
Fro [25] pay, seems nothing to deduct so I get 48

I think you read the instruction wrong.
What you want to do is, for each paytable level (e.g. [3]), take the array2 value, subtract the two array1 values, and then add the array0 value

Also, where are you getting array0[handindex0][3] = 3 ? Shouldn't that be 1? There is only one three of a kind in that 5-card hand, and not three.

When you correct the array1[handindex3] values to:
array1[handindex3][3] = 44
array1[handindex3][9] = 3
array1[handindex3][25] = 1
and array0[handindex0][3] = 1
then you get:
array2[handindex1][3] - array1[handindex2][3] - array1[handindex3][3] + array0[handindex0][3] = 1056 - 44 - 44 + 1 = 969
array2[handindex1][9] - array1[handindex2][9] - array1[handindex3][9] + array0[handindex0][9] = 72 - 3 - 3 + 0 = 66
array2[handindex1][25] - array1[handindex2][25] - array1[handindex3][25] + array0[handindex0][25] = 48 - 1 - 1 + 0 = 46



Quote: konglify

I am trying to read carefully on the the reference page, the author use combination in calculating the index or
4-card hand 3-card hand and so. For example, to hold 4 cards labelled c1, c2, c3, c4, what the author did is


int HandIndex4(int c1, int c2, int c3, int c4)
{
int r;
r=combin_array[52][4]-combin_array[52-c1][4];
r+=combin_array[51-c1][3]-combin_array[52-c2][3];
r+=combin_array[51-c2][2]-combin_array[52-c3][2];
r+=combin_array[51-c3][1]-combin_array[52-c4][1];
return r;
}


This is pretty confusing to me because no information about the order of the cards. Should I put in them in any order?

Yes. c1 < c2 < c3 < c4. Also note that each of those values is 0-51, not 1-52.



Thanks. I finally get it works for the case when holding all 5 cards, holding 4 cards, holding 3 cards, holding 2 cards and holding 1 card. I check the outcomes (expectation value) with that given in https://wizardofodds.com/games/video-poker/hand-analyzer/, it matches pretty good. But I am still confusing on the last case for discarding all 5 cards.

The instruction states "For discarding everything start with the values in array5, then subtract out the appropriate values from array4, add back in the appropriate values from array3, subtract back out the appropriate values from array2, add back in the appropriate values from array1, and subtract out the appropriate value from array0."

In which, array5 is array of 16 elements, each element is count for a certain hand value (ROYAL FLUSH, ...). However, array4, array3 and etc. are 2-dimensional array of [N][16]. I am not sure if my understanding to add/subtract arrays is correct because of different dimension. For example, when one initial hand out of 134459 is given

holding one card at a time and then compute the index, says idx, and array4[idx] will give 16 values, so we need to subtract those 16 values from array5

array5[0] -= array4[idx][0]
array5[1] -= array4[idx][1]
array5[2] -= array4[idx][2]
array5[3] -= array4[idx][3]
array5[4] -= array4[idx][4]
...
array5[15] -= array4[idx][15]

Is it a correct way to do the math? I am checking the result but I did not get the correct expectation value yet.
ThatDonGuy
ThatDonGuy 
  • Threads: 122
  • Posts: 6679
Joined: Jun 22, 2011
October 5th, 2017 at 5:49:18 AM permalink
Quote: konglify

Thanks. I finally get it works for the case when holding all 5 cards, holding 4 cards, holding 3 cards, holding 2 cards and holding 1 card. I check the outcomes (expectation value) with that given in https://wizardofodds.com/games/video-poker/hand-analyzer/, it matches pretty good. But I am still confusing on the last case for discarding all 5 cards.

The instruction states "For discarding everything start with the values in array5, then subtract out the appropriate values from array4, add back in the appropriate values from array3, subtract back out the appropriate values from array2, add back in the appropriate values from array1, and subtract out the appropriate value from array0."

In which, array5 is array of 16 elements, each element is count for a certain hand value (ROYAL FLUSH, ...). However, array4, array3 and etc. are 2-dimensional array of [N][16]. I am not sure if my understanding to add/subtract arrays is correct because of different dimension. For example, when one initial hand out of 134459 is given

holding one card at a time and then compute the index, says idx, and array4[idx] will give 16 values, so we need to subtract those 16 values from array5

array5[0] -= array4[idx][0]
array5[1] -= array4[idx][1]
array5[2] -= array4[idx][2]
array5[3] -= array4[idx][3]
array5[4] -= array4[idx][4]
...
array5[15] -= array4[idx][15]

Is it a correct way to do the math? I am checking the result but I did not get the correct expectation value yet.


Yes. Remember that a one-dimensional array of N elements is the same as a two-dimensional 1 x N (or N x 1, for that matter) array.
Remember that, for each of the 16 array5 values, you will have to subtract out five different array4 values (one for each card in the hand), then add back 10 different array3 values, then subtract back 10 different array2 values, then add back 5 different array1 values, then subtract one array0 value.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
October 5th, 2017 at 8:22:33 AM permalink
Thanks. I finally figure out the disagreement in expectation value, I double count the value from array0. So all EV matched. I am trying to combine all computation and get the total return. With a test pay table (9/6 for example), I only get 75%. It seems that something wrong in my code when combining the EV. Here is the pseudo code


totalBet = 0;
totalWin = 0;
for (int i=0; i<134459; i++) // loop each unique hand
{
pay0 = computePay( UNIQUE_HAND[ i ] ); // compute the pay with initial hand

maxEV = pay0;
// try to hold 4 cards at a time, 5 ways to do so
for (int n=0; n<5; n++)
{
EV = computeEVHolding4Cards( UNIQUE_HAND[ i ], n); // compute EV on the hand with 4 cards holding
if (EV>maxEV) maxEV=EV
}

// try to hold 3 cards at a time, 10 ways to do so
for (int n=0; n<10; n++)
{
EV = computeEVHolding3Cards( UNIQUE_HAND[ i ], n); // compute EV on the hand with 4 cards holding
if (EV>maxEV) maxEV=EV
}

// try to hold 2 cards at a time, 10 ways to do so
for (int n=0; n<10; n++)
{
EV = computeEVHolding2Cards( UNIQUE_HAND[ i ], n); // compute EV on the hand with 4 cards holding
if (EV>maxEV) maxEV=EV
}

// try to hold 1 card at a time, 5 ways to do so
for (int n=0; n<5; n++)
{
EV = computeEVHolding2Cards( UNIQUE_HAND[ i ], n); // compute EV on the hand with 4 cards holding
if (EV>maxEV) maxEV=EV
}

// try discarding all 5 cards, 1 way to do so
EV = computeEVDiscarding5Cards( UNIQUE_HAND[ i ] ); // compute EV on the hand with 5 cards discarded
if (EV>maxEV) maxEV=EV

// we get the maximum EV with holding/discarding proper cards, add the EV back to the (total pay)

totalWin += maxEV*DUPLICATE_COUNT_FOR_THIS_UNIQUE_HAND;
totalBet += 1*DUPLICATE_COUNT_FOR_THIS_UNIQUE_HAND; // assume 1 credit per game
}

payBack = totalPay/totalBet;


I spot check about 50 unique initial hands and all EVs computed are in agreement with those given in the analyzer. But the payBack is pretty off. Is it something wrong with my computation to combine the individual EV to get the total win?
Last edited by: konglify on Oct 5, 2017
ThatDonGuy
ThatDonGuy 
  • Threads: 122
  • Posts: 6679
Joined: Jun 22, 2011
October 5th, 2017 at 10:27:20 AM permalink
Your "try to hold 1 card at a time" loop is using computeEVHolding2Cards instead of computeEVHolding1Card.

This means, for example, that if a dealt hand has 4 to a Royal Flush, that Royal Flush will never be counted as you are never counting the hand built from discarding just the fifth card.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
October 5th, 2017 at 8:31:50 PM permalink
Quote: ThatDonGuy

Your "try to hold 1 card at a time" loop is using computeEVHolding2Cards instead of computeEVHolding1Card.

This means, for example, that if a dealt hand has 4 to a Royal Flush, that Royal Flush will never be counted as you are never counting the hand built from discarding just the fifth card.



Oh, it is just a typo in the code I posted, it is computeEVHolding1Card instead. However, I still get about 75% instead. I just want to make sure the methodology to search the maximized EV is correct. Let take one example from https://wizardofodds.com/games/video-poker/hand-analyzer/

initial hand is 2C 2H 2S 4S JS, there will be total 32 resulting hands in analysis (all following cards are arranged in the same order as initial card, XX means drop the card, the number is the EV)

1) 2C 2H 2S XX XX 4.302898
2) 2C 2H 2S XX JS 3.851064
3) 2C 2H 2S 4S XX 3.851064
4) 2C 2H 2S 4S JS 3.000000
5) 2C XX 2S XX XX 0.581869
6) 2C 2H XX XX XX 0.581869
7) XX 2H 2S XX XX 0.581869
8) 2C 2H XX XX JS 0.524514
9) 2C 2H XX 4S JS 0.524514
10) XX 2H 2S XX JS 0.524514
11) 2C XX 2S XX JS 0.524514
12) 2C XX 2S 4S XX 0.524514
13) XX 2H 2S 4S XX 0.524514
14) XX XX XX XX JS 0.487091
15) XX XX 2S 4S JS 0.380204
16) XX XX XX 4S JS 0.374591
17) XX XX XX XX XX 0.361344
18) XX 2H 2S 4S JS 0.319149
19) 2C 2H XX 4S JS 0.319149
20) 2C XX 2S 4S JS 0.319149
21) XX XX 2S XX JS 0.317360
22) XX XX XX 4S XX 0.317360
23) XX 2H XX XX JS 0.280358
24) 2C XX XX XX JS 0.280358
25) XX XX 2S 4S XX 0.205982
26) 2C XX XX XX XX 0.204586
27) XX 2H XX XX XX 0.204586
28) XX XX 2S XX XX 0.196137
29) XX 2H XX XX JS 0.172063
30) 2C XX XX 4S JS 0.172063
31) 2C XX XX 4S XX 0.163922
32) XX 2H XX 4S XX 0.163922

So what I do is to pick the maximum EV from those 32 numbers, which is "2C 2H 2S XX XX 4.302898", so I add 4.302898*DUPLICATE_COUNT_FOR_THIS_UNIQUE_HAND to the total pay. Repeat the same procedure for the reset 134458 initial hands. Is this a right way to do the math?

p.s. I am posting the result about the case of 4 to a royal flush obtained from my program (verified with the the wizardsofodd analyzer)
The hand dealt is 4D 10S QS KS AS

1) XX 10S QS KS AS 18.319149
2) XX XX QS KS AS 0.607771
3) XX 10S QS KS XX 0.602220
4) XX 10S XX KS AS 0.505088
5) XX 10S QS XX AS 0.505088
6) XX XX QS KS XX 0.502436
7) XX XX XX KS AS 0.490595
8) XX XX QS XX AS 0.490595
9) XX XX QS XX XX 0.435478
10) XX XX XX XX AS 0.432478
11) XX XX XX KS XX 0.431172
12) XX 10S QS XX XX 0.386617
13) XX 10S X KS XX 0.368301
14) XX 10S XX XX AS 0.356460
15) 4D XX XX XX AS 0.337465
16) 4D XX XX KS XX 0.321677
17) 4D XX QS XX XX 0.321677
18) XX XX XX XX XX 0.307338
19) 4D XX XX KS AS 0.294172
20) 4D XX QS XX AS 0.294172
21) 4D XX QS KS XX 0.294172
22) 4D XX XX XX XX 0.289564
23) XX 10S XX XX XX 0.278670
24) 4D XX QS KS AS 0.191489
25) 4D 10S XX XX AS 0.191489
26) 4D 10S XX KS XX 0.191489
27) 4D 10S QS XX XX 0.191489
28) 4D 10S XX XX XX 0.187542
29) 4D 10S XX KS AS 0.127660
30) 4D 10S QS XX AS 0.127660
31) 4D 10S QS KS XX 0.127660
32) 4D 10S QS KS AS 0.000000

So the maximum EV for this hand is 18.319149
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
October 6th, 2017 at 2:11:57 AM permalink
Quote: konglify

Oh, it is just a typo in the code I posted, it is computeEVHolding1Card instead. However, I still get about 75% instead. I just want to make sure the methodology to search the maximized EV is correct. Let take one example from https://wizardofodds.com/games/video-poker/hand-analyzer/

initial hand is 2C 2H 2S 4S JS, there will be total 32 resulting hands in analysis (all following cards are arranged in the same order as initial card, XX means drop the card, the number is the EV)

1) 2C 2H 2S XX XX 4.302898
2) 2C 2H 2S XX JS 3.851064
3) 2C 2H 2S 4S XX 3.851064
4) 2C 2H 2S 4S JS 3.000000
5) 2C XX 2S XX XX 0.581869
6) 2C 2H XX XX XX 0.581869
7) XX 2H 2S XX XX 0.581869
8) 2C 2H XX XX JS 0.524514
9) 2C 2H XX 4S JS 0.524514
10) XX 2H 2S XX JS 0.524514
11) 2C XX 2S XX JS 0.524514
12) 2C XX 2S 4S XX 0.524514
13) XX 2H 2S 4S XX 0.524514
14) XX XX XX XX JS 0.487091
15) XX XX 2S 4S JS 0.380204
16) XX XX XX 4S JS 0.374591
17) XX XX XX XX XX 0.361344
18) XX 2H 2S 4S JS 0.319149
19) 2C 2H XX 4S JS 0.319149
20) 2C XX 2S 4S JS 0.319149
21) XX XX 2S XX JS 0.317360
22) XX XX XX 4S XX 0.317360
23) XX 2H XX XX JS 0.280358
24) 2C XX XX XX JS 0.280358
25) XX XX 2S 4S XX 0.205982
26) 2C XX XX XX XX 0.204586
27) XX 2H XX XX XX 0.204586
28) XX XX 2S XX XX 0.196137
29) XX 2H XX XX JS 0.172063
30) 2C XX XX 4S JS 0.172063
31) 2C XX XX 4S XX 0.163922
32) XX 2H XX 4S XX 0.163922

So what I do is to pick the maximum EV from those 32 numbers, which is "2C 2H 2S XX XX 4.302898", so I add 4.302898*DUPLICATE_COUNT_FOR_THIS_UNIQUE_HAND to the total pay. Repeat the same procedure for the reset 134458 initial hands. Is this a right way to do the math?

p.s. I am posting the result about the case of 4 to a royal flush obtained from my program (verified with the the wizardsofodd analyzer)
The hand dealt is 4D 10S QS KS AS

1) XX 10S QS KS AS 18.319149
2) XX XX QS KS AS 0.607771
3) XX 10S QS KS XX 0.602220
4) XX 10S XX KS AS 0.505088
5) XX 10S QS XX AS 0.505088
6) XX XX QS KS XX 0.502436
7) XX XX XX KS AS 0.490595
8) XX XX QS XX AS 0.490595
9) XX XX QS XX XX 0.435478
10) XX XX XX XX AS 0.432478
11) XX XX XX KS XX 0.431172
12) XX 10S QS XX XX 0.386617
13) XX 10S X KS XX 0.368301
14) XX 10S XX XX AS 0.356460
15) 4D XX XX XX AS 0.337465
16) 4D XX XX KS XX 0.321677
17) 4D XX QS XX XX 0.321677
18) XX XX XX XX XX 0.307338
19) 4D XX XX KS AS 0.294172
20) 4D XX QS XX AS 0.294172
21) 4D XX QS KS XX 0.294172
22) 4D XX XX XX XX 0.289564
23) XX 10S XX XX XX 0.278670
24) 4D XX QS KS AS 0.191489
25) 4D 10S XX XX AS 0.191489
26) 4D 10S XX KS XX 0.191489
27) 4D 10S QS XX XX 0.191489
28) 4D 10S XX XX XX 0.187542
29) 4D 10S XX KS AS 0.127660
30) 4D 10S QS XX AS 0.127660
31) 4D 10S QS KS XX 0.127660
32) 4D 10S QS KS AS 0.000000

So the maximum EV for this hand is 18.319149



Finally get it work. Now I am able to compute pay back for Jacks or better and other similar video poker game. I am now thinking of the deuces wild game, in which deuce could be any value and any suit. For example, 2C 2H 2S 4S JS, where 2C/2H/2S should be replaced with any card A, 3, 4, ..., J, Q, K of any suit. However, the 134459 unique hands discussed in https://wizardofodds.com/games/video-poker/methodology/ list some hands with certain suits in certain order. If we could like to reuse all codes, unique hands and hand evaluation, I think we should try replacing the each deuces as follows


// hand is sorted
int c1=hand[0], c10=c1;
int c2=hand[1], c20=c2;
int c3=hand[2], c30=c3;
int c4=hand[3], c40=c4;
int c5=hand[4], c50=c5;
int pay, maxpay=0;
int w1=0, w2=0, w3=0, w4=0, w5=0; // wild1, wild2, wild3, wild4, wild5
while ( w1<52 )
{
if (c10==DEUCE)
{
c1 = w1; // if for DEUCE, replace the card with 0 to 51 one at a time
w1++;
} else w1=52; // end the loop
w2 = 0;
while ( w2<52 )
{
if (c20==DEUCE)
{
c2 = w2; // if for DEUCE, replace the card with 0 to 51 one at a time
w2++;
} else w2=52;
w3 = 0;
while (w3<52)
{
if (c30==DEUCE)
{
c3 = w3; // if for DEUCE, replace the card with 0 to 51 one at a time
w3++;
} else w3=52;
w4 = 0;
while (w4<52)
{
if (c40==DEUCE)
{
c4 = w4; // if for DEUCE, replace the card with 0 to 51 one at a time
w4++;
} else w4=52;
w5 = 0;
while (w5<52)
{
if (c50==DEUCE)
{
c5 = w5; // if for DEUCE, replace the card with 0 to 51 one at a time
w5++;
} else w5=52;
pay = evaluate_hand_with_wild_substitute(c1, c2, c3, c4, c5);
if (pay>maxpay)
{
maypay = pay;
}
}
}
}
}
}


This code enumerate all possible substitutions and find the best substitute. But with above method, the deuces may be replaced any suits such that the substituted hand is not listed in tables shown in https://wizardofodds.com/games/video-poker/methodology/. To make it correct, should I just enumerate all substituted hands and only keep that with face values and suits matched to those listed in the 134459 hands?

Secondly, should I build a different array1, array2, array3, array4, array5 for deuces wild?

Regardless of the computation, I am sort of concern on the efficiency of the code. Enumerating each wild 52 times makes it so slow, any suggestion how to improve the efficiency with wild substitution?
  • Jump to: