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
Project Euler project euler notes
Round 1: Problems 1-20 Problem 1 · Problem 2 · Problem 3 · Problem 4 · Problem 5 · Problem 6 · Problem 7 · Problem 8 · Problem 9 · Problem 10 Problem 11 · Problem 12 · Problem 13 · Problem 14 · Problem 15 · Problem 16 · Problem 17 · Problem 18 · Problem 19 · Problem 20 Round 2: Problems 50-70 Problem 51 · Problem 52 · Problem 53 · Problem 54 · Problem 55 · Problem 56 · Problem 57 · Problem 58 · ... · Problem 61 · Problem 62 · Problem 63 · Problem 64 · Problem 65 · Problem 66 · Problem 67 Round 3: Problems 100-110 Problem 100 · Problem 101 · Problem 102 Round 4: Problems 500-510 Problem 500 · Problem 501 * · Problem 502 * Round 5: Problems 150-160 Round 6: Problems 250-260 Round 7: Problems 170-180
|