CrystalMath
CrystalMath
  • Threads: 8
  • Posts: 1911
Joined: May 10, 2011
September 8th, 2014 at 8:32:58 PM permalink
Quote: konglify



I wrote the code but it give me something very odd. I think I mess up the array1 to array5. In your statement, you said ""Array1 holds a count of all the possible 5 card hands that each 4 card hand can draw to." Let's consider the array1 only, to build that I enumerate each of all 2598960 hands, for one hand, I hold 1 card only and try to fill the other 4 with the cards hold in the rest of the deck and I make a index with that 4 cards, which is used to build the table, is that correct?



Loop through all 2598960 hands.
In each of those hands, find all four card hands, and increment array1.

For instance, say we have the 5 card hand AC TC 5C 3C 2C. It evaluates to a flush (=5).
Now, find all four card hands that can be made from this hand:

AC TC 5C 3C
AC TC 5C 2C
AC TC 3C 2C
AC 5C 3C 2C
TC 5C 3C 2C

Lets say AC TC 5C 3C has an index of i1, then we'll increment array1: array1[i1][5]++;// (The 5 is for the flush that the 5 card hand evaluated to)
I heart Crystal Math.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 8th, 2014 at 8:45:21 PM permalink
Quote: CrystalMath

Loop through all 2598960 hands.
In each of those hands, find all four card hands, and increment array1.

For instance, say we have the 5 card hand AC TC 5C 3C 2C. It evaluates to a flush (=5).
Now, find all four card hands that can be made from this hand:

AC TC 5C 3C
AC TC 5C 2C
AC TC 3C 2C
AC 5C 3C 2C
TC 5C 3C 2C

Lets say AC TC 5C 3C has an index of i1, then we'll increment array1: array1[i1][5]++;// (The 5 is for the flush that the 5 card hand evaluated to)



Many thanks. So I modify the code in the following pseudo code


for i=1 to 2598960
begin
hand(i)
win_index = evaluate_win_index(hand(i))
for each 4 cards in hand(i)
begin
index = evaluate_4card_index(4 cards)
array1[index][win_index]++
end

for each 3 cards in hand(i)
begin
index = evaluate_3card_index(3 cards)
array2[index][win_index]++
end

for each 2 cards in hand(i)
begin
index = evaluate_2card_index(2 cards)
array3[index][win_index]++
end

for each 1 card in hand(i)
begin
index = evaluate_1card_index(1 card)
array4[index][win_index]++
end
end


It is still confusing me that how to fill array0 and array5
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
September 8th, 2014 at 9:12:35 PM permalink
Quote: konglify

It is still confusing me that how to fill array0 and array5


Array0 would have as many elements as there are types of hands, so for Jacks or Better, 10.

Array5 can be handled differently. Instead of having 2,598,960 * 10 elements, just have 2,598,960 elements, and when it comes time to determine the raw number of hands with a certain 5-card combination, use 0 (zero) unless the hand type you're checking is the hand type the 5 cards correspond to, in which case use 1.

To clarify the purpose of each array, I name mine as follows:

HandsWith0 = hands of each type with 0 known cards = combin(52,0) * 10 = 10 elements
HandsWith1 = hands of each type with 1 known card = combin(52,1) * 10 = 520 elements
HandsWith2 = hands of each type with 2 known cards = combin(52,2) * 10 = 13,260 elements
HandsWith3 = hands of each type with 3 known cards = combin(52,3) * 10 = 221,000 elements
HandsWith4 = hands of each type with 4 known cards = combin(52,4) * 10 = 2,707,250 elements
HandType = the hand type of each 5-card combination = combin(52,5) elements

It would be a waste of memory to make a HandsWith5 having combin(52,5) * 10 elements, therefore I call it HandType with just combin(52,5) elements and determine (when the time comes) if the count should be 0 or 1 according to the hand being scored and the hand count needed.

Also, to conserve memory:

HandsWith0 and HandsWith1 can be 32-bit integers (int)
HandsWith2 and HandsWith3 can be 16-bit integers (short)
HandsWith4 and HandType can be 8-bit integers (byte)

This works out nicely because the arrays with more elements need fewer bytes per element.
CrystalMath
CrystalMath
  • Threads: 8
  • Posts: 1911
