Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Optimising combinatorial iterations by filtration

by Moron (Curate)
on Mar 08, 2007 at 16:46 UTC ( [id://603857]=perlquestion: print w/replies, xml ) Need Help??

Moron has asked for the wisdom of the Perl Monks concerning the following question:

This might be more algorithmic than pure Perl as a question, on the other hand the availability of methods in CPAN modules does form a boundary for the current state of the problem ...

On the TV Holdem Poker shows, they often have a calculator (presumably a program) that shows onscreen which hand has what winning percentage at a given moment.

Last year I had a go (but got stuck and put it on the backburner) at trying to create my own, to test different people's opinions on whether a particular hand is favourite to win for a given set of community cards (betting history etc. being, albeit unrealistically, ignored for the purpose of this calculator).

Math::Combinatorics and its Algorithmic brother can generate for example all the permutations of nine cards to use for testing the in the heads-up situation, 11 for three players and so on, BUT...

Even in just the heads-up case, the number of raw (unfiltered) combinations to test that would be generated by said module is going to be 52C2 * 50C5 (er something over five trillion (giga- oops tera-!)). So I got to thinking things like, "Well, two red aces is the same as two black ones and moreover all of the, erm, 1028 slightly different 23569 flops (where none of those cards are in anybody's hand) are for example going to be the same ..."

To cut that story short, it is clear that many combinations can be eliminated by filtration and further that if the iterations through the combinations could be ordered so as to be able to group them by hand value yet more reduction in permutations can be achieved or at the very least, the capability to jump along the so-ordered list of combinations by some means to reduce the actual iterations to a manageable number.

The problem is that there doesn't seem to be a way to control the module in that way ... or is there? ... or is there some other clever way to make this programmable? Obviously ... it's been done on TV so there must be... ;)

Update: and even if the module can be tweaked to skip some iterations, it isn't trivial to calculate where to jump to, for example, in the 23569 case, three of the cards could match the suit of a suited two card holding making the hand value different from the cases where no flush is held and even an ordering method that overcomes that might miss holdings of 4X and 78 where some of these are runs and the rest are straight flushes. So ordering the combinations usefully remains to my mind an obstacle to finding a feasible solution along above lines.

-M

Free your mind

  • Comment on Optimising combinatorial iterations by filtration

Replies are listed 'Best First'.
Re: Optimising combinatorial iterations by filtration (mu)
by tye (Sage) on Mar 08, 2007 at 18:45 UTC

    This is likely the wrong way to go about this. I don't need to iterate over all of the poker hands to know that there are 52!/47!/5! of them, that 52-4 have 4 aces, 4*48*47/2 have 3 aces, 13*4*12*6 are full houses, 13*4*48*47/2 have 3-of-kind in them so 13*4*48*47/2-13*4*12*6 are 3-of-kind hands, etc.

    Those are the types of calculations that you need to make, rather than just counting (if you want to do this fast enough to be useful in real time).

    I suppose you could try doing weighted combinations where instead of combinations of cards you do combinations of classes of cards. For example, if the only types of cards that will change the standings are an ace or a spade, then you'd do combinations of the following classes: non-spade aces, ace of spades, non-ace spades, non-ace non-spades. Those combinations then lead to calculations like I was doing above. I not sure that would be any simpler.

    You could look at my Permuting with duplicates and no memory (now part of Algorithm::Loops) and compare it to a standard lexicographic permutations combinations algorithm to see how my changes deal with duplicates and try to make similar changes to one of the combinations algorithms. Likely, you could search and find an algorithm for doing combinations with duplicates somewhere.

    - tye        

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Optimising combinatorial iterations by filtration
by YuckFoo (Abbot) on Mar 08, 2007 at 22:54 UTC
    Maybe this will help you generate a lookup table.

    The number of truly different five card poker hands is not that large. Brute force is good enough to list all 7462 of them.

    First, forget about suits, and generate all combinations of ranks. Sort them and join them in a string. Count the number of unique ranks in the hand. If it is one, the combination is no good (five aces). If it is five, a flush is possible.

    Rank all hands from 0..7461 and you have a quick lookup.

    Update:
    Deal a few hundred random outcomes and tally the results.

    YuckFold

    #!/usr/bin/perl use strict; my @chars = 'a'..'m'; my %hands; for my $c0 (@chars) { for my $c1 (@chars) { for my $c2 (@chars) { for my $c3 (@chars) { for my $c4 (@chars) { my $list = [$c0, $c1, $c2, $c3, $c4]; my $uniq = unique_ranks($list); my $key = join('', sort @$list ); # is a valid hand if ($uniq > 1) { $hands{$key}++; } # can be flushed if ($uniq > 4) { $hands{"$key+"}++; } } } } } } for my $key (sort(keys(%hands))) { $key =~ tr/a-m/AKQJT98765432/; print "$key\n"; } #----------------------------------------------------------- sub unique_ranks { my $list = shift; my %uniq = map { ($_ => 1) } @$list; return keys %uniq; }
      Your ideas are truly excellent. I will need to work on it to be able to apply this at different stages in the hand lifecycle (pre-flop, flop, turn, river), but, very well done anyway - you have found a good optimisation strategy indeed!

      Update: Just spotted one hole that I thought had been covered in this but seems to be there after all. For example, there are 48 ways to get four aces but only 20 7-high flushes. Therefore a holding of say full house has to take into account the number different ways to land on each rank above or below it or at least take into account the cumulative sum of all possible ways up to current rank and divide that by the (constant and known) number of all possible combinations.

      But I could for example calculate the number of possible hands at each rank by a cut-down combination operation and feed that in instead of doing your ++ iterative approach - this changes things a bit so I need to do further work on this algorithm even so.

      More update - actually that wasn't quite the right example. I should have been talking about exact rank, i.e. for identical hands. Here is a better one: There are only four combinations (and 480 permutations) of 7 5 4 3 2 suited, but there are 1020 combinations (and 122400 permutations) of the same hand unsuited. These might be unique by the reduced iteration but do not therefore have equal likelihood.

      -M

      Free your mind

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://603857]
Approved by wfsp
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (2)
As of 2024-04-19 20:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found