## Project Euler Problem #54

### November 18, 2016

Read the details of the problem here

Summary

Poker hands.

Solution

This was a straightforward programming problem rather than anything taxing from a mathematical perspective. I used Groovy listops to process the input file into a sorted list of [ count, face_value ] pairs that could then just be inspected in order of priority (along with some flags to indicate whether there was a monotonic sequence and a only a single suit in the hand) to rank the hand.

There are only 5 combinations of counts available (as given below). It would have been possible to simply check against these to provide a basic classification of the hand but with the need to have the flush and straight processing it just seemed easier and clearer to have the ranking done explicitly.

Count Permutations: [ 1, 1, 1, 1, 1 ], [ 2, 1, 1, 1 ], [2, 2, 1 ], [ 3, 2 ], [4, 1]

Ties were broken by using a base-13 (tridecimal) system with the rank being the most-significant digit and then using the first two group face values as the differentiators so a simple score was created for each hand. As it happened there were no clashes that weren’t broken by this method – it would have to be extended to subsequent cards and then suits (which were ignored in this question) otherwise, so you’d end up with a base-52 (duopentagecimal) system where each card had a unique value but were grouped unless there were clashes.

It didn’t take a lot of coding to get this done. It could be done more tersely, perhaps, but it would be more cryptic!

```class Hand {

private final _cards
private final _isStraight
private final _isFlush

Hand(cardList) {
def vals = cardList.collect { ['face': '23456789TJQKA'.indexOf(it[0]), 'suit': it[1]] }

_isFlush = (vals.groupBy { it.suit }.size() == 1 )
_cards   = vals.groupBy { it.face }
.collect { [ (it.value.size), it.key ] }
.sort { -(it[0] * 13 + it[1]) }
_isStraight = (_cards.size() == 5) && (_cards[0][1] - _cards[-1][1] == 4)
}

def score() {
rank() * 169 + _cards[0][1] * 13 + _cards[1][1]
}

def rank() {
if (_isStraight && _isFlush && _cards[0][1] == 12) return 9
if (_isStraight && _isFlush)                       return 8
if (_cards[0][0] == 4 )                            return 7
if (_cards[0][0] == 3 && _cards[1][0] == 2 )       return 6
if (_isFlush)                                      return 5
if (_isStraight)                                   return 4
if (_cards[0][0] == 3 )                            return 3
if (_cards[0][0] == 2 && _cards[1][0] == 2 )       return 2
if (_cards[0][0] == 2)                             return 1
0
}

def beats(opponent) {
def (s1, s2) = [ this.score(), opponent.score() ]
if (s1 > s2) return true
assert (s1 != s2)
}
}

def cards = it.split(" ")
new Hand(cards[0..4]).beats(new Hand(cards[5..-1]))
}
```

This executes in Groovy 2.4.7 under Java 8u112 in around 0.25 seconds, so well within my 5 second cut-off.

Conclusion

Groovy was perfectly good for this problem with the simple file handling and listops allowing the input to be prepared for processing very easily.