Joined: May 10, 2011
September 8th, 2014 at 9:14:08 PM permalink
The pseudo code looks good.

array0 is just the win index for each of the C(52,5) hands. array0[5 card index] = win_index
array5 should look something like: array5[win_index]++
I heart Crystal Math.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 9th, 2014 at 6:08:05 PM permalink
After spending some times on this, I finally setup the correct array0 to array5. I then read the page at http://www.vpgenius.com/articles/analyzing-video-poker-hands.aspx, where it gaves a table to combine the hit while holding zero card, 1 card @ any 1 out of 5 place, 2 cards @ any 2 out of 5 place ... So does the next step to calculate the maximum payout be something like this?


for i=1 to 324459
begin
for n=1 to 32
begin
hit(n) = evaluate_pay(hand(i))
end
combine hits(n=1 to 32) based on the table to give pay(n)
the pay for hand(i) is max{pay(n)}
end

is that correct?
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
September 9th, 2014 at 6:41:03 PM permalink
Just make sure that when you compare the 32 ways to play a hand, you don't compare absolute values. For example, the sum of all possible pays for holding 0 cards is likely to exceed the sum of all possible pays for holding 4 cards, even if holding 4 cards is the better play. In other words, divide the absolute value (sum of all possible pays) by the number of draw combinations for that hold, before comparing them. Alternatively, you can keep them integers by applying weight factors to the sums, but that's a topic for another day.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 9th, 2014 at 10:30:41 PM permalink
Quote: JB

Just make sure that when you compare the 32 ways to play a hand, you don't compare absolute values. For example, the sum of all possible pays for holding 0 cards is likely to exceed the sum of all possible pays for holding 4 cards, even if holding 4 cards is the better play. In other words, divide the absolute value (sum of all possible pays) by the number of draw combinations for that hold, before comparing them. Alternatively, you can keep them integers by applying weight factors to the sums, but that's a topic for another day.



In "divide the absolute value (sum of all possible pays) by the number of draw combinations for that hold", the number of draw combinations for that hold, do you mean for example, hold 2 cards, should the divisor be combin(52-5, 3)? I try that way but I got overal payback very large.
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
September 9th, 2014 at 10:32:05 PM permalink
Quote: konglify

In "divide the absolute value (sum of all possible pays) by the number of draw combinations for that hold", the number of draw combinations for that hold, do you mean for example, hold 2 cards, should the divisor be combin(52-5, 3)? I try that way but I got overal payback very large.


Correct. Once you've determined the EV of the best play, multiply it by the unique hand's weight factor (4, 12, or 24) and add it to the running total for the game. Once all 134,459 unique hands have been analyzed, divide the running total for the game by 2,598,960 to get the long-term return.
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 10th, 2014 at 10:07:33 AM permalink
Hi all,
I am very close to completing the fast algorithm but it ends up with pretty high payback, I got 1870.27 instead. I have double check all parts and still can't tell which part goes wrong. Let me explain my algorithm with some critical but real code post below and let me know if you see any thing not right. I am using c++ and stl algorithm for coding. The card representation is the very regular one, i.e. I map each card to 0 to 51 inclusive. The face value is n%13 and the suit is (int)(n/13)

Here is the rank I use for all winning hands

#define ROYAL_FLUSH 0
#define STRAIGHT_FLUSH 1
#define FOUR_OF_A_KIND 2
#define FULL_HOUSE 3
#define FLUSH 4
#define STRAIGHT 5
#define THREE_OF_A_KIND 6
#define TWO_PAIR 7
#define JACKS_BETTER 8
#define ONE_PAIR 9
#define HIGH_CARD 10


The paytable is the 9/6

int PAYTABLE[HIGH_CARD+1];

PAYTABLE[ROYAL_FLUSH] = 800;
PAYTABLE[STRAIGHT_FLUSH] = 50;
PAYTABLE[FOUR_OF_A_KIND] = 25;
PAYTABLE[FULL_HOUSE] = 9;
PAYTABLE[FLUSH] = 6;
PAYTABLE[STRAIGHT] = 4;
PAYTABLE[THREE_OF_A_KIND] = 3;
PAYTABLE[TWO_PAIR] = 2;
PAYTABLE[JACKS_BETTER] = 1;
PAYTABLE[ONE_PAIR] = 0;
PAYTABLE[HIGH_CARD] = 0;


