640 lines
15 KiB
640 lines
15 KiB
import java.util.*; |
|
import java.io.*; |
|
|
|
public class Poker { |
|
|
|
public static void main(String[] args) throws FileNotFoundException { |
|
test1(); |
|
test2(); |
|
test3(); |
|
test4(); |
|
test5(); |
|
} |
|
|
|
|
|
////////////////////////////////////// |
|
// Tests |
|
|
|
|
|
public static void test1() { |
|
PokerHand h1 = new PokerHand("5H 5C 6S 7S KD"); |
|
PokerHand h2 = new PokerHand("2C 3S 8S 8D TD"); |
|
PokerCompare p = new PokerCompare(); |
|
if( p.compare( h1, h2 ) > 0 ) { |
|
System.out.println("Test 1 correct."); |
|
} else { |
|
System.out.println("Test 1 failed."); |
|
} |
|
} |
|
|
|
public static void test2() { |
|
PokerHand h1 = new PokerHand("5D 8C 9S JS AC"); |
|
PokerHand h2 = new PokerHand("2C 5C 7D 8S QH"); |
|
PokerCompare p = new PokerCompare(); |
|
if(p.compare(h1,h2)<0) { |
|
System.out.println("Test 2 correct."); |
|
} else { |
|
System.out.println("Test 2 failed."); |
|
} |
|
} |
|
|
|
|
|
public static void test3() { |
|
PokerHand h1 = new PokerHand("2D 9C AS AH AC"); |
|
PokerHand h2 = new PokerHand("3D 6D 7D TD QD"); |
|
PokerCompare p = new PokerCompare(); |
|
if(p.compare(h1,h2)>0) { |
|
System.out.println("Test 3 correct."); |
|
} else { |
|
System.out.println("Test 3 failed."); |
|
} |
|
} |
|
|
|
|
|
public static void test4() { |
|
PokerHand h1 = new PokerHand("4D 6S 9H QH QC"); |
|
PokerHand h2 = new PokerHand("3D 6D 7H QD QS"); |
|
PokerCompare p = new PokerCompare(); |
|
if(p.compare(h1,h2)<0) { |
|
System.out.println("Test 4 correct."); |
|
} else { |
|
System.out.println("Test 4 failed."); |
|
} |
|
} |
|
|
|
|
|
public static void test5() { |
|
PokerHand h1 = new PokerHand("2H 2D 4C 4D 4S"); |
|
PokerHand h2 = new PokerHand("3C 3D 3S 9S 9D"); |
|
PokerCompare p = new PokerCompare(); |
|
if(p.compare(h1,h2)<0) { |
|
System.out.println("Test 5 correct."); |
|
} else { |
|
System.out.println("Test 5 failed."); |
|
} |
|
} |
|
|
|
|
|
|
|
////////////////////////////////////// |
|
// Main driver/main problem |
|
|
|
|
|
|
|
public static void doit() throws FileNotFoundException { |
|
Scanner s = new Scanner( new BufferedReader( new FileReader("poker.txt"))); |
|
|
|
LinkedList<PokerHand> player1 = new LinkedList<PokerHand>(); |
|
LinkedList<PokerHand> player2 = new LinkedList<PokerHand>(); |
|
|
|
while(s.hasNextLine()) { |
|
String line = s.nextLine(); |
|
int middleIndex = 2*5 + (5-1) +1; |
|
|
|
String hand1 = line.substring(0, middleIndex); |
|
String hand2 = line.substring(middleIndex, line.length()); |
|
|
|
player1.add(new PokerHand(hand1)); |
|
player2.add(new PokerHand(hand2)); |
|
} |
|
|
|
// Now count the number of wins for player 1 |
|
int p1w = 0; |
|
PokerCompare p = new PokerCompare(); |
|
for(int i=0; i<player1.size(); i++) { |
|
|
|
System.out.println(player1.get(i) + "\t\t\t" + player2.get(i)); |
|
if( p.compare(player1.get(i), player2.get(i)) < 0 ) { |
|
System.out.println("player 1 wins."); |
|
} |
|
System.out.println(); |
|
|
|
if( p.compare(player1.get(i), player2.get(i)) < 0 ) { |
|
// player 1 wins, has higher ranked hand |
|
p1w++; |
|
} |
|
} |
|
|
|
System.out.println("Number of wins for player 1: " + p1w); |
|
|
|
} |
|
} |
|
|
|
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'}; |
|
|
|
private class Cards { |
|
char suit; |
|
char value; |
|
public Cards(char suit,char value) { this.suit=suit; this.value=value; } |
|
public char getSuit() { return suit; } |
|
public char getValue() { return value; } |
|
public String toString() { |
|
StringBuffer sb = new StringBuffer(); |
|
sb.append(value); |
|
sb.append(suit); |
|
return sb.toString(); |
|
} |
|
} |
|
|
|
|
|
/////////////////////////////// |
|
// Implement a poker hand |
|
|
|
// The list of five Cards that are dealt to a given player |
|
LinkedList<Cards> hand; |
|
|
|
// Final cards that matter to the outcome of the game |
|
LinkedList<Cards> finallyhand; |
|
|
|
|
|
// Keep track of various quantities in the hand |
|
int nSuits; |
|
int nValues; |
|
int nPairs; |
|
int nThrees; |
|
|
|
|
|
public PokerHand(String handStr) { |
|
hand = new LinkedList<Cards>(); |
|
finallyhand = new LinkedList<Cards>(); |
|
String[] tokens = handStr.split(" "); |
|
// assume exactly 5 tokens, otherwise you're a masochist |
|
for(int i=0; i<tokens.length; i++) { |
|
char suit = tokens[i].charAt(1); |
|
char value = tokens[i].charAt(0); |
|
hand.add( new Cards(suit, value) ); |
|
} |
|
countSuits(); |
|
countValues(); |
|
countPairs(); |
|
countTriplets(); |
|
} |
|
|
|
public String toString() { |
|
StringBuffer sb = new StringBuffer(); |
|
for(Cards c : hand) { |
|
sb.append(c.getValue()); |
|
sb.append(c.getSuit()); |
|
sb.append(" "); |
|
} |
|
sb.append( OUTCOMES[this.getOutcome()] ); |
|
return sb.toString(); |
|
} |
|
|
|
/** Card comparator: compare cards by face value. */ |
|
private class ValueComparator implements Comparator<Cards> { |
|
public int compare(Cards c1, Cards c2) { |
|
int c1outcome = indexOf(VALUES,c1.value); |
|
int c2outcome = indexOf(VALUES,c2.value); |
|
// swapping the normal order so bigger cards come first |
|
return (c2outcome-c1outcome); |
|
} |
|
} |
|
|
|
/** Card comparator: compare cards by suit. */ |
|
private class SuitComparator implements Comparator<Cards> { |
|
public int compare(Cards c1, Cards c2) { |
|
int c1outcome = indexOf(SUITS,c1.suit); |
|
int c2outcome = indexOf(SUITS,c1.suit); |
|
// swapping the normal order so bigger cards come first |
|
return (c2outcome-c1outcome); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
///////////////////////////////////////// |
|
// This is the heart of the problem. |
|
|
|
|
|
|
|
|
|
/** 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); |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////// |
|
// Utility counting methods |
|
|
|
|
|
|
|
/** Count number of unique suits. */ |
|
protected void countSuits() { |
|
this.nSuits = 0; |
|
Set<Character> suits = new HashSet<Character>(); |
|
for(Cards c : hand) { |
|
suits.add(c.getValue()); |
|
} |
|
} |
|
|
|
/** Count number of unique values. */ |
|
protected void countValues() { |
|
this.nValues = 0; |
|
Set<Character> values = new HashSet<Character>(); |
|
for(Cards c : hand) { |
|
values.add(c.getValue()); |
|
} |
|
} |
|
|
|
/** Count pairs. */ |
|
protected void countPairs() { |
|
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++; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////// |
|
// Here is the meat of the class. |
|
|
|
/** 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()=='D') nd++; |
|
} |
|
if( na==1 && nk==1 && nq==1 && nj==1 && nd==1 ) { |
|
finallyhand = (LinkedList<Cards>)( hand.clone() ); |
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Check for straight flush - same suit cards in order. */ |
|
public boolean hasStraightFlush() { |
|
// If we have a straight or a flush, these will take care of finallyhand for us. |
|
if( hasStraight() && hasFlush() ) { |
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Four of a kind */ |
|
public boolean hasFour() { |
|
if(nValues==2 && nPairs==0){ |
|
|
|
// Only four of a kind cards should go in finallyhand |
|
for(int i=0; i<hand.size(); i++) { |
|
int duper = 0; |
|
for(int j=0; j<hand.size(); j++) { |
|
if(i==j) { |
|
continue; |
|
} |
|
if(hand.get(i).getValue()==hand.get(j).getValue()) { |
|
duper++; |
|
} |
|
} |
|
if(duper==4) { |
|
finallyhand.add(hand.get(i)); |
|
} |
|
} |
|
|
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Full house. */ |
|
public boolean hasFullHouse() { |
|
if(nValues==2 && nPairs==1) { |
|
|
|
// Only three of a kind cards should go in finallyhand |
|
for(int i=0; i<hand.size(); i++) { |
|
int duper = 0; |
|
for(int j=0; j<hand.size(); j++) { |
|
if(i==j) { |
|
continue; |
|
} |
|
if(hand.get(i).getValue()==hand.get(j).getValue()) { |
|
duper++; |
|
} |
|
} |
|
if(duper==2) { |
|
finallyhand.add(hand.get(i)); |
|
} |
|
} |
|
|
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Check for flush - matching straights. */ |
|
public boolean hasFlush() { |
|
// Add suits to a set, size should be 1 |
|
Set<Character> suits = new HashSet<Character>(); |
|
for(Cards c : hand) { |
|
suits.add(c.getSuit()); |
|
} |
|
if(suits.size()==1) { |
|
finallyhand = (LinkedList<Cards>)( hand.clone() ); |
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Check for straight - cards in order. */ |
|
public boolean hasStraight() { |
|
// Sort by face value |
|
ValueComparator comp = new ValueComparator(); |
|
Collections.sort(hand, comp); |
|
|
|
// This is a bit messy, but basically it checks the index of each card |
|
// and ensures that the next card has an index of previous - 1. |
|
// |
|
// Ace is a special case - it can either end a straight DJQKA, |
|
// or it can start a straight A2345. |
|
// We have ace hard coded in the values index at the end, |
|
// so it always behaves as expected with DJQKA. |
|
// However, if we see an ace at the beginning, |
|
// we have to check if it's an ok start. |
|
|
|
int priorCardIndex, thisCardIndex; |
|
|
|
Iterator<Cards> iter = hand.iterator(); |
|
Cards mycard = iter.next(); |
|
if(mycard.getValue()=='A') { |
|
priorCardIndex = -1; |
|
} else { |
|
priorCardIndex = indexOf(VALUES, mycard.getValue()); |
|
} |
|
|
|
while(iter.hasNext()) { |
|
mycard = iter.next(); |
|
thisCardIndex = indexOf(VALUES, mycard.getValue()); |
|
if( thisCardIndex != (priorCardIndex-1) ) { |
|
return false; |
|
} |
|
} |
|
finallyhand = (LinkedList<Cards>)( hand.clone() ); |
|
return true; |
|
|
|
} |
|
|
|
/** Check for three pairs */ |
|
public boolean hasThree() { |
|
if(nThrees>0) { |
|
|
|
// Only three of a kind cards should go in finallyhand |
|
for(int i=0; i<hand.size(); i++) { |
|
int duper = 0; |
|
for(int j=0; j<hand.size(); j++) { |
|
if(i==j) { |
|
continue; |
|
} |
|
if(hand.get(i).getValue()==hand.get(j).getValue()) { |
|
duper++; |
|
} |
|
} |
|
if(duper==2) { |
|
finallyhand.add(hand.get(i)); |
|
} |
|
} |
|
|
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Check for two pairs */ |
|
public boolean hasTwo() { |
|
if(nPairs==2) { |
|
|
|
// Only pair cards should go in finallyhand |
|
for(int i=0; i<hand.size(); i++) { |
|
int duper = 0; |
|
for(int j=0; j<hand.size(); j++) { |
|
if(i==j) { |
|
continue; |
|
} |
|
if(hand.get(i).getValue()==hand.get(j).getValue()) { |
|
duper++; |
|
} |
|
} |
|
if(duper==1) { |
|
finallyhand.add(hand.get(i)); |
|
} |
|
} |
|
|
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** Check for one pair */ |
|
public boolean hasOne() { |
|
if(nPairs==1) { |
|
|
|
// Only pair cards should go in finallyhand |
|
for(int i=0; i<hand.size(); i++) { |
|
int duper = 0; |
|
for(int j=0; j<hand.size(); j++) { |
|
if(i==j) { |
|
continue; |
|
} |
|
if(hand.get(i).getValue()==hand.get(j).getValue()) { |
|
duper++; |
|
} |
|
} |
|
if(duper==1) { |
|
finallyhand.add(hand.get(i)); |
|
} |
|
} |
|
|
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
// Finished the meat of the class. |
|
//////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
/** Get string indicating outcome. */ |
|
public int getOutcome() { |
|
// Check in order of rank: |
|
// royal flush |
|
if(hasRoyalFlush()) { |
|
return indexOf(OUTCOMES,"royal flush"); |
|
} else if(hasFour()) { |
|
return indexOf(OUTCOMES,"four"); |
|
} else if(hasFullHouse()) { |
|
return indexOf(OUTCOMES,"full house"); |
|
} else if(hasFlush()) { |
|
return indexOf(OUTCOMES,"flush"); |
|
} else if(hasStraight()) { |
|
return indexOf(OUTCOMES,"straight"); |
|
} else if(hasThree()) { |
|
return indexOf(OUTCOMES,"three"); |
|
} else if(hasTwo()) { |
|
return indexOf(OUTCOMES,"two"); |
|
} else if(hasOne()) { |
|
return indexOf(OUTCOMES,"one"); |
|
} else { |
|
finallyhand = (LinkedList<Cards>)( hand.clone() ); |
|
return indexOf(OUTCOMES,"high"); |
|
} |
|
} |
|
|
|
|
|
public int indexOf(char[] arr, char target) { |
|
for(int i=0; i<arr.length; i++) { |
|
if(arr[i]==target) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
public int indexOf(String[] arr, String target) { |
|
for(int i=0; i<arr.length; i++) { |
|
if(arr[i].equals(target)) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
} |
|
|
|
|
|
class PokerCompare implements Comparator<PokerHand> { |
|
public PokerCompare() {} |
|
public int compare(PokerHand hand1, PokerHand hand2) { |
|
return hand1.compareTo(hand2); |
|
} |
|
} |
|
|
|
|
|
|