Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmp committed Mar 18, 2018
0 parents commit db950e7
Show file tree
Hide file tree
Showing 7 changed files with 2,600,830 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.iml
.idea
out
72 changes: 72 additions & 0 deletions src/Card.java
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;
}
}
100 changes: 100 additions & 0 deletions src/Hand.java
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];
}
}
Loading

0 comments on commit db950e7

Please sign in to comment.