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