RaspberryCheeseBlintz
RaspberryCheeseBlintz
  • Threads: 5
  • Posts: 38
Joined: Oct 22, 2011
November 21st, 2011 at 3:06:35 PM permalink
I was wondering if, since you can squeeze a 7 card poker hand into one 64 bit word (7*8 = 56, plus some extra info in the high byte)
there would be any speed advantages for simulations?
weaselman
weaselman
  • Threads: 20
  • Posts: 2349
Joined: Jul 11, 2010
November 21st, 2011 at 3:20:08 PM permalink
You actually only need 42 bits (6*7=42).
But I am not sure I understand where you get a connection with speed here ... And what do you compare with what when you are talking about "advantages".
"When two people always agree one of them is unnecessary"
Paigowdan
Paigowdan
  • Threads: 115
  • Posts: 5692
Joined: Apr 28, 2010
November 21st, 2011 at 3:22:55 PM permalink
Yes, bit mapping as a data structure affords great speed in processing, but may make for messy programming.
Beware of all enterprises that require new clothes - Henry David Thoreau. Like Dealers' uniforms - Dan.
weaselman
weaselman
  • Threads: 20
  • Posts: 2349
Joined: Jul 11, 2010
November 21st, 2011 at 3:26:46 PM permalink
Quote: Paigowdan

Yes, bit mapping as a data structure affords great speed in processing, but may make for messy programming.


The only thing that makes for messy programming is messy programmers.
Bit mapping isn't really a data structure. But if you design a data structure that uses a bit map, that is likely to make your program work slower (or, perhaps, as fast), not faster, but require less memory (unless you are trying to map like every poker hand to a bit or something like that - that would be both slow, and bloated).
"When two people always agree one of them is unnecessary"
teliot
teliot
  • Threads: 43
  • Posts: 2871
Joined: Oct 19, 2009
November 21st, 2011 at 3:43:58 PM permalink
This site has helped me a lot along the way: Poker hand evaluator roundup
Climate Casino: https://climatecasino.net/climate-casino/
Paigowdan
Paigowdan
  • Threads: 115
  • Posts: 5692
Joined: Apr 28, 2010
November 21st, 2011 at 3:44:28 PM permalink
Very true. But if you give programmers less to hang themselves with, there are generally less hangings. This is because there are programmers, and there are PROGRAMMERS.

I was an old school ALGOL programmer on Burroughs (Unisys) equipment back in the day, and by using DEFINEs properly, bit mapping can indeed be well-organized.
Beware of all enterprises that require new clothes - Henry David Thoreau. Like Dealers' uniforms - Dan.
RaspberryCheeseBlintz
RaspberryCheeseBlintz
  • Threads: 5
  • Posts: 38
Joined: Oct 22, 2011
November 21st, 2011 at 5:55:02 PM permalink
Quote: teliot

This site has helped me a lot along the way: Poker hand evaluator roundup



Thanks for the responses, and in particular the above site. I'm afraid I saw too much of myself in the paragraph on "naive simulators" and so will
have to rethink a few things.

My original plan was to code in pascal; will using the provided code be possible in that language, or will I have to learn C++ (and get a compiler for that too)?
MarkAbe
MarkAbe
  • Threads: 1
  • Posts: 52
