Project Euler/54
From charlesreid1
Problem Statement
POKER TIME!!!
This problem asks us to compare 1 thousand poker hands and count the number of hands player 1 wins.
- High Card: Highest value card.
- One Pair: Two cards of the same value.
- Two Pairs: Two different pairs.
- Three of a Kind: Three cards of the same value.
- Straight: All cards are consecutive values.
- Flush: All cards of the same suit.
- Full House: Three of a kind and a pair.
- Four of a Kind: Four cards of the same value.
- Straight Flush: All cards are consecutive values of same suit.
- Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
Solution Technique
The technique was to implement each type of hand as a boolean check, and run through checks of each type of hand in the correct order. I also wrote lots of individual sanity checks to test particular types of hands and make sure they would win if they were supposed to.
I also used Java and implemented a PokerHand object as a comparable, so that I could do something like if(hand1>hand2) playerOneWins++
I also had arrays of outcomes and card values.
class PokerHand implements Comparable<PokerHand> {
public static final String[] OUTCOMES = {"high","one","two","three","straight","flush","full house","four","straight flush","royal flush"};
public static final char[] VALUES = {'2','3','4','5','6','7','8','9','T','J','Q','K','A'};
public static final char[] SUITS = {'S','C','D','H'};
Here is the core functionality, the comparison of two hands:
/** Compare two PokerHand objects based on outcome, or if tie, on face value. */
public int compareTo(PokerHand other) {
int hand1outcome = this.getOutcome();
int hand2outcome = other.getOutcome();
if(hand1outcome==hand2outcome) {
// Resolve by high card.
// First, resolve by high card in finallyhand,
// the cards that were actually important to the
// final outcome.
// If those are tied, resolve by high card in hand.
ValueComparator comp = new ValueComparator();
Collections.sort(this.finallyhand, comp);
Collections.sort(other.finallyhand, comp);
Iterator<Cards> carditer1 = this.finallyhand.iterator();
Iterator<Cards> carditer2 = other.finallyhand.iterator();
// Break ties by highest finallyhand cards
while(carditer1.hasNext() && carditer2.hasNext()) {
Cards c1 = carditer1.next();
Cards c2 = carditer2.next();
if(c1.getValue()!=c2.getValue()) {
return comp.compare(c1,c2);
}
}
// If we get here, it's something like
// two pairs that are tied.
// Use the rest of the hand.
carditer1 = this.hand.iterator();
carditer2 = other.hand.iterator();
// Break ties by highest finallyhand cards
while(carditer1.hasNext() && carditer2.hasNext()) {
Cards c1 = carditer1.next();
Cards c2 = carditer2.next();
if(c1.getValue()!=c2.getValue()) {
return comp.compare(c1,c2);
}
}
// Well sheeeyut
return 0;
} else {
// swapping the normal order so bigger cards come first
return (hand2outcome-hand1outcome);
}
}
I also had two types of methods:
- Utility methods - these methods do things like count number of triplets, number of pairs, number of unique cards, etc.
- Case methods - these check for cases like royal flush, full house, etc.
Example utility methods: check for pairs and triplets:
/** Count pairs. */
protected void countPairs() {
this.nPairs = 0;
// Sort by face value
ValueComparator comp = new ValueComparator();
Collections.sort(hand, comp);
// Count pairs, not triples
for(int i=0; i+1<hand.size(); i++) {
Cards ci = hand.get(i);
Cards cip1 = hand.get(i+1);
if( ci.getValue() == cip1.getValue() ) {
nPairs++;
try {
Cards cip2 = hand.get(i+2);
if( ci.getValue() == cip2.getValue() ) {
nPairs--;
}
} catch(IndexOutOfBoundsException e){
// its cool
}
// Skip new pair
i++;
}
}
}
/** Count three of a kind occurrences. */
protected void countTriplets() {
nThrees = 0;
// Sort by face value
ValueComparator comp = new ValueComparator();
Collections.sort(hand, comp);
// Count pairs, not triples
for(int i=0; i+2<hand.size(); i++) {
if( hand.get(i).getValue()==hand.get(i+1).getValue()
&& hand.get(i).getValue()==hand.get(i+2).getValue() ) {
nThrees++;
try {
if(hand.get(i).getValue()==hand.get(i+3).getValue()) {
nThrees--;
}
} catch(IndexOutOfBoundsException e){
// its cool
}
// Skip new triplet
i++;
i++;
}
}
}
Example case method: check for royal flush
/** Check for royal flush. */
public boolean hasRoyalFlush() {
// Sort by face value
ValueComparator comp = new ValueComparator();
Collections.sort(hand, comp);
// Each card should have same suit
char whichSuit = hand.get(0).getSuit();
// We need one of each
int na = 0, nk = 0, nq = 0, nj = 0, nd = 0;
for(Cards c : hand) {
if(c.getSuit()!=whichSuit) return false;
if(c.getValue()=='A') na++;
if(c.getValue()=='K') nk++;
if(c.getValue()=='Q') nq++;
if(c.getValue()=='J') nj++;
if(c.getValue()=='T') nd++;
}
if( na==1 && nk==1 && nq==1 && nj==1 && nd==1 ) {
finallyhand = (LinkedList<Cards>)( hand.clone() );
return true;
} else {
return false;
}
}
Code
Link: https://git.charlesreid1.com/cs/euler/src/master/scratch/Round2_050-070/054
Flags