I firstly loop through all 2598960 hands to build array0 to array5 based on CrystalMath's explanation

map<int, int> array0, array5;
map< int, map<int, int> > array1, array2, array3, array4;

void GenAllHandsAndArrays(void)
{
int hand[5], deck[52];
for (int i=0; i<52; i++) deck[ i ]=i;

array5.insert(pair<int, int>(ROYAL_FLUSH, 0));
array5.insert(pair<int, int>(STRAIGHT_FLUSH, 0));
array5.insert(pair<int, int>(FOUR_OF_A_KIND, 0));
array5.insert(pair<int, int>(FULL_HOUSE, 0));
array5.insert(pair<int, int>(FLUSH, 0));
array5.insert(pair<int, int>(STRAIGHT, 0));
array5.insert(pair<int, int>(THREE_OF_A_KIND, 0));
array5.insert(pair<int, int>(TWO_PAIR, 0));
array5.insert(pair<int, int>(JACKS_BETTER, 0));
array5.insert(pair<int, int>(ONE_PAIR, 0));
array5.insert(pair<int, int>(HIGH_CARD, 0));

for (int a=0; a<48; a++)
{
hand[0] = deck[ a];
for (int b=a+1; b<49; b++)
{
hand[1] = deck[ b];
for (int c=b+1; c<50; c++)
{
hand[2] = deck[ c];
for (int d=c+1; d<51; d++)
{
hand[3] = deck[ d];
for (int e=d+1; e<52; e++)
{
hand[4] = deck[ e];
short winhand = hand_rank(eval_5hand(hand));

array0[HandIndex5(hand)] = winhand;
array5[winhand]++;
FillArray4(hand, winhand);
FillArray3(hand, winhand);
FillArray2(hand, winhand);
FillArray1(hand, winhand);
}
}
}
}
}
cout << "array0 size = " << array0.size() << endl; // it returns 2598960
cout << "array1 size = " << array1.size() << endl; // it returns 52
cout << "array2 size = " << array2.size() << endl; // it returns 1326
cout << "array3 size = " << array3.size() << endl; // it returns 22100
cout << "array4 size = " << array4.size() << endl; // it returns 270725
cout << "array5 size = " << array5.size() << endl; // it returns 11
}


where the FillArrayxx functions are given as

// in below code, winhand is the index of winning hand, i.e. ROYAL_FLUSH, STRAIGHT_FLUSH ...
inline void FillArray4(const int hand[5], int winhand)
{
int pos[5][4]={{0,1,2,3},{0,1,2,4},{0,1,3,4},{0,2,3,4},{1,2,3,4}};
int index;

for (int r=0; r<5; r++)
{
index = HandIndex4(hand[pos[ r][0]], hand[pos[ r][1]], hand[pos[ r][2]], hand[pos[ r][3]]);
if (array4.find(index)!=array4.end()) array4[index][winhand]++;
else
{
map<int, int> weight;
weight.insert(pair<int, int>(ROYAL_FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT_FLUSH, 0));
weight.insert(pair<int, int>(FOUR_OF_A_KIND, 0));
weight.insert(pair<int, int>(FULL_HOUSE, 0));
weight.insert(pair<int, int>(FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT, 0));
weight.insert(pair<int, int>(THREE_OF_A_KIND, 0));
weight.insert(pair<int, int>(TWO_PAIR, 0));
weight.insert(pair<int, int>(JACKS_BETTER, 0));
weight.insert(pair<int, int>(ONE_PAIR, 0));
weight.insert(pair<int, int>(HIGH_CARD, 0));
array4.insert(pair<int, map<int, int> >(index, weight));
array4[index][winhand]++;
}
}
}

