Project Euler/54: Difference between revisions
From charlesreid1
m (Replacing charlesreid1.com:3000 with git.charlesreid1.com) |
|||
| (2 intermediate revisions by the same user not shown) | |||
| Line 17: | Line 17: | ||
==Solution Technique== | ==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 <code>if(hand1>hand2) playerOneWins++</code> | |||
I also had arrays of outcomes and card values. | |||
<pre> | |||
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'}; | |||
</pre> | |||
Here is the core functionality, the comparison of two hands: | |||
<pre> | |||
/** 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); | |||
} | |||
} | |||
</pre> | |||
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: | |||
<pre> | |||
/** 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++; | |||
} | |||
} | |||
} | |||
</pre> | |||
Example case method: check for royal flush | |||
<pre> | |||
/** 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; | |||
} | |||
} | |||
</pre> | |||
==Code== | ==Code== | ||
Link: https://charlesreid1.com | Link: https://git.charlesreid1.com/cs/euler/src/master/scratch/Round2_050-070/054 | ||
==Flags== | ==Flags== | ||
{{ProjectEulerFlag}} | {{ProjectEulerFlag}} | ||
Latest revision as of 03:48, 9 October 2019
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