-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit db950e7
Showing
7 changed files
with
2,600,830 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.iml | ||
.idea | ||
out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/** | ||
* An immutable class representing a card from a normal 52-card deck. | ||
*/ | ||
public class Card { | ||
private final int value; // Format: xxxAKQJT 98765432 CDHSrrrr xxPPPPPP | ||
|
||
// Ranks | ||
public static final int DEUCE = 0; | ||
public static final int TREY = 1; | ||
public static final int FOUR = 2; | ||
public static final int FIVE = 3; | ||
public static final int SIX = 4; | ||
public static final int SEVEN = 5; | ||
public static final int EIGHT = 6; | ||
public static final int NINE = 7; | ||
public static final int TEN = 8; | ||
public static final int JACK = 9; | ||
public static final int QUEEN = 10; | ||
public static final int KING = 11; | ||
public static final int ACE = 12; | ||
|
||
// Suits | ||
public static final int CLUBS = 0x8000; | ||
public static final int DIAMONDS = 0x4000; | ||
public static final int HEARTS = 0x2000; | ||
public static final int SPADES = 0x1000; | ||
|
||
// Rank symbols | ||
private static final String RANKS = "23456789TJQKA"; | ||
private static final String SUITS = "shdc"; | ||
|
||
public Card(int rank, int suit) { | ||
if (rank < DEUCE || rank > ACE) { | ||
throw new IllegalArgumentException("Invalid rank."); | ||
} | ||
|
||
if (suit != CLUBS && suit != DIAMONDS && suit != HEARTS && suit != SPADES) { | ||
throw new IllegalArgumentException("Invalid suit."); | ||
} | ||
|
||
value = (1 << (rank + 16)) | suit | (rank << 8) | Tables.PRIMES[rank]; | ||
} | ||
|
||
public static Card fromString(String string) { | ||
if (string.length() != 2) { | ||
throw new IllegalArgumentException("Card string length must be exactly 2."); | ||
} | ||
|
||
final int rank = RANKS.indexOf(string.charAt(0)); | ||
final int suit = SPADES << SUITS.indexOf(string.charAt(1)); | ||
|
||
return new Card(rank, suit); | ||
} | ||
|
||
public int getRank() { | ||
return (value >> 8) & 0xF; | ||
} | ||
|
||
public int getSuit() { | ||
return value & 0xF000; | ||
} | ||
|
||
public int getValue() { | ||
return value; | ||
} | ||
|
||
public String toString() { | ||
char rank = RANKS.charAt(getRank()); | ||
char suit = SUITS.charAt((int) (Math.log(getSuit()) / Math.log(2)) - 12); | ||
return "" + rank + suit; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import java.util.Arrays; | ||
|
||
/** Utility methods for evaluating or creating a hand of cards. */ | ||
public class Hand { | ||
/** | ||
* Poker hand evaluator based on Kevin Suffecool's 5-card hand evaluator and with Paul Senzee's pre-computed hash. | ||
* @param cards a hand of cards to evaluate | ||
* @return the value of the hand as an integer between 1 and 7462 | ||
*/ | ||
public static int evaluate(Card[] cards) { | ||
// Only 5-card hands are supported | ||
if (cards == null || cards.length != 5) | ||
throw new IllegalArgumentException("Exactly 5 cards are required."); | ||
|
||
// Binary representations of each card | ||
final int c1 = cards[0].getValue(); | ||
final int c2 = cards[1].getValue(); | ||
final int c3 = cards[2].getValue(); | ||
final int c4 = cards[3].getValue(); | ||
final int c5 = cards[4].getValue(); | ||
|
||
// No duplicate cards allowed | ||
if (hasDuplicates(new int[]{c1, c2, c3, c4, c5})) | ||
throw new IllegalArgumentException("Illegal hand."); | ||
|
||
// Calculate index in the flushes/unique table | ||
final int index = (c1 | c2 | c3 | c4 | c5) >> 16; | ||
|
||
// Flushes, including straight flushes | ||
if ((c1 & c2 & c3 & c4 & c5 & 0xF000) != 0) | ||
return Tables.Flushes.TABLE[index]; | ||
|
||
// Straight and high card hands | ||
final int value = Tables.Unique.TABLE[index]; | ||
if (value != 0) | ||
return value; | ||
|
||
// Remaining cards | ||
final int product = (c1 & 0xFF) * (c2 & 0xFF) * (c3 & 0xFF) * (c4 & 0xFF) * (c5 & 0xFF); | ||
return Tables.Hash.Values.TABLE[hash(product)]; | ||
} | ||
|
||
/** | ||
* Creates a new 5-card hand from the given string. | ||
* @param string the string to create the hand from, such as "Kd 5s Jc Ah Qc" | ||
* @return a new hand as an array of cards | ||
*/ | ||
public static Card[] fromString(String string) { | ||
final String[] parts = string.split(" "); | ||
final Card[] cards = new Card[parts.length]; | ||
|
||
if (parts.length != 5) | ||
throw new IllegalArgumentException("Exactly 5 cards are required."); | ||
|
||
int index = 0; | ||
for (String part : parts) | ||
cards[index++] = Card.fromString(part); | ||
|
||
return cards; | ||
} | ||
|
||
/** | ||
* Converts the given hand into concatenation of their string representations | ||
* @param cards a hand of cards | ||
* @return a concatenation of the string representations of the given cards | ||
*/ | ||
public static String toString(Card[] cards) { | ||
final StringBuilder builder = new StringBuilder(); | ||
|
||
for (int i = 0; i < cards.length; i++) { | ||
builder.append(cards[i]); | ||
if (i < cards.length - 1) | ||
builder.append(" "); | ||
} | ||
|
||
return builder.toString(); | ||
} | ||
|
||
/** | ||
* Checks if the given array of values has any duplicates. | ||
* @param values the values to check | ||
* @return true if the values contain duplicates, false otherwise | ||
*/ | ||
private static boolean hasDuplicates(int[] values) { | ||
Arrays.sort(values); | ||
for (int i = 1; i < values.length; i++) { | ||
if (values[i] == values[i - 1]) | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private static int hash(int key) { | ||
key += 0xE91AAA35; | ||
key ^= key >>> 16; | ||
key += key << 8; | ||
key ^= key >>> 4; | ||
return ((key + (key << 2)) >>> 19) ^ Tables.Hash.Adjust.TABLE[(key >>> 8) & 0x1FF]; | ||
} | ||
} |
Oops, something went wrong.