inline void FillArray3(const int hand[5], int winhand)
{
int pos[10][3]={{0,1,2},{0,1,3},{0,1,4},{0,2,3},{0,2,4},{0,3,4},{1,2,3},{1,2,4},{1,3,4},{2,3,4}};
int index;

for (int r=0; r<10; r++)
{
index = HandIndex3(hand[pos[ r][0]], hand[pos[ r][1]], hand[pos[ r][2]]);
if (array3.find(index)!=array3.end()) array3[index][winhand]++;
else
{
map<int, int> weight;
weight.insert(pair<int, int>(ROYAL_FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT_FLUSH, 0));
weight.insert(pair<int, int>(FOUR_OF_A_KIND, 0));
weight.insert(pair<int, int>(FULL_HOUSE, 0));
weight.insert(pair<int, int>(FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT, 0));
weight.insert(pair<int, int>(THREE_OF_A_KIND, 0));
weight.insert(pair<int, int>(TWO_PAIR, 0));
weight.insert(pair<int, int>(JACKS_BETTER, 0));
weight.insert(pair<int, int>(ONE_PAIR, 0));
weight.insert(pair<int, int>(HIGH_CARD, 0));
array3.insert(pair<int, map<int, int> >(index, weight));
array3[index][winhand]++;
}
}
}

inline void FillArray2(const int hand[5], int winhand)
{
int pos[10][2]={{0,1},{0,2},{0,3},{0,4},{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}};
int index;

for (int r=0; r<10; r++)
{
index = HandIndex2(hand[pos[ r][0]], hand[pos[ r][1]]);
if (array2.find(index)!=array2.end()) array2[index][winhand]++;
else
{
map<int, int> weight;
weight.insert(pair<int, int>(ROYAL_FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT_FLUSH, 0));
weight.insert(pair<int, int>(FOUR_OF_A_KIND, 0));
weight.insert(pair<int, int>(FULL_HOUSE, 0));
weight.insert(pair<int, int>(FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT, 0));
weight.insert(pair<int, int>(THREE_OF_A_KIND, 0));
weight.insert(pair<int, int>(TWO_PAIR, 0));
weight.insert(pair<int, int>(JACKS_BETTER, 0));
weight.insert(pair<int, int>(ONE_PAIR, 0));
weight.insert(pair<int, int>(HIGH_CARD, 0));
array2.insert(pair<int, map<int, int> >(index, weight));
array2[index][winhand]++;
}
}
}

inline void FillArray1(const int hand[5], int winhand)
{
int pos[5]={0, 1, 2, 3, 4};
int index;

for (int r=0; r<5; r++)
{
index = (int)hand[ r];
if (array1.find(index)!=array1.end()) array1[index][winhand]++;
else
{
map<int, int> weight;
weight.insert(pair<int, int>(ROYAL_FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT_FLUSH, 0));
weight.insert(pair<int, int>(FOUR_OF_A_KIND, 0));
weight.insert(pair<int, int>(FULL_HOUSE, 0));
weight.insert(pair<int, int>(FLUSH, 0));
weight.insert(pair<int, int>(STRAIGHT, 0));
weight.insert(pair<int, int>(THREE_OF_A_KIND, 0));
weight.insert(pair<int, int>(TWO_PAIR, 0));
weight.insert(pair<int, int>(JACKS_BETTER, 0));
weight.insert(pair<int, int>(ONE_PAIR, 0));
weight.insert(pair<int, int>(HIGH_CARD, 0));
array1.insert(pair<int, map<int, int> >(index, weight));
array1[index][winhand]++;
}
}
}


Note that to calculate the winning hand index, I convert the hand in my representation to Cactus Kev's Poker hand evaluator (http://www.suffecool.net/poker/evaluator.html) and using his functions hand_rank & eval_5hand, those functions are fully tested so I didn't give the code here.

Again, to find the index of 2 cards, 3 cards, ..., 5 cards, I copy the code from http://www.suffecool.net/poker/evaluator.html but with the combin_array replaced with my function choose(n, k)


unsigned int choose(unsigned int n, unsigned int k)
{
if (k==0) return 1;
else return (n*choose(n-1,k-1))/k;
}

int HandIndex2(int c1, int c2)
{
int r;
r=choose(52,2)-choose(52-c1,2);
r+=choose(51-c1,1)-choose(52-c2,1);
return r;
}

int HandIndex3(int c1, int c2, int c3)
{
int r;
r=choose(52,3)-choose(52-c1,3);
r+=choose(51-c1,2)-choose(52-c2,2);
r+=choose(51-c2,1)-choose(52-c3,1);
return r;
}

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