Joined: Oct 23, 2010
November 21st, 2011 at 6:38:21 PM permalink
Raspberry, that site has a lot of good code. If I remember Pascal at all (it's been a long time) they will not work in Pascal. For most uses C++/C#/Java are easy to adapt between, I'd go with one of them. C++ (from the Gnu C++ compiler) and Java are free. C# you will probably have to pay Microsoft for.
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
November 22nd, 2011 at 12:35:32 PM permalink
You can fit it into a 32-bit integer. There are combin(52,7) = 133,784,560 possible hands, which only requires 27 bits.

To start, I recommend using pre-populated arrays for the combin(n,k) function with a value of 0 for evaluations that would normally result in an error condition, such as combin(2, 3). Here would be the code for a 52-card deck:
int[] Choose2 = { 0, 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105, 120, 136, 153, 171, 190, 210, 231, 253, 276, 300, 
325, 351, 378, 406, 435, 465, 496, 528, 561, 595, 630, 666, 703, 741, 780, 820, 861, 903, 946, 990, 1035, 1081, 1128, 1176, 1225,
1275, 1326 };

int[] Choose3 = { 0, 0, 0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286, 364, 455, 560, 680, 816, 969, 1140, 1330, 1540, 1771,
2024, 2300, 2600, 2925, 3276, 3654, 4060, 4495, 4960, 5456, 5984, 6545, 7140, 7770, 8436, 9139, 9880, 10660, 11480, 12341, 13244,
14190, 15180, 16215, 17296, 18424, 19600, 20825, 22100 };

int[] Choose4 = { 0, 0, 0, 0, 1, 5, 15, 35, 70, 126, 210, 330, 495, 715, 1001, 1365, 1820, 2380, 3060, 3876, 4845, 5985, 7315,
8855, 10626, 12650, 14950, 17550, 20475, 23751, 27405, 31465, 35960, 40920, 46376, 52360, 58905, 66045, 73815, 82251, 91390,
101270, 111930, 123410, 135751, 148995, 163185, 178365, 194580, 211876, 230300, 249900, 270725 };

int[] Choose5 = { 0, 0, 0, 0, 0, 1, 6, 21, 56, 126, 252, 462, 792, 1287, 2002, 3003, 4368, 6188, 8568, 11628, 15504, 20349, 26334,
33649, 42504, 53130, 65780, 80730, 98280, 118755, 142506, 169911, 201376, 237336, 278256, 324632, 376992, 435897, 501942, 575757,
658008, 749398, 850668, 962598, 1086008, 1221759, 1370754, 1533939, 1712304, 1906884, 2118760, 2349060, 2598960 };

int[] Choose6 = { 0, 0, 0, 0, 0, 0, 1, 7, 28, 84, 210, 462, 924, 1716, 3003, 5005, 8008, 12376, 18564, 27132, 38760, 54264, 74613,
100947, 134596, 177100, 230230, 296010, 376740, 475020, 593775, 736281, 906192, 1107568, 1344904, 1623160, 1947792, 2324784,
2760681, 3262623, 3838380, 4496388, 5245786, 6096454, 7059052, 8145060, 9366819, 10737573, 12271512, 13983816, 15890700, 18009460,
20358520 };

int[] Choose7 = { 0, 0, 0, 0, 0, 0, 0, 1, 8, 36, 120, 330, 792, 1716, 3432, 6435, 11440, 19448, 31824, 50388, 77520, 116280,
170544, 245157, 346104, 480700, 657800, 888030, 1184040, 1560780, 2035800, 2629575, 3365856, 4272048, 5379616, 6724520, 8347680,
10295472, 12620256, 15380937, 18643560, 22481940, 26978328, 32224114, 38320568, 45379620, 53524680, 62891499, 73629072, 85900584,
99884400, 115775100, 133784560 };

Then if you number each card from 0 to 51, and each hand from 0 to 133784559, you can convert 7 card indexes to a hand index as follows:

Choose7[card7] + Choose6[card6] + Choose5[card5] + Choose4[card4] + Choose3[card3] + Choose2[card2] + card1

...where card7 is the highest-numbered card index and card1 is the lowest-numbered card index (it is critical that the card indexes are sorted from highest to lowest).

Then, to convert a hand index (0 ... 133784559) to card indexes, use the following logic:

int card1 = hand_index, card2, card3, card4, card5, card6, card7;

card7 = 51; while (Choose7[card7] > card1) { card7--; } card1 -= Choose7[card7];
card6 = card7 - 1; while (Choose6[card6] > card1) { card6--; } card1 -= Choose6[card6];
card5 = card6 - 1; while (Choose5[card5] > card1) { card5--; } card1 -= Choose5[card5];
card4 = card5 - 1; while (Choose4[card4] > card1) { card4--; } card1 -= Choose4[card4];
card3 = card4 - 1; while (Choose3[card3] > card1) { card3--; } card1 -= Choose3[card3];
card2 = card3 - 1; while (Choose2[card2] > card1) { card2--; } card1 -= Choose2[card2];

...where hand_index is the hand index from 0 to 133784559. The result will be 7 card indexes in sorted order (card1 being the lowest-numbered card index, and card7 the highest-numbered one), just as was required for the function to compute the hand index.

Hope that helps!
RaspberryCheeseBlintz
RaspberryCheeseBlintz
  • Threads: 5
  • Posts: 38
Joined: Oct 22, 2011
November 22nd, 2011 at 12:41:06 PM permalink
Wow, my stack overfloweth...thanks, that sure looks really efficient.
weaselman
weaselman
  • Threads: 20
  • Posts: 2349
Joined: Jul 11, 2010
November 22nd, 2011 at 1:00:51 PM permalink
Why bother? Save 4 bytes per hand? How many hands do you need to have in memory at the same time?
"When two people always agree one of them is unnecessary"
CrystalMath
CrystalMath
  • Threads: 8
  • Posts: 1911
Joined: May 10, 2011
November 22nd, 2011 at 4:00:40 PM permalink
Quote: JB

Then if you number each card from 0 to 51, and each hand from 0 to 133784559, you can convert 7 card indexes to a hand index as follows:

Choose7[card7] + Choose6[card6] + Choose5[card5] + Choose4[card4] + Choose3[card3] + Choose2[card2] + card1

...where card7 is the highest-numbered card index and card1 is the lowest-numbered card index (it is critical that the card indexes are sorted from highest to lowest).

Then, to convert a hand index (0 ... 133784559) to card indexes, use the following logic:

int card1 = hand_index, card2, card3, card4, card5, card6, card7;

card7 = 51; while (Choose7[card7] > card1) { card7--; } card1 -= Choose7[card7];
card6 = card7 - 1; while (Choose6[card6] > card1) { card6--; } card1 -= Choose6[card6];
card5 = card6 - 1; while (Choose5[card5] > card1) { card5--; } card1 -= Choose5[card5];
card4 = card5 - 1; while (Choose4[card4] > card1) { card4--; } card1 -= Choose4[card4];
card3 = card4 - 1; while (Choose3[card3] > card1) { card3--; } card1 -= Choose3[card3];
card2 = card3 - 1; while (Choose2[card2] > card1) { card2--; } card1 -= Choose2[card2];

...where hand_index is the hand index from 0 to 133784559. The result will be 7 card indexes in sorted order (card1 being the lowest-numbered card index, and card7 the highest-numbered one), just as was required for the function to compute the hand index.

Hope that helps!



These concepts are gold; they are invaluable to making a poker analyzer.

The Wizard has some of the same info at the bottom of this page, but his requires numbers sorted low to high, and is not quite as straight forward:
Video Poker Programming Tips
I heart Crystal Math.
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
November 24th, 2011 at 4:20:23 AM permalink
Quote: weaselman

Why bother? Save 4 bytes per hand? How many hands do you need to have in memory at the same time?


It depends on the application. For example, if you're writing something in Java then this would be the way to go since Java's memory constraints are restrictive. If you're creating a binary data file then you definitely want to go this route to minimize the disk space used for it.

Another reason is to standardize the sequence of the cards (that is, to store combinations and not permutations). It would obviously be quicker to use a 64-bit number and just bit-shift the card indexes if memory is not an issue but speed is, but even if you do that you'll still have to sort the card indexes.
weaselman
weaselman
  • Threads: 20
  • Posts: 2349
Joined: Jul 11, 2010
November 24th, 2011 at 5:38:21 AM permalink
Quote: JB

It depends on the application. For example, if you're writing something in Java then this would be the way to go since Java's memory constraints are restrictive.


Not sure what you mean by this. Java long is 8 bytes just like in (64 bit) C.

Quote:

If you're creating a binary data file then you definitely want to go this route to minimize the disk space used for it.


Nah... Gzip will pack it better than you ever would anyway.

Quote:

Another reason is to standardize the sequence of the cards (that is, to store combinations and not permutations). It would obviously be quicker to use a 64-bit number and just bit-shift the card indexes if memory is not an issue but speed is, but even if you do that you'll still have to sort the card indexes.


I don't understand what this means. Sort the indexes? Why?
"When two people always agree one of them is unnecessary"
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
November 24th, 2011 at 6:02:12 AM permalink
Quote: weaselman

Not sure what you mean by this. Java long is 8 bytes just like in (64 bit) C.


Yes but the default amount of memory you can use for arrays is pretty limited, when designing an applet for the web anyway.

Quote: weaselman

Nah... Gzip will pack it better than you ever would anyway.


If adding another layer of complexity and slowing things down is worth it, sure.

Quote: weaselman

I don't understand what this means. Sort the indexes? Why?


For a 7-card hand, there are 7! = 5040 ways to arrange the card indexes. You don't want to store each unique hand 5040 times in an array with 674274182400 subscripts (consuming about 4.9 terabytes); it would be better to sort the card indexes and store each hand once in an array with 133784560 subscripts. Even so, that's about 1GB of memory if you use 64-bit integers, and of course only half of that if you use 32-bit integers.
weaselman
weaselman
  • Threads: 20
  • Posts: 2349
Joined: Jul 11, 2010
November 24th, 2011 at 6:36:35 AM permalink
Quote: JB

Yes but the default amount of memory you can use for arrays is pretty limited, when designing an applet for the web anyway.


How much is it? I have not done applets for quite a while, don't remember anymore... Who uses defaults nowadays anyway?

Quote:

If adding another layer of complexity and slowing things down is worth it, sure.


Piping data through gzip is hardly "complexity". Especially, was compared.to your mapping algorithm :-) As for speed, reading and writing gzipped files is generally faster, than unpacked ones. Even if there is no significant reduction in size, it does not take any longer because io is done in parallel with gzip CPU activity.

