I am thinking about poker hand (5 cards) evaluation in Java. Now I am looking for simplicity and clarity rather than performance and efficiency. I probably can
Here's a simple rule-based implementation in Kotlin:
class PokerHand constructor(hand: String) : Comparable {
companion object {
const val WIN = 1
const val TIE = 0
const val LOSS = -1
}
val cards: List
val isStraightFlush: Boolean
get() = isStraight && isFlush
val isFourOfAKind: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 4 }
val isFullHouse: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.size == 2
val isFlush: Boolean
get() = cards.groupBy { it.suit }.map { it.value }.size == 1
val isStraight: Boolean
get() = cards.map { it.weight.ordinal } == (cards[0].weight.ordinal..cards[0].weight.ordinal + 4).toList()
val isThreeOfAKind: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 3 }
val isTwoPair: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.filter { it.size == 2 }.count() == 2
val isPair: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 2 }
init {
val cards = ArrayList()
hand.split(" ").forEach {
when (it.length != 2) {
true -> throw RuntimeException("A card code must be two characters")
else -> cards += Card(Weight.forCode(it[0]), Suit.forCode(it[1]))
}
}
if (cards.size != 5) {
throw RuntimeException("There must be five cards in a hand")
}
this.cards = cards.sortedBy { it.weight.ordinal }
}
override fun compareTo(other: PokerHand): Int = when {
(this.isStraightFlush || other.isStraightFlush) ->
if (this.isStraightFlush) if (other.isStraightFlush) compareByHighCard(other) else WIN else LOSS
(this.isFourOfAKind || other.isFourOfAKind) ->
if (this.isFourOfAKind) if (other.isFourOfAKind) compareByHighCard(other) else WIN else LOSS
(this.isFullHouse || other.isFullHouse) ->
if (this.isFullHouse) if (other.isFullHouse) compareByHighCard(other) else WIN else LOSS
(this.isFlush || other.isFlush) ->
if (this.isFlush) if (other.isFlush) compareByHighCard(other) else WIN else LOSS
(this.isStraight || other.isStraight) ->
if (this.isStraight) if (other.isStraight) compareByHighCard(other) else WIN else LOSS
(this.isThreeOfAKind || other.isThreeOfAKind) ->
if (this.isThreeOfAKind) if (other.isThreeOfAKind) compareByHighCard(other) else WIN else LOSS
(this.isTwoPair || other.isTwoPair) ->
if (this.isTwoPair) if (other.isTwoPair) compareByHighCard(other) else WIN else LOSS
(this.isPair || other.isPair) ->
if (this.isPair) if (other.isPair) compareByHighCard(other) else WIN else LOSS
else -> compareByHighCard(other)
}
private fun compareByHighCard(other: PokerHand, index: Int = 4): Int = when {
(index < 0) -> TIE
cards[index].weight === other.cards[index].weight -> compareByHighCard(other, index - 1)
cards[index].weight.ordinal > other.cards[index].weight.ordinal -> WIN
else -> LOSS
}
}
Implementation details:
2H 3H 4H 5H 6HComparable to evaluate against another hand using a simple rules approach, eg a straight flush beats four of a kind, which beats a full house, and so forth. The sources are here.