Two Plus Two Poker Forums PLO Hand Lookup program
 User Name Remember Me? Password
 Register FAQ Search Today's Posts Mark Forums Read TwoPlusTwo.com

 Notices The Theory of Poker Applied to No-Limit now available For those of you here in Las Vegas, The Theory of Poker Applied to No-Limit by David Sklansky is now available at Gamblers General Store/ GAMBLER'S BOOK CLUB in downtown Las Vegas. Their address is 727 S Main St, Las Vegas, NV 89101 and their phone number is (702) 382-9903. We also have this title available in several special poker book promotions directly from Two Plus Two Publishing. For more info or to ask questions check out this thread in the books and publications forum: Sklansky Invites Reviews, Comments, And Questions, About Theory of Poker Applied To No Limit .

 Programming Discussions about computer programming

 Thread Tools Display Modes
 09-21-2018, 10:25 AM #1 Steve journeyman     Join Date: Jan 2003 Location: Florida Posts: 276 PLO Hand Lookup program There are 270,725 (52C4) starting hands in Omaha, counting suits. I wrote a program that puts them all in a list. Hand #1: 2c 3c 4c 5c Hand #2: 2c 3c 4c 6c Hand #3: 2c 3c 4c 7c Hand #4: 2c 3c 4c 8c .etc Hand #48: 2c 3c 4c Ks Hand #49: 2c 3c 4c As Hand #50: 2c 3c 5c 6c Hand #51: 2c 3c 5c 7c .etc Hand #270722: Ts Js Qs As Hand #270723: Ts Js Ks As Hand #270724: Ts Qs Ks As Hand #270725: Js Qs Ks As Great. So now, how do we do the reverse? Given four random cards, such as (7d 8d Kh Ks) is there an elegant formula that will compute its hand number? I want to store some statistics for each hand in an array[270725] and then quickly look up a hand.
 09-21-2018, 12:30 PM #2 RustyBrooks Carpal \'Tunnel     Join Date: Feb 2006 Location: Austin, TX Posts: 24,465 Re: PLO Hand Lookup program I feel like there has to be a way to do this, but I spent a little time this morning and came up fairly blank, in terms of a straightforward numeric algorithm Can you do me a favor and send me your hand list? I could generate it myself but it would save me some time. I have a few ideas. I assume you'll be using C/C++? If not I'd say just use a hashmap.
 09-21-2018, 01:20 PM #3 Steve journeyman     Join Date: Jan 2003 Location: Florida Posts: 276 Re: PLO Hand Lookup program Here's the code, is that what you wanted? Or do you want a file with all 270725 hands in it? public function EnumerateOmahaHands() { var totalHands = 0; for (var c0 = 0; c0 < 1; c0++) { for (var c1 = c0+1; c1 < 50; c1++) { for (var c2 = c1+1; c2 < 51; c2++) { for (var c3 = c2+1; c3 < 52; c3++) { totalHands++; trace("HAND #" + totalHands + ": " + GetCard(c0) + " " + GetCard(c1) + " " + GetCard(c2) + " " + GetCard(c3)); } } } } } public function GetCard(card:Number) { var cardString = ""; var rankArray = "23456789TJQKA"; var suitArray = "cdhs"; cardString += rankArray.charAt(card % 13); cardString += suitArray.charAt(card / 13); return cardString; }
 09-21-2018, 02:04 PM #4 jukofyork Carpal \'Tunnel     Join Date: Sep 2004 Posts: 11,365 Re: PLO Hand Lookup program Code: ```// First make a lookup table of all the 24 possible hand ordering permutations: int PERMS[24][4]={{0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1}, {1, 0, 2, 3}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0}, {2, 0, 1, 3}, {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, {3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0}}; // Next we need a function to map an unordered 4-card hand to a unique integer. // NOTE: 140608=52^3, 2704=52^2, etc. int getIndex(int c0, int c1, int c2, int c3) { return c0*140608 + c1*2704 + c2*52 + c3; } // Next create a lookup table of size 52^4, which we will populate so as to map from unordered --> ordered index. int lookup[7311616]; // You can now populate this as you create your ordering: int handIndex=0; for (int c0 = 0; c0 < 49; c0++) { for (int c1 = c0+1; c1 < 50; c1++) { for (int c2 = c1+1; c2 < 51; c2++) { for (int c3 = c2+1; c3 < 52; c3++) { int hand[4]={c0, c1, c2, c3}; for (int i=0; i<24; i++) { lookup[getIndex(hand[PERMS[i][0]],hand[PERMS[i][1]],hand[PERMS[i][2]],hand[PERMS[i][3]])]=handIndex; } handIndex++; } } } } . . . // Now you can lookup your ordered hand index in O(1) from an unordered hand using: int handIndex=lookup[getIndex(c0,c1,c2,c3)];``` PS: Be careful if you copy my code exactly and write this in C/C++: putting a ~30MB array on the stack will cause a stack overflow! Either use "static int lookup[7311616];" or allocate it dynamically to ensure it goes on the heap. Juk Last edited by jukofyork; 09-21-2018 at 02:19 PM.