int HandIndex5(int CardIndex[])
{
int r;
r=choose(52,5)-choose(52-CardIndex[0],5);
r+=choose(51-CardIndex[0],4)-choose(52-CardIndex[1],4);
r+=choose(51-CardIndex[1],3)-choose(52-CardIndex[2],3);
r+=choose(51-CardIndex[2],2)-choose(52-CardIndex[3],2);
r+=choose(51-CardIndex[3],1)-choose(52-CardIndex[4],1);
return r;
}


The very last thing is to generate the 133456 unique hands, this was done in my previous poker evaluator discussed in the beginning of this post and I give the same payback with that code so all those unique hands must be correctly generated. I store all those hands into a map call uniqueHands. The following code is used to enumerate each unique hand, search the hit from array0 to array5, find the pay and calculate the maximum payout for each unique hand


void CheckAllHands(void)
{
int hand[5], duplicateCounts;
double payoff=0.0, maxpayoff=0.0;
long totalCreditIn =0, totalPayoff=0;
long pays[32];
int ii1=0, ii2=0, ii3=0, ii4=0, ii5=0;
int u1[5] = {0, 1, 2, 3, 4};
int u2[10][2] = { {0,1}, {0,2}, {0,3}, {0,4}, {1,2}, {1,3}, {1,4}, {2,3}, {2,4}, {3,4} };
int u3[10][3] = { {0,1,2}, {0,1,3}, {0,1,4}, {0,2,3}, {0,2,4}, {0,3,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4} };
int u4[5][4] = { {0,1,2,3}, {0,1,2,4}, {0,1,3,4}, {0,2,3,4}, {1,2,3,4} };
int u5[1][5] = { {0,1,2,3,4} };
int weights[5];
vector<int> input[32] =
{{0, -1, -2, 3, -4, 5, 6, -7, -8, 9, 10, -11, 12, -13, -14, 15, -16, 17, 18, -19, 20, -21, -22, 23, 24, -25, -26, 27, -28, 29, 30, -31},
{1, -3, -5, 7, -9, 11, 13, -15, -17, 19, 21, -23, 25, -27, -29, 31},
{2, -3, -6, 7, -10, 11, 14, -15, -18, 19, 22, -23, 26, -27, -30, 31},
{3, -7, -11, 15, -19, 23, 27, -31},
{4, -5, -6, 7, -12, 13, -14, 15, -20, 21, 22, -23, 28, -29, -30, 31},
{5, -7, -13, 15, -21, 23, 29, -31},
{6, -7, -14, 15, -22, 23, 30, -31},
{7, -15, -23, 31},
{8, -9, -10, 11, -12, 13, 14, -15, -24, 25, 26, -27, 28, -29, -30, 31},
{9, -11, -13, 15, -25, 27, 29, -31},
{10, -11, -14, 15, -26, 27, 30, -31},
{11, -15, -27, 31},
{12, -13, -14, 15, -28, 29, 30, -31},
{13, -15, -29, 31},
{14, -15, -30, 31},
{15, -31},
{16, -17, -18, 19, -20, 21, 22, -23, -24, 25, 26, -27, 28, -29, -30, 31},
{17, -19, -21, 23, -25, 27, 29, -31},
{18, -19, -22, 23, -26, 27, 30, -31},
{19, -23, -27, 31},
{20, -21, -22, 23, -28, 29, 30, -31},
{21, -23, -29, 31},
{22, -23, -30, 31},
{23, -31},
{24, -25, -26, 27, -28, 29, 30, -31},
{25, -27, -29, 31},
{26, -27, -30, 31},
{27, -31},
{28, -29, -30, 31},
{29, -31},
{30, -31},
{31}
};
map<int, int> whand;
int cb[32];

counts = 0;

// weights is the total combination for dropping 0 cards, 1 card, 2 cards ...
weights[0] = 1;
weights[1] = choose(52-5, 1);
weights[2] = choose(52-5, 2);
weights[3] = choose(52-5, 3);
weights[4] = choose(52-5, 4);
weights[5] = choose(52-5, 5);

// there are total 32 possible replacements (including i=0 stands for no replacement), covert that into a binary and count
// the number of "1" will get how many cards needed to be replace
for (int i=0; i<32; i++) cb[ i]=bitset<5>(i).count();

// for each unique hands out of 133456
for (map< int, vector<int> >::iterator it=uniqueHands.begin(); it!=uniqueHands.end(); it++)
{
duplicateCounts=(*it).second[0]; // the first element store how many hands in 2598960 will give the same hand as this one
hand[0]=(*it).second[1]; // the following 5 numbers will store the card value (ranged 0 to 51)
hand[1]=(*it).second[2];
hand[2]=(*it).second[3];
hand[3]=(*it).second[4];
hand[4]=(*it).second[5];

pays[0] = PAYTABLE[array0[HandIndex5(hand)]]; // for no replacement, just calculate the payout storing to pays[0]
ii1=ii2=ii3=ii4=ii5=0; // ii1 to ii5 used to point to the next index in replacement position
for (int i=1; i<=31; i++) // exclude the NO REPLACEMENT, we still have 31 possible replacements to go through
{
if (cb[ i]==1) // if only one card replaced, look at array1
{
whand = array1[hand[u1[ii1]]];
pays[ i] = whand[ROYAL_FLUSH]*PAYTABLE[ROYAL_FLUSH] + whand[STRAIGHT_FLUSH]*PAYTABLE[STRAIGHT_FLUSH] +
whand[FOUR_OF_A_KIND]*PAYTABLE[FOUR_OF_A_KIND] + whand[FULL_HOUSE]*PAYTABLE[FULL_HOUSE] +
whand[FLUSH]*PAYTABLE[FLUSH] + whand[STRAIGHT]*PAYTABLE[STRAIGHT] +
whand[THREE_OF_A_KIND]*PAYTABLE[THREE_OF_A_KIND] + whand[TWO_PAIR]*PAYTABLE[TWO_PAIR] +
whand[JACKS_BETTER]*PAYTABLE[JACKS_BETTER] + whand[ONE_PAIR]*PAYTABLE[ONE_PAIR] +
whand[HIGH_CARD]*PAYTABLE[HIGH_CARD];
ii1++;
}
else if (cb[ i]==2) // if two cards replaced, look at array2
{
whand = array2[HandIndex2(hand[u2[ii2][0]], hand[u2[ii2][1]])];
pays[ i] = whand[ROYAL_FLUSH]*PAYTABLE[ROYAL_FLUSH] + whand[STRAIGHT_FLUSH]*PAYTABLE[STRAIGHT_FLUSH] +
whand[FOUR_OF_A_KIND]*PAYTABLE[FOUR_OF_A_KIND] + whand[FULL_HOUSE]*PAYTABLE[FULL_HOUSE] +
whand[FLUSH]*PAYTABLE[FLUSH] + whand[STRAIGHT]*PAYTABLE[STRAIGHT] +
whand[THREE_OF_A_KIND]*PAYTABLE[THREE_OF_A_KIND] + whand[TWO_PAIR]*PAYTABLE[TWO_PAIR] +
whand[JACKS_BETTER]*PAYTABLE[JACKS_BETTER] + whand[ONE_PAIR]*PAYTABLE[ONE_PAIR] +
whand[HIGH_CARD]*PAYTABLE[HIGH_CARD];
ii2++;
}
else if (cb[ i]==3) // if 3 cards replaced, look at array3
{
whand = array3[HandIndex3(hand[u3[ii3][0]], hand[u3[ii3][1]], hand[u3[ii3][2]])];
pays[ i] = whand[ROYAL_FLUSH]*PAYTABLE[ROYAL_FLUSH] + whand[STRAIGHT_FLUSH]*PAYTABLE[STRAIGHT_FLUSH] +
whand[FOUR_OF_A_KIND]*PAYTABLE[FOUR_OF_A_KIND] + whand[FULL_HOUSE]*PAYTABLE[FULL_HOUSE] +
whand[FLUSH]*PAYTABLE[FLUSH] + whand[STRAIGHT]*PAYTABLE[STRAIGHT] +
whand[THREE_OF_A_KIND]*PAYTABLE[THREE_OF_A_KIND] + whand[TWO_PAIR]*PAYTABLE[TWO_PAIR] +
whand[JACKS_BETTER]*PAYTABLE[JACKS_BETTER] + whand[ONE_PAIR]*PAYTABLE[ONE_PAIR] +
whand[HIGH_CARD]*PAYTABLE[HIGH_CARD];
ii3++;
}
else if (cb[ i]==4) // if 4 cards replaced, look at array4
{
whand = array4[HandIndex4(hand[u4[ii4][0]], hand[u4[ii4][1]], hand[u4[ii4][2]], hand[u4[ii4][3]])];
pays[ i] = whand[ROYAL_FLUSH]*PAYTABLE[ROYAL_FLUSH] + whand[STRAIGHT_FLUSH]*PAYTABLE[STRAIGHT_FLUSH] +
whand[FOUR_OF_A_KIND]*PAYTABLE[FOUR_OF_A_KIND] + whand[FULL_HOUSE]*PAYTABLE[FULL_HOUSE] +
whand[FLUSH]*PAYTABLE[FLUSH] + whand[STRAIGHT]*PAYTABLE[STRAIGHT] +
whand[THREE_OF_A_KIND]*PAYTABLE[THREE_OF_A_KIND] + whand[TWO_PAIR]*PAYTABLE[TWO_PAIR] +
whand[JACKS_BETTER]*PAYTABLE[JACKS_BETTER] + whand[ONE_PAIR]*PAYTABLE[ONE_PAIR] +
whand[HIGH_CARD]*PAYTABLE[HIGH_CARD];
ii4++;
}
else if (cb[ i]==5) // if 5 cards replaced, look at array5
{
int winhand = hand_rank(eval_5hand(hand));
pays[ i] = array5[winhand]*PAYTABLE[winhand];
}
}
maxpayoff = pays[0]; // set the max payback for the current unique hand to the case without replacement first
for (int i=1; i<32; i++) // look the rest 31 replacement cases to find the corresponding payout
{
payoff = 0.0;
// here we add or subtract some pay to find the correct pay based on the table found in here
// http://www.vpgenius.com/articles/analyzing-video-poker-hands.aspx
for (int j=0; j<input[ i].size(); j++) payoff += sign(input[ i][ j])*pays[abs(input[ i][ j])];
payoff /= (double)weights[cb[ i]]; // we need to divide the weight to get the correct payback
if (payoff>maxpayoff) maxpayoff = payoff; // find the maximum payout
}
totalPayoff += maxpayoff*duplicateCounts; // there are duplicateCounts hands will give exact same payout so times that number
totalCreditIn += duplicateCounts; // so does the total credit in

cout << " Payback: " << totalPayoff/(double)totalCreditIn << endl;
}
}
ThatDonGuy
ThatDonGuy
  • Threads: 117
  • Posts: 6330
