This code compares two 5 card draw poker hands together to determine a win/loss or a tie with the caveats of:
- A single 52-card deck, so that means no one can have the same three or four-of-a-kind
- Aces are not allowed as a low card
- Ties are allowed after some reasonable attempts at tie-breaking (suits are not used)
- No wildcards/jokers
This is a Java 1.8, Maven 3.2 project, so clone, install your maven dependencies, and mvn test
.
git clone [email protected]:schenkman/pokerhand.git
cd pokerhand
mvn install
mvn -q clean test
mvn exec:java -q -Dexec.mainClass="com.cbschenk.poker.fivecarddraw.FiveCardDraw"
Hand.java contains all of the interesting code.
When 5 cards are reached in addCard
, computeRank
is automatically called, which first calls computeHand
and all tie-breaker values are generated as well. Once a hand is given out, it's value is static and can be
trivially compared to any other hand as an integer.
Card.java represents a card which has a value and a suit.
FiveCardDraw.java contains our main
and
play
methods and runs some examples with nice output to explain the hand encodings.
FiveCardDrawTest.java contains all of the
"acceptance" tests which plays each hand type against one another, resulting in roughly 45 games
(n(n+1)/2
where n
is 9 types of hands), and I also include some edge cases for my own sake
(i.e. end-of-loop counting, tie-breaker cases, etc.).
HandTest.java verifies the bit encodings for hands as well as the hand types.
CardTest.java verifies the comparator created for sorting in the TreeMap.
- Add cards to a Hand
- Cards are added to a sorted set to iterate over them in order later
- Hand type and rank are computed when 5 cards reached
- Iterate over cards in order and compute hand type
- Generate Hand rank encoded as an integer
- Play hands against each other comparing rank values as integers
The algorithm generates a bit encoding representing the hand as well as any pertinent information to perform tie-breakers when facing an equivalent hand from your opponent. Encodings are generated in the Hand as soon as 5 cards are available. The breakdown of bits required for each hand type is as follows:
- Hands - 9 types encoded in 4 bits (8 to 0, listed below)
- Cards - 13 values encoded in 4 bits (14 or Ace to 2)
Hands are encoded to the most-significant bits and tie-breakers are handled in the least-significant bits. Tie-breakers only matter when battling a hand of the same type.
Cases are as follows:
- c1 is smallest card and c5 is largest
- 'hp'/'lp' is high pair/low pair
- 'rc' is remaining card
- 'v' is value (4 bits)
E.g. 'c5v' is 'card 5 value'
'lpv' is 'low-pair value'
'rc1v' is 'remaining card 1 value' (least-significant)
Hand Bits Type Tie Breaker values
8) Straight Flush 10 1000 c5v
nnnn nnnn
7) Four of a Kind 8 0111 c4v
nnnn nnnn
6) Full House 8 0110 c3v
nnnn nnnn
5) Flush 24 0101 c5v c4v c3v c2v c1v
nnnn nnnn nnnn nnnn nnnn nnnn
4) Straight 24 0100 c5v c4v c3v c2v c1v
nnnn nnnn nnnn nnnn nnnn nnnn
3) Three of a Kind 4 0011 c3v
nnnn nnnn
2) Two Pair 16 0010 hpv lpv rcv
nnnn nnnn nnnn nnnn
1) One Pair 20 0001 lpv rc3v rc2v rc1v
nnnn nnnn nnnn nnnn nnnn
0) High Card 24 0000 c5v c4v c3v c2v c1v
nnnn nnnn nnnn nnnn nnnn nnnn
In summary, our max encoding length is 24 bits long, which fits into an integer.
Once computed, a simple integer comparison is all that is required to determine a winner or a loser or a tie (See class FiveCardDraw).
In the examples below, you can see how the card values map to the tie-breaker values in the encoded representation.
Note that 11 == Jack
, 12 == Queen
, 13 == King
, and 14 == Ace
.
Result Cards Hand Integer Hand Tie Breaker
8 6 0 0 0 0
WIN 2D 3D 4D 5D 6D - Straight Flush 8781824 1000 0110 0000 0000 0000 0000
2C 10S 10H 10D 10C - Four of a Kind 7995392 0111 1010 0000 0000 0000 0000
7 10 0 0 0 0
Result Cards Hand Integer Hand Tie Breaker
5 13 9 8 5 3
WIN 3H 5H 8H 9H KH - Flush 6133843 0101 1101 1001 1000 0101 0011
3C 4C 8C 9C KC - Flush 6133827 0101 1101 1001 1000 0100 0011
5 13 9 8 4 3
Result Cards Hand Integer Hand Tie Breaker
0 14 9 7 6 3
3C 6S 7H 9D AH - High Card 956259 0000 1110 1001 0111 0110 0011
WIN 7D 8S 8H 9H 10D - One Pair 1616240 0001 1000 1010 1001 0111 0000
1 8 10 9 7 0
Result Cards Hand Integer Hand Tie Breaker
2 9 8 10 0 0
TIE 8S 8C 9S 9C 10S - Two Pair 2722304 0010 1001 1000 1010 0000 0000
TIE 8H 8D 9H 9D 10D - Two Pair 2722304 0010 1001 1000 1010 0000 0000
2 9 8 10 0 0
- N inserts into the Hand (TreeSet) in the average case are
O(klog k)
wherek
is the number of cards in the hand. - Computing the hand type is
O(k)
where the code iterates over each card only once. Constant space is required to save the last card seen and a few other interesting values depending on the hand type (See private Card members on Hand). - Computing the rank after determining the hand type would normally either require an additional
O(k)
orO(1)
time depending on the hand type, however since we have a fixed number of cards per hand (5), the algorithm overall isO(1)
constant time once the cards are sorted.
This software is licensed under the MIT license. See the LICENSE file.
Copyright 2017 Chris Schenk
"Poker, I didn't even know her!" - Someone