Thread Rating:

socks
socks
  • Threads: 15
  • Posts: 364
Joined: Jul 13, 2011
October 12th, 2016 at 12:19:51 PM permalink
I thought I'd add my current clojure version to the code in this thread:

(require '[clojure.math.combinatorics :as c])
(def mod-deck (vec (for [e (range 52)] [(mod e 13) (mod e 4)])))
(def mod->int (zipmap mod-deck (range 52)))
(def suit-combos (vec (c/permutations [0 1 2 3])))
(def syms (atom {}))

(defn mk-syms [num]
(doall
(pmap
(fn [e] (let [h (sort (map mod-deck e))
entries (first (filter #(@syms %)
(for [f suit-combos]
(sort (mapv #(vector (% 0) (f (% 1)))
h)) ) ) ) ]
(if (nil? entries)
(swap! syms assoc h 1)
(swap! syms update-in [entries] inc) )))
(c/combinations (range 52) num)
))
1
)

(spit "PATHNAME/syms.txt") ;sticks the result in a text file, about 5MB for 5 cards
;(def syms (read-string (slurp "PATHNAME/FILENAME.txt))) ;to read back in

to run for 5 cards: (mk-syms 5)

On my computer ('12 'mini quad), it ran in 82s for 5 cards, so it's not winning any speed awards, but to get different size starting hands, just call with that number. I'm not doing anything here with bit manipulations, but if you want to pack into bits, do something like:

(defn mk-key [hand]
(apply bit-or
(for [e hand] (bit-shift-left 1 e))) )

(def syms-bits (atom {}))
(doseq [[k v] @syms] (swap! syms-bits assoc (mk-key (map mod->int k)) v))


For 7 cards, you may have to slide this into the main function due to memory concerns. The version I originally used was slightly different.

edit: I get the correct # for 5 cards, but I'm not certain I'm taking the appropriate care for doing this in parallel, so I'd double check any output.
Wizard
Administrator
Wizard
  • Threads: 1491
  • Posts: 26432
Joined: Oct 14, 2009
October 18th, 2016 at 9:19:56 PM permalink
I've been thinking about this off and on. I offer the following solution for those like me who are strong in math and weak in programming.

Before I go further, let me remind you the formula for choosing k out of n items, with replacement, is combin(n+k-1,k). Think of the deck having k-1 "repeat" cards.

First, let's ask the question how many classes of 5-card hands are there?

  1. There are combin(13,5)=1,287 ways all five cards can be in the same suit.
  2. There are combin(13,4)*13=9,295 ways four cards can be in the same suit and one singleton in another suit.
  3. There are combin(13,3)*combin(13,2)=22,308 ways 3 cards can be in the same suit and 2 in another suit.
  4. There are combin(13,3)*combin(13+2-1,2)=26,026 ways 3 cards can be in the same suit and 1 each in two other suits.
  5. There are (COMBIN(13,2)*(COMBIN(13,2)+1)/2)*13=40,053 ways 2 cards can be in two separate suits and 1 in a third suit.
  6. There are COMBIN(13,2)*COMBIN(13+3-1,3)=35,490 ways 2 cards can be in one suit and 3 singletons in the other 3 suits.


Add that up and you get 133,459.

If you're going to cycle through the whole deck you have to weight all 133,459 by the appropriate number of suits in each class. Here is a table to help you with that.

Suit distribution Comments Ranks Suits Product
5,0 All 1287 4 5148
4,1 All 9295 12 111540
3,2 All 22308 12 267696
3,1,1 Matching singletons 3718 12 44616
3,1,1 Non-matching singletons 22308 24 535392
2,2,1 Both matching ranks 1014 12 12168
2,2,1 One matching rank 11154 24 267696
2,2,1 No matching ranks 27885 24 669240
2,1,1,1 Matching ranks 1014 4 4056
2,1,1,1 One matching rank 12168 12 146016
2,1,1,1 No matching ranks 22308 24 535392
Total 134459 2598960


I admit this is not elegant like the solutions posted earlier. It will require more code and just one math error will screw everything up. However, it isn't a memory hog. It should use quite little.

I can confirm the 7-card case has 6,009,159 classes of hands. Upon request, I can supply a similar math table for that.

I'm still working on the bit mapping solution, just for my own programming edification.
"For with much wisdom comes much sorrow." -- Ecclesiastes 1:18 (NIV)
AceTwo
AceTwo
  • Threads: 5
  • Posts: 359
Joined: Mar 13, 2012
October 31st, 2016 at 1:21:07 PM permalink
A completely different approach to evaluate poker hands which I found out many years ago and did the algorithm in Excel VBA is as follows:
Assign each rank a Prime Number from 2 to 41.
A Hand evaluates to a unique number which is the product of all of its card ranks.
A second evaluation is done to each cards suit, ie if all suits are equal then it is flush.

The number of possible hands using this unique number are only 6.175
A look Up table is created using this unique number from lowest to highest (so that binary search can be quickly done)
The table has this Unique Number and the ranking of the hand (and a second ranking for flushes) as follows:
NON FLUSH
Unique Ranking Quantity of Rankings
Number
4 Kind 156 11-23 13
FH 156 24-36 13
Straight 10 1314-1323 10
3 Kind 858 1324-1336 13
2 Pairs 858 1337-2194 858
Pair 2860 2195-5054 2860
Nothing 1277 5055-6331 1277
TOTAL 6175 5044

FLUSH
Royal Fl 1 1
Straight Fl 2-10 9
Flush 37-1313 1277
Total 1287

So for example for 4 KIND
You get 156 unique numbers but you rank them only from 11-23, 13 different rankings for the 13 ranks

And the 6.175 unique numbers map to 5044 rankings AND 1287 of them have a second ranking for flushes = 6331 total rankings
Last edited by: AceTwo on Oct 31, 2016
tringlomane
tringlomane
  • Threads: 8
  • Posts: 6281
Joined: Aug 25, 2012
October 31st, 2016 at 1:27:53 PM permalink
Quote: AceTwo

A completely different approach to evaluate poker hands which I found out many years ago and did the algorithm in Excel VBA is as follows:
Assign each rank a Prime Number from 2 to 41.
A Hand evaluates to a unique number which is the product of all of its card ranks.
A second evaluation is done to each cards suit, ie if all suits are equal then it is flush.

The number of possible hands using this unique number are only 6.175
A look Up table is created using this unique number from lowest to highest (so that binary search can be quickly done)
The table has this Unique Number and the ranking of the hand (and a second ranking for flushes) as follows:
NON FLUSH
4 Kind 156 11-23 13
FH 156 24-36 13
Straight 10 1314-1323



The method used by "Cactus Kev"?

http://suffe.cool/poker/evaluator.html
AceTwo
AceTwo
  • Threads: 5
  • Posts: 359
Joined: Mar 13, 2012
October 31st, 2016 at 1:48:32 PM permalink
Quote: tringlomane

The method used by "Cactus Kev"?

http://suffe.cool/poker/evaluator.html



Yes. I forgot where I found it. But looking at the link, that's where I found it.
It is quite fast.
AceTwo
AceTwo
  • Threads: 5
  • Posts: 359
Joined: Mar 13, 2012
October 31st, 2016 at 1:55:05 PM permalink
Quote: tringlomane

The method used by "Cactus Kev"?

http://suffe.cool/poker/evaluator.html



Also now that I look at the Cactus Kev Evaluation, I modified it a bit as I was only interested in evaluating normal poker hands between 2 players.
For example 4 Kind has 156 Distinct Hands BUT it is impossible for 2 people to have 4 Kind of the same rank. So mine evaluates only to 13 rankings.
socks
socks
  • Threads: 15
  • Posts: 364
Joined: Jul 13, 2011
October 31st, 2016 at 11:17:45 PM permalink
As I remember it, when doing 3 card poker, I gave all 52 cards a prime. Since the hands were only 3 cards, I could afford to stick all values in a sparse array for lookup. I'm sure this is too gimmicky to be worth much (it can't be expanded to many other games), but I felt ever so slightly clever doing it.
Wizard
Administrator
Wizard
  • Threads: 1491
  • Posts: 26432
Joined: Oct 14, 2009
March 4th, 2017 at 6:05:34 PM permalink
In preparation for my analysis of Magic Deal, I've been looking at this topic again, to determine the number of distinct sets of 2, 3, and 4 cards. Here is what I get:

2 cards: 247
3 cards: 1,755
4 cards: 19,435

Anyone agree or disagree?
Last edited by: Wizard on Mar 4, 2017
"For with much wisdom comes much sorrow." -- Ecclesiastes 1:18 (NIV)
JB
Administrator
JB
  • Threads: 334
  • Posts: 2089
Joined: Oct 14, 2009
March 4th, 2017 at 6:16:42 PM permalink
Here are the totals:

2 cards: 169 unique patterns
3 cards: 1,755 unique patterns
4 cards: 16,432 unique patterns

Here are the patterns:

TWO CARDS:

Type Rank Pattern Rank Weight Suit Pattern Suit Weight Total
1P AA 13 AB 6 78
0P A/B 78 A/A 4 312
0P A/B 78 A/B 12 936
Totals 169 1326


THREE CARDS:

Type Rank Pattern Rank Weight Suit Pattern Suit Weight Total
3K AAA 13 ABC 4 52
1P AA/B 156 AB/A 12 1872
1P AA/B 156 AB/C 12 1872
0P A/B/C 286 A/A/A 4 1144
0P A/B/C 286 A/A/B 12 3432
0P A/B/C 286 A/B/A 12 3432
0P A/B/C 286 A/B/B 12 3432
0P A/B/C 286 A/B/C 24 6864
Totals 1755 22100


FOUR CARDS:

Type Rank Pattern Rank Weight Suit Pattern Suit Weight Total
4K AAAA 13 ABCD 1 13
3K AAA/B 156 ABC/A 12 1872
3K AAA/B 156 ABC/D 4 624
2P AA/BB 78 AB/AB 6 468
2P AA/BB 78 AB/AC 24 1872
2P AA/BB 78 AB/CD 6 468
1P AA/B/C 858 AB/A/A 12 10296
1P AA/B/C 858 AB/A/B 12 10296
1P AA/B/C 858 AB/A/C 24 20592
1P AA/B/C 858 AB/C/A 24 20592
1P AA/B/C 858 AB/C/C 12 10296
1P AA/B/C 858 AB/C/D 12 10296
0P A/B/C/D 715 A/A/A/A 4 2860
0P A/B/C/D 715 A/A/A/B 12 8580
0P A/B/C/D 715 A/A/B/A 12 8580
0P A/B/C/D 715 A/A/B/B 12 8580
0P A/B/C/D 715 A/A/B/C 24 17160
0P A/B/C/D 715 A/B/A/A 12 8580
0P A/B/C/D 715 A/B/A/B 12 8580
0P A/B/C/D 715 A/B/A/C 24 17160
0P A/B/C/D 715 A/B/B/A 12 8580
0P A/B/C/D 715 A/B/B/B 12 8580
0P A/B/C/D 715 A/B/B/C 24 17160
0P A/B/C/D 715 A/B/C/A 24 17160
0P A/B/C/D 715 A/B/C/B 24 17160
0P A/B/C/D 715 A/B/C/C 24 17160
0P A/B/C/D 715 A/B/C/D 24 17160
Totals 16432 270725
Last edited by: JB on Mar 4, 2017
Wizard
Administrator
Wizard
  • Threads: 1491
  • Posts: 26432
Joined: Oct 14, 2009
March 4th, 2017 at 7:53:21 PM permalink
Thanks JB. I found my error for the four card case.
"For with much wisdom comes much sorrow." -- Ecclesiastes 1:18 (NIV)
socks
socks
  • Threads: 15
  • Posts: 364
Joined: Jul 13, 2011
March 21st, 2017 at 1:55:39 PM permalink
A few months back I played with using suit symmetries, in my cache, at each stage of the deal, instead of just the starting hands. It looked like the technique had promise, but the cost of bucketing the hands at the last step cut into the gains I was hoping for. Backing off by one level looked promising, but it was too game specific for me to follow through with at the time.

edit: I mention this because it comes to mind when I see 2-4 card counts listed together.
Last edited by: socks on Mar 21, 2017
camapl
camapl
  • Threads: 8
  • Posts: 420
Joined: Jun 22, 2010
July 15th, 2017 at 2:34:07 AM permalink
Hey Wiz,

Sorry if this is a high jack... Any chance you are planning to use the techniques in this thread to fashion a more time-efficient analysis of Three-Way Action? (If memory serves, your original code took 80 days!) The reason I ask is that I sometimes play on a version whose pay tables are different from those on your WoO page. By using the hand counts shown on that page (which I believe are sub-optimal for my game), I estimate the return to be only a bit higher than 99%, but I'd love to know the actual return and "optimal-ish" strategy, as this may still be a couponing opportunity. I'd like to know if it's a "good bet" in spite of itself! ;)

Thank you!

"We now return you to your regularly scheduled" thread!

Quite clever, folks, making your code not only effective but efficient! I commend thee!
Expectation is the root of all heartache.
camapl
camapl
  • Threads: 8
  • Posts: 420
Joined: Jun 22, 2010
July 22nd, 2017 at 12:52:05 PM permalink
Bump. Question for the Wizard above. 😅 Thank you!
Expectation is the root of all heartache.
Wizard
Administrator
Wizard
  • Threads: 1491
  • Posts: 26432
Joined: Oct 14, 2009
July 22nd, 2017 at 1:45:45 PM permalink
Quote: camapl

Hey Wiz,

Sorry if this is a high jack... Any chance you are planning to use the techniques in this thread to fashion a more time-efficient analysis of Three-Way Action? (If memory serves, your original code took 80 days!) The reason I ask is that I sometimes play on a version whose pay tables are different from those on your WoO page. By using the hand counts shown on that page (which I believe are sub-optimal for my game), I estimate the return to be only a bit higher than 99%, but I'd love to know the actual return and "optimal-ish" strategy, as this may still be a couponing opportunity. I'd like to know if it's a "good bet" in spite of itself! ;)



Just for clarity, you're referring to 3 Way Action, with the numeral 3. There is also a defunct table game called Three Way Action.

I'm afraid my analysis on that is over ten years old and I don't recall the details very well. What you see on the page is what there is. I certainly never went down the road of making a playable strategy. Given that this game seems to be going the way of the dodo bird, revisiting it is not a high priority for me.

Sorry, I'm sure that's not what you wanted to hear. And sorry for the tardy reply, I was in Europe at the time you initially asked.
"For with much wisdom comes much sorrow." -- Ecclesiastes 1:18 (NIV)
camapl
camapl
  • Threads: 8
  • Posts: 420
Joined: Jun 22, 2010
July 23rd, 2017 at 8:26:39 AM permalink
Yes, 3, not Three. Understood. No worries - I only bumped b/c I realized I put "Wiz", not "Wizard."

Thanks for the response. Hope the trip went well!
Expectation is the root of all heartache.
Wizard
Administrator
Wizard
  • Threads: 1491
  • Posts: 26432
Joined: Oct 14, 2009
July 23rd, 2017 at 8:33:28 AM permalink
Quote: camapl

Yes, 3, not Three. Understood. No worries - I only bumped b/c I realized I put "Wiz", not "Wizard."

Thanks for the response. Hope the trip went well!



You're welcome.

Just FYI, bumping is against the rules, but I was in a good mood after some time away.

Yes, had a nice trip. Will post reports on at least the casinos soon.
"For with much wisdom comes much sorrow." -- Ecclesiastes 1:18 (NIV)
konglify
konglify
  • Threads: 28
  • Posts: 160
Joined: Aug 28, 2014
September 24th, 2017 at 5:37:14 AM permalink
Quote: Wizard

Quote: MathExtremist


var list = new Dictionary<long, int>();
List<uint> suits = new List<uint>();

for (var c5 = 4; c5 < 52; ++c5) {
for (var c4 = 3; c4 < c5; ++c4) {
for (var c3 = 2; c3 < c4; ++c3) {
for (var c2 = 1; c2 < c3; ++c2) {
for (var c1 = 0; c1 < c2; ++c1) {

// Set a bit for each card in the bitmask
ulong mask = 1 << c5 | 1 << c4 | 1 << c3 | 1 << c2 | 1 << c1;

// reused variable - start with a blank slate
suits.clear();

// strip the suits out, add them individually to the container
suits.Add((uint)((mask >> (13 * 0)) & 0x1fffUL));
suits.Add((uint)((mask >> (13 * 1)) & 0x1fffUL));
suits.Add((uint)((mask >> (13 * 2)) & 0x1fffUL));
suits.Add((uint)((mask >> (13 * 3)) & 0x1fffUL));

// sort them
suits.Sort();

// rebuild the handprint
ulong key = (ulong)suits[0] | (ulong)suits[1] << (13 * 1) | (ulong)suits[2] << (13 * 2) | (ulong)suits[3] << (13 * 3);

// use the key however you want (e.g., the add-or-increment operation you're already doing.)
// ...
} } } } }



Thank you. I've been trying to figure out the logic of this but your level is obviously higher than mine.

Can you please go over more slowly, and in as simple English as possible, what these lines do:


ulong mask = 1 << c5 | 1 << c4 | 1 << c3 | 1 << c2 | 1 << c1;

and

suits.Add((uint)((mask >> (13 * 3)) & 0x1fffUL));

and

suits.Add((uint)((mask >> (13 * 0)) & 0x1fffUL));

If the code is different in C++, could I trouble you to translate it.

Thank you!!!



I know this thread is long time ago but I am just try to follow to find a good way to map the 1-deck hands into unique one. I am tracking the original post and all replies. I tried the method posted at top, it is quite straightforward to me. I end up getting 134459 hands but when I add the duplicate number for each 134459 hands, I get 2588664 hands instead. I figure out there was a bug in the sorting function (where H should be H) but that's is the reason why end up total 2588664 hands instead of 2598960.

Then, I tried the method I just quoted. It is quite surprisingly short and I port to the c++ code as


map<long, int> uniqueMap;
vector<int> suits;

for (int c5 = 4; c5 < 52; ++c5) {
for (int c4 = 3; c4 < c5; ++c4) {
for (int c3 = 2; c3 < c4; ++c3) {
for (int c2 = 1; c2 < c3; ++c2) {
for (int c1 = 0; c1 < c2; ++c1) {
// Set a bit for each card in the bitmask
long mask = 1 << c5 | 1 << c4 | 1 << c3 | 1 << c2 | 1 << c1;

// reused variable - start with a blank slate
suits.clear();

// strip the suits out, add them individually to the container
suits.push_back((int)((mask >> (13 * 0)) & 0x1fffUL));
suits.push_back((int)((mask >> (13 * 1)) & 0x1fffUL));
suits.push_back((int)((mask >> (13 * 2)) & 0x1fffUL));
suits.push_back((int)((mask >> (13 * 3)) & 0x1fffUL));

// sort them
sort(suits.begin(), suits.end());

// rebuild the handprint
long key = (long)suits[0] | (long)suits[1] << (13 * 1) | (long)suits[2] << (13 * 2) | (long)suits[3] << (13 * 3);
if (uniqueMap.find(key)!=uniqueMap.end()) {
uniqueMap[key]++;
} else {
uniqueMap.insert(make_pair(key, 1));
}

}}}}}


It results 102221 hands but all unique hands with duplicates added up to the 2598960. Could any one help to check what's wrong with my code. Thanks.
MoonRaker1
MoonRaker1
  • Threads: 1
  • Posts: 8
Joined: Feb 28, 2018
February 28th, 2018 at 3:36:47 PM permalink
OK, the answer is a little late, but ... here it is.
In C++ one has to take care about data types, casting and so on.
The following code compiles on VC++ and gives the expected result.

Remark: I cannot post the whole code, because the forum software thinks it contains links.
Therefore only the different lines.


map<unsigned long long, int> uniqueMap;
vector<unsigned long long> suits;

// Set a bit for each card in the bitmask
unsigned long long mask = 1ull << c5 | 1ull << c4 | 1ull << c3 | 1ull << c2 | 1ull << c1;

// rebuild the handprint
unsigned long long key = ((unsigned long long)suits[0]) | ((unsigned long long)suits[1] << (13 * 1)) | ((unsigned long long)suits[2] << (13 * 2)) | ((unsigned long long)suits[3] << (13 * 3));

mustangsally
mustangsally
  • Threads: 25
  • Posts: 2463
Joined: Mar 29, 2011
January 18th, 2019 at 4:01:02 PM permalink
Quote: ThatDonGuy

I seem to recall somebody asking a while ago if there was an "easy" way to map the 2,598,960 different possible 5-card hands into the 134,459 "unique" 5-card hands (the ones that took suits into account, but didn't depend on "specific" suits -

this is a beginning for me.
Combin (52,5) = 2,598,960 possible unique poker hands
7,462 = possible distinct poker hands

data, list and thought process from here:
http://suffe.cool/poker/evaluator.html
Hand ValueUniqueDistinct
Straight Flush4010
Four of a Kind624156
Full Houses3744156
Flush51081277
Straight1020010
Three of a Kind54912858
Two Pair123552858
One Pair10982402860
High Card13025401277
TOTAL25989607462


why do so many say there are 134,459 "unique" 5-card hands
(even S.N. Ethier comes up with that value in his book. I also found out he does not teach any more!)

(I can find this almost everywhere, but the above (that there are only 7,462 where suits do not matter except where they do matter) is found only one place?)

I looked at the text file (he linked to) in Excel and it all looks great and adds up to exactly C(52,5)
I do not see what I may have missed.
and if I did not miss anything
Yahoo!
Sally
I Heart Vi Hart
unJon
unJon
  • Threads: 14
  • Posts: 4570
Joined: Jul 1, 2018
January 18th, 2019 at 4:14:24 PM permalink
Quote: mustangsally

this is a beginning for me.
Combin (52,5) = 2,598,960 possible unique poker hands
7,462 = possible distinct poker hands

data, list and thought process from here:
http://suffe.cool/poker/evaluator.html

Hand ValueUniqueDistinct
Straight Flush4010
Four of a Kind624156
Full Houses3744156
Flush51081277
Straight1020010
Three of a Kind54912858
Two Pair123552858
One Pair10982402860
High Card13025401277
TOTAL25989607462


why do so many say there are 134,459 "unique" 5-card hands
(even S.N. Ethier comes up with that value in his book. I also found out he does not teach any more!)

(I can find this almost everywhere, but the above (that there are only 7,462 where suits do not matter except where they do matter) is found only one place?)

I looked at the text file (he linked to) in Excel and it all looks great and adds up to exactly C(52,5)
I do not see what I may have missed.
and if I did not miss anything
Yahoo!
Sally


Hi, Sally.

My off the cuff answer is that the “unique” hands and “distinct” hands is that unique counts the number of different suits in a hand (but doesn’t care what those suits are), but unique hands ignore how many suits are in a hand.

So a ten high straight containing 3 of one suit (T, 9 and 8) and 2 (7 and 6) of another suit is not distinct from a ten high straight containing 4 of one suit (T, 9, 8, and 7) and 1 of a different suit (6), but they are in different categories for uniqueness. (Because they may have different answers about whether to draw cards.)

This is a pure guess and I am not a VP player.
The race is not always to the swift, nor the battle to the strong; but that is the way to bet.
ThatDonGuy
ThatDonGuy
  • Threads: 117
  • Posts: 6218
Joined: Jun 22, 2011
January 18th, 2019 at 4:20:06 PM permalink
Quote: mustangsally

this is a beginning for me.
Combin (52,5) = 2,598,960 possible unique poker hands
7,462 = possible distinct poker hands

data, list and thought process from here:
http://suffe.cool/poker/evaluator.html

Hand ValueUniqueDistinct
Straight Flush4010
Four of a Kind624156
Full Houses3744156
Flush51081277
Straight1020010
Three of a Kind54912858
Two Pair123552858
One Pair10982402860
High Card13025401277
TOTAL25989607462


why do so many say there are 134,459 "unique" 5-card hands
(even S.N. Ethier comes up with that value in his book. I also found out he does not teach any more!)

(I can find this almost everywhere, but the above (that there are only 7,462 where suits do not matter except where they do matter) is found only one place?)

I looked at the text file (he linked to) in Excel and it all looks great and adds up to exactly C(52,5)
I do not see what I may have missed.
and if I did not miss anything
Yahoo!
Sally


Your definition of "distinct" is different from mine.
For Straight Flushes, Fours-Of-A-Kind, and Flushes, they are the same.
However, as an example, take Full Houses into account.
You appear to be treating AAAKK as one distinct hand. (In terms of non-draw poker, that is correct.)
I, however, treat it as two:
1. Both Kings have suits that match Aces: As Ah Ad Ks Kh
2. One King has a suit that matches an Ace, but the other does not: As Ah Ad Ks Kc
The distinction is necessary when drawing because of the possibility of drawing a flush.

For straights, the difference is much greater, because for each sequence, there are 4 possible suits for the second card, 4 for the third, 4 for the fourth, and 4 for the fifth (it doesn't matter what suit the first card is), minus the one that makes it a straight flush, which is 255 distinct hands.
You have to differentiate, say, As Ks Qd Js 10s from the other Ace-high straights as you are holding 4 to a Royal Flush, whereas As Kd Qc Jh 10s is only 2 to a Royal, which will require a different play.
KevinAA
KevinAA
  • Threads: 18
  • Posts: 283
Joined: Jul 6, 2017
January 18th, 2019 at 6:01:39 PM permalink
I wrote a similar program to do VP calculations, and I mapped the 2,598,960 (52 choose 5) hands down to 204,087.

What I did was:

1a) change the definition of suits from names to numbers, easier to use; 1, 2, 3 or 4
1b) change the definition of J,Q,K to 11,12,13 and change A to 1 (again, just easier to write programs this way)

1) make the suit of the first card always 1
2) if the suit of the second card is the same as the first card, of course it's 1; if it's different, then make it suit 2
3) if the suit of the third card is the same as the first card, it's 1; if it's the same as the suit of the 2nd card, make it the suit of the 2nd card (would have to be 2); if it's different from both 1st and 2nd cards, then it's suit 3
4) similar process for the fourth card
5) similar process for the fifth card

Then I tally up how many original hands fall into the same mapped hand (what I call "dups") -- it can be 1,2,3,4,6,8,12 or 24.

For example:
2 suit 1
6 suit 2
11 suit 3
12 suit 4
13 suit 2
this one has 24 dups; hold 3 to a straight JQK

4 suit 1
5 suit 1
5 suit 2
9 suit 1
12 suit 2
6 dups; pair of 5's beats the single Q

When I sum all the dups for the 204,087 mapped hands, I get the result I should: 2,598,960
When I do expected value calculations, I take the expected value for any one particular row of the 204,087 and multiply by dups to "un-map" it.
14c14c
14c14c
  • Threads: 0
  • Posts: 1
Joined: Aug 30, 2023
August 30th, 2023 at 9:19:21 AM permalink
In case there is anyone who like me, jumped into this problem for whatever reasons, here is a short and non-optimized python code which perform the counting using the method suggested by MathExtremist.


The code only uses itertools. In the code, a suit folding function is provided, which maps any hand to a unique representative. A dictionary "mapping" is also created, where keys are each unique/canonical hands representative, and values are the count of the equivalence class.

Each card is represented by an integer ID from 0 to 51. Suits are represented by 0 to 3, card rank are represented by 0-12, and card ID = rank*4+suit. This ID also coincide with the integer ID used by HenryRLee et al. in their PokerHandEvaluator.