Joined: Jun 22, 2011
September 10th, 2014 at 7:32:08 PM permalink
One thing I do to make my version run faster is to use an array for the combination function - i.e. define int Choose[53][6], where Choose[n][k] = your choose(n,k). (I use [53][6] instead of [52][5] so I don't have to subtract 1 from each parameter each time I want to use it.)
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 10th, 2014 at 8:01:17 PM permalink
Quote: ThatDonGuy

One thing I do to make my version run faster is to use an array for the combination function - i.e. define int Choose[53][6], where Choose[n][k] = your choose(n,k). (I use [53][6] instead of [52][5] so I don't have to subtract 1 from each parameter each time I want to use it.)


Yes, that will help to boost the speed. But now my question is above code doesn't give the correct payback and I still don't know which part in the code is wrong.
ThatDonGuy
ThatDonGuy
  • Threads: 117
  • Posts: 6330
Joined: Jun 22, 2011
September 11th, 2014 at 7:52:59 PM permalink
Quote: konglify

But now my question is above code doesn't give the correct payback and I still don't know which part in the code is wrong.


I'll see if I have time to look at it over the weekend. Right now, I'm trying to get my own version (which runs on an Android device) down below six seconds. The main problem is, what the program does is, it lets the user manually enter numbers, then it does the analysis - but then it has to reset most of the lookup tables to the "old" numbers, and, rather than save copies of them (memory tends to be a premium on things like smartphones), I rebuild them from scratch, which takes another four seconds.
ThatDonGuy
ThatDonGuy
  • Threads: 117
  • Posts: 6330
Joined: Jun 22, 2011
September 12th, 2014 at 6:06:33 PM permalink
I'm pretty sure I found an error:

In input[4], -14 should be 14, and 15 should be -15. (The signs should be the same in rows 1, 2, 4, and 8, right?)
  • Jump to: