The simplest algorithm for poker hand evaluation The simplest algorithm for poker hand evaluation r r

The simplest algorithm for poker hand evaluation


Here is a very short but complete histogram based 5 card poker scoring function in Python (2.x). It will get considerably longer if converted to Java.

def poker(hands):    scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]    winner = sorted(scores , key=lambda x:x[1])[-1][0]    return hands[winner]def score(hand):    ranks = '23456789TJQKA'    rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()    score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])    if len(score) == 5:        if ranks[0:2] == (12, 3): #adjust if 5 high straight            ranks = (3, 2, 1, 0, -1)        straight = ranks[0] - ranks[4] == 4        flush = len({suit for _, suit in hand}) == 1        '''no pair, straight, flush, or straight flush'''        score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]    return score, ranks >>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS']) '8C AD 8D AC 9C'


Lookup tables are the most straightforward and simplest solution to the problem, and also the fastest. The trick is managing the size of the table and keeping the mode of use simple enough to process very quickly (space–time tradeoff). Obviously, in theory you could just encode each hand that could be held and have an array of evaluations, then --poof-- one table lookup and you are done. Unfortunately, such a table would be huge and unmanageable for most machines, and would invariably have you thrashing disks anyway as memory gets swapped out lots.

The so-called two-plus-two solution sports a big 10M table, but literally involves one table lookup for each card in the hand. You are not likely to find a faster and simpler to understand algorithm.

Other solutions involve more compressed tables with more complex indexing, but they are readily comprehensible and pretty fast (although much slower than 2+2). This is where you see language concerning hashing and so forth -- tricks to reduce a table size to more manageable sizes.

In any case, lookup solutions are orders of magnitude faster than the histogram-sort-dance-on-your-head-compare-special-case-and-by-the-way-was-it-a-flush solutions, almost none of which are worthy of a second glance.


You actually don't need any advanced functions, it can be all done bitwise: (source: http://www.codeproject.com/Articles/569271/A-Poker-hand-analyzer-in-JavaScript-using-bit-math)

(This one is actually written in JavaScript, but you can evaluate JavaScript from Java if needed, so it shouldn't be a problem. Also, this is as short as it gets, so if even for illustration of the approach...):

First you split your cards into two arrays: ranks (cs) and suits (ss) and to represent suits, you will use either 1,2,4 or 8 (that is 0b0001, 0b0010,...):

var J=11, Q=12, K=13, A=14, C=1, D=2, H=4, S=8;

Now here's the magic:

function evaluateHand(cs, ss) {    var pokerHands = ["4 of a Kind", "Straight Flush","Straight","Flush","High Card","1 Pair","2 Pair","Royal Flush", "3 of a Kind","Full House"];    var v,i,o,s = 1 << cs[0] | 1 << cs[1] | 1 << cs[2] | 1 << cs[3] | 1 << cs[4];    for (i = -1, v = o = 0; i < 5; i++, o = Math.pow(2, cs[i] * 4)) {v += o * ((v / o & 15) + 1);}    v = v % 15 - ((s / (s & -s) == 31) || (s == 0x403c) ? 3 : 1);    v -= (ss[0] == (ss[1] | ss[2] | ss[3] | ss[4])) * ((s == 0x7c00) ? -5 : 1);    return pokerHands[v];}

Usage:

evaluateHand([A,10,J,K,Q],[C,C,C,C,C]); // Royal Flush

Now what it does (very briefly) is that it puts 1 into 3rd bit of s when there's a 2, into 4th when there's 3, etc., so for the above example s looks like this:

0b111110000000000

for [A,2,3,4,5] it would look like this

0b100 0000 0011 1100

etc.

v uses four bits to record multiple occurencies of same card, so it's 52bits long and if you have three Aces and two kings, its 8 MSB bits look like:

0111 0011 ...

The last line then checks for a flush or straight flush or royal flush (0x7c00).