09-21-2018, 02:16 PM   #5
jukofyork
Carpal \'Tunnel

Join Date: Sep 2004
Posts: 11,365
Re: PLO Hand Lookup program

Quote:
 Originally Posted by Steve Code: ```public function EnumerateOmahaHands() { var totalHands = 0; for (var c0 = 0; c0 < 1; c0++) { for (var c1 = c0+1; c1 < 50; c1++) { for (var c2 = c1+1; c2 < 51; c2++) { for (var c3 = c2+1; c3 < 52; c3++) { totalHands++; trace("HAND #" + totalHands + ": " + GetCard(c0) + " " + GetCard(c1) + " " + GetCard(c2) + " " + GetCard(c3)); } } } } }```
Surely that should be 49 or else you'll only generate hands starting with 2c?

Juk

09-21-2018, 02:47 PM   #6
Steve
journeyman

Join Date: Jan 2003
Location: Florida
Posts: 276
Re: PLO Hand Lookup program

Quote:
 Originally Posted by jukofyork Surely that should be 49 or else you'll only generate hands starting with 2c? Juk
Yikes, sorry yep that's what I meant.

09-21-2018, 02:51 PM   #7
Steve
journeyman

Join Date: Jan 2003
Location: Florida
Posts: 276
Re: PLO Hand Lookup program

Quote:
 Originally Posted by jukofyork Code: ```// First make a lookup table of all the 24 possible hand ordering permutations: int PERMS[24][4]={{0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1}, {1, 0, 2, 3}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0}, {2, 0, 1, 3}, {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, {3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0}}; // Next we need a function to map an unordered 4-card hand to a unique integer. // NOTE: 140608=52^3, 2704=52^2, etc. int getIndex(int c0, int c1, int c2, int c3) { return c0*140608 + c1*2704 + c2*52 + c3; } // Next create a lookup table of size 52^4, which we will populate so as to map from unordered --> ordered index. int lookup[7311616]; // You can now populate this as you create your ordering: int handIndex=0; for (int c0 = 0; c0 < 49; c0++) { for (int c1 = c0+1; c1 < 50; c1++) { for (int c2 = c1+1; c2 < 51; c2++) { for (int c3 = c2+1; c3 < 52; c3++) { int hand[4]={c0, c1, c2, c3}; for (int i=0; i<24; i++) { lookup[getIndex(hand[PERMS[i][0]],hand[PERMS[i][1]],hand[PERMS[i][2]],hand[PERMS[i][3]])]=handIndex; } handIndex++; } } } } . . . // Now you can lookup your ordered hand index in O(1) from an unordered hand using: int handIndex=lookup[getIndex(c0,c1,c2,c3)];``` PS: Be careful if you copy my code exactly and write this in C/C++: putting a ~30MB array on the stack will cause a stack overflow! Either use "static int lookup[7311616];" or allocate it dynamically to ensure it goes on the heap. Juk
Thanks Juk. I'm still hoping there is an elegant formula for looking up a hand# that doesn't involve creating this 7MB table in memory. This is going to be in a JavaScript poker tool and I was hoping to avoid creating that at runtime (or having to download 7MB). But, there may not be a formula.

 09-21-2018, 03:19 PM #8 RustyBrooks Carpal \'Tunnel     Join Date: Feb 2006 Location: Austin, TX Posts: 24,465 Re: PLO Hand Lookup program yeah so if it's javascript I would just say use a hashmap instead of a numeric array
09-21-2018, 05:18 PM   #9
jukofyork
Carpal \'Tunnel

Join Date: Sep 2004
Posts: 11,365
Re: PLO Hand Lookup program

Quote:
 Originally Posted by Steve Thanks Juk. I'm still hoping there is an elegant formula for looking up a hand# that doesn't involve creating this 7MB table in memory. This is going to be in a JavaScript poker tool and I was hoping to avoid creating that at runtime (or having to download 7MB). But, there may not be a formula.
Here's a rough outline of a method that requires no lookup table (but is more costly per operation):

Given an unordered 4-tuple:

You first need sort it into ascending order. The most efficient method for this is to use a 4-element sorting network, eg:

Code:
```void sortInPlace(int& c0, int& c1, int& c2, int& c3) {
SWAP_IF_GREATER_THAN(c0,c2);
SWAP_IF_GREATER_THAN(c1,c3);
SWAP_IF_GREATER_THAN(c0,c1);
SWAP_IF_GREATER_THAN(c2,c3);
SWAP_IF_GREATER_THAN(c1,c2);
}```
Then you need to use the idea of combinadics to be able to directly generate a position in the lexicographic ordering, eg:

Code:
```int getHandIndex(int c0, int c1, int c2, int c3) {
return binomial(c0,1) + binomial(c1,2) + binomial(c2,3) + binomial(c3,4);
}```
So then you can get your hand index directly like so:

Code:
```sortInPlace(c0,c1,c2,c3);
int handIndex=getHandIndex(c0,c1,c2,c3);```
(you'll have to search for a javascript implementation of binomial(). In C++ you can use the boost library's binomial_coefficient() function - perhaps have a look at the source for that?)

Juk

Last edited by jukofyork; 09-21-2018 at 05:30 PM.

09-21-2018, 06:23 PM   #10
jukofyork
Carpal \'Tunnel

Join Date: Sep 2004
Posts: 11,365
Re: PLO Hand Lookup program

Too late to edit now, but I just noticed that the code above doesn't actually generate the indices in the same order as your loops. From the wiki page:

Quote:
 So comparing the 5-combinations C = {0,3,4,6,9} and C' = {0,1,3,7,9}, one has that C comes before C', since they have the same largest part 9, but the next largest part 6 of C is less than the next largest part 7 of C'; the sequences compared lexicographically are (9,6,4,3,0) and (9,7,3,1,0)
I *think* this should generate the ordering in exactly the same way as your loops though:

Code:
```int getHandIndex(int c0, int c1, int c2, int c3) {
return 270724 - binomial(52-(c1+1),4) - binomial(52-(c2+1),3) - binomial(52-(c3+1),2) - binomial(52-(c4+1),1);
}```
Also, the "National Lottery example in Excel" example shows a slight optimisation as: binomial(52-(c4+1),1) = 51-c4

Code:
```int getHandIndex(int c0, int c1, int c2, int c3) {
return 270673 - binomial(52-(c1+1),4) - binomial(52-(c2+1),3) - binomial(52-(c3+1),2) + c4;
}```
Juk

Last edited by jukofyork; 09-21-2018 at 06:28 PM.

 09-21-2018, 07:04 PM #11 jukofyork Carpal \'Tunnel     Join Date: Sep 2004 Posts: 11,365 Re: PLO Hand Lookup program Courtesy of Mathematica's "simplify", here's the final function along with a small test driver: Code: ```#include // NOTE: Must have c0 < c1 < c2 < c3. int getHandIndex(int c0, int c1, int c2, int c3) { return (484902*c0 - 14699*c0*c0 + 198*c0*c0*c0 - c0*c0*c0*c0 + 4*(-7962 + 7499*c1 - 150*c1*c1 + c1*c1*c1 + 303*c2 - 3*c2*c2 + 6*c3))/24; } int main() { int handIndex=0; for (int c0 = 0; c0 < 49; c0++) { for (int c1 = c0+1; c1 < 50; c1++) { for (int c2 = c1+1; c2 < 51; c2++) { for (int c3 = c2+1; c3 < 52; c3++) { std::cout << handIndex << " = " << getHandIndex(c0,c1,c2,c3) << "\n"; handIndex++; } } } } }``` (just paste it into http://cpp.sh/ and hit "run") I'm not sure if I'd call it an "elegant formula" as the OP hoped for, but it does seem to work! Juk
09-21-2018, 09:17 PM   #12
Steve
journeyman

Join Date: Jan 2003
Location: Florida
Posts: 276
Re: PLO Hand Lookup program

Quote:
 Originally Posted by jukofyork I'm not sure if I'd call it an "elegant formula" as the OP hoped for, but it does seem to work! Juk
THAT'S INCREDIBLE!

And yes, I call that elegant x 10^23

I'm reading up on the lottery example now. THANKS JUK!

09-22-2018, 07:30 AM   #13
jukofyork
Carpal \'Tunnel

Join Date: Sep 2004
Posts: 11,365
Re: PLO Hand Lookup program

Quote:
 Originally Posted by Steve THAT'S INCREDIBLE! And yes, I call that elegant x 10^23 I'm reading up on the lottery example now. THANKS JUK!
NP

If you search google for 'site:twoplustwo.com combinadics' and 'site:twoplustwo.com "sorting network"' then you'll find some other posts I made (~10 years ago) about using this same method in the "7 Card Hand Evaluators" thread.

Juk

09-26-2018, 03:57 PM   #14
browni3141
veteran

Join Date: Aug 2015
Location: South Florida
Posts: 3,365
Re: PLO Hand Lookup program

Quote:
 Originally Posted by Steve I want to store some statistics for each hand in an array[270725] and then quickly look up a hand.
Why not just use a hash table?

 09-28-2018, 11:35 AM #15 stlows journeyman   Join Date: Apr 2016 Posts: 218 Re: PLO Hand Lookup program Ehn you create your hands, jsut store them in a hash table... Code: ```public function EnumerateOmahaHands() { var hands = {}; var totalHands = 0; for (var c0 = 0; c0 < 1; c0++) { for (var c1 = c0+1; c1 < 50; c1++) { for (var c2 = c1+1; c2 < 51; c2++) { for (var c3 = c2+1; c3 < 52; c3++) { totalHands++; var hand = GetCard(c0) + " " + GetCard(c1) + " " + GetCard(c2) + " " + GetCard(c3); trace("HAND #" + totalHands + ": " + hand ); hands[hand] = totalHands; } } } } return hands; } public function GetCard(card:Number) { var cardString = ""; var rankArray = "23456789TJQKA"; var suitArray = "cdhs"; cardString += rankArray.charAt(card % 13); cardString += suitArray.charAt(card / 13); return cardString; }``` Now you can do: Code: ```var hands = EnumerateOmahaHands() var handNumber = hands["2c 6s 8h Td"];``` And it's gonna give you the number !
 09-28-2018, 02:37 PM #16 jukofyork Carpal \'Tunnel     Join Date: Sep 2004 Posts: 11,365 Re: PLO Hand Lookup program Code: ```// The first 52 prime numbers. uint32_t PRIMES[52] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239}; // NOTE: Cards can be passed in any order as each permutation will have the same unique product of primes. // NOTE: Max key value will be: 227*229*233*239=2,894,777,321 so will fit in an unsigned 32bit integer. uint32_t getKey(int c0, int c1, int c2, int c3) { return PRIMES[c0]*PRIMES[c1]*PRIMES[c2]*PRIMES[c3]; } // Used to map from key --> hand index. std::unordered_map hash; // You can now populate this as you create your ordering: int handIndex=0; for (int c0 = 0; c0 < 49; c0++) { for (int c1 = c0+1; c1 < 50; c1++) { for (int c2 = c1+1; c2 < 51; c2++) { for (int c3 = c2+1; c3 < 52; c3++) { hash[getKey(c0,c1,c2,c3)]=handIndex; handIndex++; } } } } // Now you can lookup your ordered hand index in O(1) from an unordered hand using: int handIndex=hash.at(getKey(c0,c1,c2,c3));``` Juk

 Thread Tools Display Modes Linear Mode

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is Off Forum Rules
 Forum Jump User Control Panel Private Messages Subscriptions Who's Online Search Forums Forums Home Links to Popular Forums     News, Views, and Gossip     Beginners Questions     Marketplace & Staking     Casino & Cardroom Poker     Internet Poker     NL Strategy Forums     Poker Goals & Challenges     Las Vegas Lifestyle     Sporting Events     Other Other Topics Two Plus Two     About the Forums     Two Plus Two Magazine Forum     The Best of Two Plus Two Marketplace & Staking     Commercial Marketplace     General Marketplace     Staking - Offering Stakes     Staking         Staking - Offering Stakes         Staking - Seeking Stakes         Staking - Selling Shares - Online         Staking - Selling Shares - Live         Staking Rails         Transaction Feedback & Disputes     Transaction Feedback & Disputes Coaching & Training     Coaching Advice     Cash Game Poker Coach Listings     Tournament/SNG Poker Coach Listings Poker News & Discussion     News, Views, and Gossip     Poker Goals & Challenges     Poker Beats, Brags, and Variance     That's What She Said!     Poker Legislation & PPA Discussion hosted by Rich Muny     Twitch - Watch and Discuss Live Online Poker     Televised Poker General Poker Strategy     Beginners Questions     Books and Publications     Poker Tells/Behavior, hosted by: Zachary Elwood     Poker Theory     Psychology No Limit Hold'em Strategy     Medium-High Stakes PL/NL     Micro-Small Stakes PL/NL     Medium-High Stakes Full Ring     Micro-Small Stakes Full Ring     Heads Up NL     Live Low-stakes NL Limit Texas Hold'em Strategy     Mid-High Stakes Limit     Micro-Small Stakes Limit Tournament Poker Strategy     STT Strategy     Heads Up SNG and Spin and Gos     Mid-High Stakes MTT     Small Stakes MTT     MTT Community     Tournament Events Other Poker Strategy     High Stakes PL Omaha     Small Stakes PL Omaha     Omaha/8     Stud     Draw and Other Poker Live Poker     Casino & Cardroom Poker         Venues & Communities         Regional Communities     Venues & Communities     Tournament Events         WPT.com     Home Poker     Cash Strategy     Tournament Strategy Internet Poker     Internet Poker         Global Poker         MPN  Microgaming Poker Network         BetOnline.ag Online Poker     Commercial Software     Software         Commercial Software         Free Software General Gambling     Backgammon Forum hosted by Bill Robertie.     Probability     Sports Betting     Other Gambling Games 2+2 Communities     Other Other Topics         OOTV         Game of Thrones     The Lounge: Discussion+Review     EDF     Las Vegas Lifestyle     BBV4Life         omg omg omg     House of Blogs Sports and Games     Sporting Events         Single-Team Season Threads         Fantasy Sports     Fantasy Sports         Sporting Events     Wrestling     Golf     Chess and Other Board Games     Video Games         League of Legends         Hearthstone     Puzzles and Other Games Other Topics     Politics and Society     History     Business, Finance, and Investing     Science, Math, and Philosophy     Religion, God, and Theology     Travel     Health and Fitness     Laughs or Links!     Computer Technical Help     Programming

All times are GMT -4. The time now is 01:29 PM.

 Contact Us - Two Plus Two Publishing LLC - Privacy Statement - Top

Powered by vBulletin®
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
Copyright © 2008-2017, Two Plus Two Interactive