Change r from 5 to 7 gets 7 hands mapping. The 7 hands calculation takes about 16.5 mins in my local computer.

from itertools import combinations
mapping = {}
r = 5

def folding(hand):
rank_list = [[],[],[],[]]
for card in hand:
rank_list[card%4].append(card//4)
rank_list. sort(reverse = True, key=lambda x:(len(x),x))
return tuple(k*4 + i for i in range(0,4) for k in rank_list[i])

for hand in combinations(range(52),r):
mapping[folding(hand)] = mapping. get(folding(hand),0) + 1

print(len(mapping))
cnt=0
for i in mapping:
cnt+=mapping[i]
print(cnt)

Mental
Mental
  • Threads: 13
  • Posts: 1236
Joined: Dec 10, 2018
August 30th, 2023 at 10:11:25 AM permalink
I wrote this 25 years ago, so don't ask me how it works. It works for joker and double joker games. EDIT: The suit folding takes 0.52 seconds on my old desktop machine.

void printArrays(handInfo & hand, int weights)
{
int i, j, i0, i1, i2, i3, i4, k;
int deckSize = 54;
// dump unique and weight arrays to stdout for creating source code
int * tmp = new int [3162510 * sizeof(int)];
for (k = 0; k < 3162510; k++) {
tmp[k] = 0;
}
int shift;
unsigned long long int mask, uno = 1, masks[5];
unsigned long long int order, max;
for (i0 = 0; i0 < deckSize - 4; i0++) {
for (i1 = i0 + 1; i1 < deckSize - 3; i1++) {
for (i2 = i1 + 1; i2 < deckSize - 2; i2++) {
for (i3 = i2 + 1; i3 < deckSize - 1; i3++) {
for (i4 = i3 + 1; i4 < deckSize; i4++) {
hand.set(0, i0);
hand.set(1, i1);
hand.set(2, i2);
hand.set(3, i3);
hand.set(4, i4);
hand.indexSort();
mask = (uno << i0) | (uno << i1)
| (uno << i2) | (uno << i3) | (uno << i4);
for (i = 0, shift = 0; shift < 53; i++, shift += 13) {
masks = (mask >> shift) & 0x1fff;
}
// Order the bits for each suit, largest first, into order mask
order = 0;
for (shift = 0; shift < 40; shift += 13) {
max = j = 0;
for (i = 0; i < 4; i++) {
if (masks > max) {
max = masks;
j = i;
}
}
if (max > 0) {
masks
= 0;
order |= max << shift;
}
}
// copy jokers to last bits
if (masks[4] > 0) {
order |= masks[4] << 52;
}
// copy the ordered bits back into the hand (with new suits)
j = 0;
for (i = 0; i < 5; i++) {
for ( ; j < 54; j++) {
if ((order >> j) & 1) {
hand.set(i, j++);
break;
}
}
}
hand.indexSort();
k = hand.key5();
tmp[k]++;
}
}
}
}
}
i = j = 0;
if (weights < 2) {
printf("char unique[] = {\n");
} else {
printf("char weight[] = {\n");
}
for (i0 = 0; i0 < deckSize - 4; i0++) {
for (i1 = i0 + 1; i1 < deckSize - 3; i1++) {
for (i2 = i1 + 1; i2 < deckSize - 2; i2++) {
for (i3 = i2 + 1; i3 < deckSize - 1; i3++) {
for (i4 = i3 + 1; i4 < deckSize; i4++) {
if (i4 == 53 && i3 != 52) continue;
hand.set(0, i0);
hand.set(1, i1);
hand.set(2, i2);
hand.set(3, i3);
hand.set(4, i4);
hand.indexSort();
k = hand.key5();
if (!tmp[k]) continue;
// make sure we use the first joker for one-joker hands
if (i4 == 52) {
tmp[k] *= 2;
}
if (weights > 1) {
hand.showHand();
printf("wgt= %d %d\n", tmp[k], k);
}
if (weights < 2) {
printf("%2d, %2d, %2d, %2d, %2d, // %d\n", i0, i1, i2, i3, i4, i);
} else {
printf("%2d, // %d\n", tmp[k], i);
}
i++;
j += tmp[k];
}
}
}
}
}
if (weights < 2) {
printf("};\n");
} else {
printf("};\n\nconst int u_arraySize = %d;\n", i);
}
}
The output is a C declaration of an array listing all of the unique hands.
char unique[] = {
0, 1, 2, 3, 4, // 0
0, 1, 2, 3, 5, // 1
0, 1, 2, 3, 6, // 2
0, 1, 2, 3, 7, // 3
.........
12, 25, 38, 50, 52, // 152643
12, 25, 38, 51, 52, // 152644
12, 25, 38, 52, 53, // 152645
};
Where 0-51 index normal cards and 52 and 53 are the joker indices.

Alternately, the function prints the array of hand weights if weights==2:
char weight[] = {
4, // 0
4, // 1
.......
8, // 152643
2, // 152644
4 // 152645
};

If I am not evaluating a game with jokers, I just ignore an hand with a joker and I get the right number of unique hands and total number of hands if I add up the weights (what Kevin calls dups).
Last edited by: Mental on Aug 30, 2023
This forum is more enjoyable after I learned how to use the 'Block this user' button.
  • Jump to: