Two Plus Two Publishing LLC
Two Plus Two Publishing LLC
 

Go Back   Two Plus Two Poker Forums > >

Notices

Programming Discussions about computer programming

Reply
 
Thread Tools Display Modes
Old Yesterday, 10:25 AM   #1
Steve
journeyman
 
Steve's Avatar
 
Join Date: Jan 2003
Location: Florida
Posts: 270
Diamond 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.
Steve is offline   Reply With Quote
Old Yesterday, 12:30 PM   #2
RustyBrooks
Carpal \'Tunnel
 
RustyBrooks's Avatar
 
Join Date: Feb 2006
Location: Austin, TX
Posts: 23,838
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.
RustyBrooks is offline   Reply With Quote
Old Yesterday, 01:20 PM   #3
Steve
journeyman
 
Steve's Avatar
 
Join Date: Jan 2003
Location: Florida
Posts: 270
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;
}
Steve is offline   Reply With Quote
Old Yesterday, 02:04 PM   #4
jukofyork
Carpal \'Tunnel
 
jukofyork's Avatar
 
Join Date: Sep 2004
Location: Glastonbury Grove
Posts: 11,314
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; Yesterday at 02:19 PM.
jukofyork is offline   Reply With Quote
Old Yesterday, 02:16 PM   #5
jukofyork
Carpal \'Tunnel
 
jukofyork's Avatar
 
Join Date: Sep 2004
Location: Glastonbury Grove
Posts: 11,314
Re: PLO Hand Lookup program

Quote:
Originally Posted by Steve View Post
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
jukofyork is offline   Reply With Quote
Old Yesterday, 02:47 PM   #6
Steve
journeyman
 
Steve's Avatar
 
Join Date: Jan 2003
Location: Florida
Posts: 270
Re: PLO Hand Lookup program

Quote:
Originally Posted by jukofyork View Post
Surely that should be 49 or else you'll only generate hands starting with 2c?

Juk
Yikes, sorry yep that's what I meant.
Steve is offline   Reply With Quote
Old Yesterday, 02:51 PM   #7
Steve
journeyman
 
Steve's Avatar
 
Join Date: Jan 2003
Location: Florida
Posts: 270
Re: PLO Hand Lookup program

Quote:
Originally Posted by jukofyork View Post
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.
Steve is offline   Reply With Quote
Old Yesterday, 03:19 PM   #8
RustyBrooks
Carpal \'Tunnel
 
RustyBrooks's Avatar
 
Join Date: Feb 2006
Location: Austin, TX
Posts: 23,838
Re: PLO Hand Lookup program

yeah so if it's javascript I would just say use a hashmap instead of a numeric array
RustyBrooks is offline   Reply With Quote
Old Yesterday, 05:18 PM   #9
jukofyork
Carpal \'Tunnel
 
jukofyork's Avatar
 
Join Date: Sep 2004
Location: Glastonbury Grove
Posts: 11,314
Re: PLO Hand Lookup program

Quote:
Originally Posted by Steve View Post
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; Yesterday at 05:30 PM.
jukofyork is offline   Reply With Quote
Old Yesterday, 06:23 PM   #10
jukofyork
Carpal \'Tunnel
 
jukofyork's Avatar
 
Join Date: Sep 2004
Location: Glastonbury Grove
Posts: 11,314
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; Yesterday at 06:28 PM.
jukofyork is offline   Reply With Quote
Old Yesterday, 07:04 PM   #11
jukofyork
Carpal \'Tunnel
 
jukofyork's Avatar
 
Join Date: Sep 2004
Location: Glastonbury Grove
Posts: 11,314
Re: PLO Hand Lookup program

Courtesy of Mathematica's "simplify", here's the final function along with a small test driver:
Code:
#include <iostream>

// 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
jukofyork is offline   Reply With Quote
Old Yesterday, 09:17 PM   #12
Steve
journeyman
 
Steve's Avatar
 
Join Date: Jan 2003
Location: Florida
Posts: 270
Re: PLO Hand Lookup program

Quote:
Originally Posted by jukofyork View Post

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!
Steve is offline   Reply With Quote
Old Today, 07:30 AM   #13
jukofyork
Carpal \'Tunnel
 
jukofyork's Avatar
 
Join Date: Sep 2004
Location: Glastonbury Grove
Posts: 11,314
Re: PLO Hand Lookup program

Quote:
Originally Posted by Steve View Post
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
jukofyork is offline   Reply With Quote

Reply
      

Thread Tools
Display Modes

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 Jump


All times are GMT -4. The time now is 09:57 AM.


Powered by vBulletin®
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Copyright © 2008-2017, Two Plus Two Interactive
 
 
Poker Players - Streaming Live Online