Quote:

For a 7-card hand, there are 7! = 5040 ways to arrange the card indexes. You don't want to store each unique hand 5040 times


Ah, yeah, that makes sense. Though, I am still not sure what kind of application requires storing this many hands.
If you are doing a simulator, and just want to log every hand, you'd have to store as many hands as you play anyway, regardless of how they are represented.
"When two people always agree one of them is unnecessary"
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
November 24th, 2011 at 6:57:08 AM permalink
Quote: weaselman

How much is it? I have not done applets for quite a while, don't remember anymore... Who uses defaults nowadays anyway?


I don't know what the specific limit is, but I ran into problems trying to create an applet that generates video poker strategies. I would assume that those who don't specifically tinker with Java's memory settings are the ones who use defaults.

Quote: weaselman

Piping data through gzip is hardly "complexity". Especially, was compared.to your mapping algorithm :-) As for speed, reading and writing gzipped files is generally faster, than unpacked ones. Even if there is no significant reduction in size, it does not take any longer because io is done in parallel with gzip CPU activity.


We may be arguing two different things here. I see my method to map hands as the most efficient and simple method possible. Using compression only comes into play if you're saving or loading the array to/from a file (or memory stream).

Quote: weaselman

Ah, yeah, that makes sense. Though, I am still not sure what kind of application requires storing this many hands.
If you are doing a simulator, and just want to log every hand, you'd have to store as many hands as you play anyway, regardless of how they are represented.


For a calculator it would be useful. For example, if you know two hole cards, loop through the other 5 cards, calculate the combination, and look up the hand type in the array; this is much faster than calling a separate function to determine the hand rank due to the overhead of calling a function 2,118,760 times.
s2dbaker
s2dbaker
  • Threads: 51
  • Posts: 3259
Joined: Jun 10, 2010
November 24th, 2011 at 7:13:15 AM permalink
I do everything in MS-SQL. It's so easy to program and store results. I'm perfectly happy with resolving only 5000 rounds of poker per second. Since there are only 7462 possible 5 card poker outcomes, it's easy to store the results in a table.
Someday, joor goin' to see the name of Googie Gomez in lights and joor goin' to say to joorself, "Was that her?" and then joor goin' to answer to joorself, "That was her!" But you know somethin' mister? I was always her yuss nobody knows it! - Googie Gomez
  • Jump to: