package common.handeval.stevebrecher;
/**
* Non-instantiable class containing a variety of static poker hand evaluation and related utility methods.
* <p>
* All of the methods are thread-safe.
* <p>
* Each evaluation method takes a single parameter representing a hand of five to
* seven cards represented in four 13-bit masks, one mask per suit, in
* the low-order 52 bits of a long (64 bits). In each mask, bit 0 set
* (0x0001) for a deuce, ..., bit 12 set (0x1000) for an ace. Each mask
* denotes the ranks present in one of the suits. The ordering of the
* 13-bit suit fields is immaterial.
* <p>
* A hand parameter can be built by encoding a {@link CardSet} or by bitwise
* OR-ing, or adding, the encoded values of individual {@link Card}s. These
* encodings are returned by an {@link #encode encode} method.
* <p>
* Different methods are called for high and for lowball evaluation. The
* return value format below is the same except: For low evaluation, as for
* wheels in high evaluation, Ace is rank 1 and its mask bit is the LS bit;
* otherwise Ace is rank 14, mask bit 0x1000, and the deuce's mask bit is
* the LS bit. 8-or-better low evaluation methods may also return {@link #NO_8_LOW}.
* <p>
* For high evaulation, if results R1 > R2 then hand 1 beats hand 2;<br>
* For low evaluation, if results R1 > R2 then hand 2 beats hand 1.
* <p>
* Each evaluation method's return value is an int; 32 bits = 0x0VTBKKKK
* where each letter refers to a 4-bit nybble:<pre>
* V nybble = category code ranging from {@link HandCategory#NO_PAIR}<code>.ordinal()</code>
* to {@link HandCategory#STRAIGHT_FLUSH}<code>.ordinal()</code>
* T nybble = rank (2..14) of top pair for two pair, 0 otherwise
* B nybble = rank (1..14) of quads or trips (including full house trips),
* or rank of high card (5..14) in straight or straight flush,
* or rank of bottom pair for two pair (hence the symbol "B"),
* or rank of pair for one pair,
* or 0 otherwise
* KKKK mask = 16-bit mask with...
* 5 bits set for no pair or (non-straight-)flush
* 3 bits set for kickers with pair,
* 2 bits set for kickers with trips,
* 1 bit set for pair within full house or kicker with quads
* or kicker with two pair
* or 0 otherwise</pre>
* @version 2008Apr27.0
* @author Steve Brecher
*
*/
// 2008Apr27.0
// fix hand6Eval's calls to flushAndOrStraight6
// 2006Dec05.0
// original Java release, ported from C
public final class HandEval {
private HandEval() {
} // no instances
/**
* Returns a value which can be used in building a parameter to one of the HandEval evaluation methods.
* @param card a {@link Card}
* @return a value which may be bitwise OR'ed or added to other such
* values to build a parameter to one of the HandEval evaluation methods.
*/
public static long encode(final Card card) {
return 0x1L << (card.suitOf().ordinal() * 13 + card.rankOf().ordinal());
}
/**
* Returns a value which can be used as a parameter to one of the HandEval evaluation methods.
* @param cs a {@link CardSet}
* @return a value which can be used as a parameter to one of the HandEval evaluation methods.
* The value may also be bitwise OR'ed or added to other such
* values to build an evaluation method parameter.
*/
public static long encode(final CardSet cs) {
long result = 0;
for (Card c : cs)
result |= encode(c);
return result;
}
public static enum HandCategory {
NO_PAIR, PAIR, TWO_PAIR, THREE_OF_A_KIND, STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH;
}
private static final int BOT_SHIFT = 16;
private static final int TOP_SHIFT = BOT_SHIFT + 4;
private static final int VALUE_SHIFT = TOP_SHIFT + 4;
// javac doesn't propagate NO_PAIR (==0) so doesn't constant-fold it out of bitwise-or expressions
// private static final int NO_PAIR = HandCategory.NO_PAIR.ordinal() << VALUE_SHIFT;
private static final int PAIR = HandCategory.PAIR.ordinal() << VALUE_SHIFT;
private static final int TWO_PAIR = HandCategory.TWO_PAIR.ordinal() << VALUE_SHIFT;
private static final int THREE_OF_A_KIND = HandCategory.THREE_OF_A_KIND.ordinal() << VALUE_SHIFT;
private static final int STRAIGHT = HandCategory.STRAIGHT.ordinal() << VALUE_SHIFT;
private static final int FLUSH = HandCategory.FLUSH.ordinal() << VALUE_SHIFT;
private static final int FULL_HOUSE = HandCategory.FULL_HOUSE.ordinal() << VALUE_SHIFT;
private static final int FOUR_OF_A_KIND = HandCategory.FOUR_OF_A_KIND.ordinal() << VALUE_SHIFT;
private static final int STRAIGHT_FLUSH = HandCategory.STRAIGHT_FLUSH.ordinal() << VALUE_SHIFT;
/* Arrays for which index is bit mask of card ranks in hand: */
private static final int ARRAY_SIZE = 0x1FC0 + 1; // all combos of up to 7 of LS 13 bits on
private static final int[] straightValue = new int[ARRAY_SIZE]; // STRAIGHT | (straight's high card rank (5..14) << BOT_SHIFT); 0 if no straight
private static final int[] nbrOfRanks = new int[ARRAY_SIZE]; // count of bits set
private static final int[] hiTopRankTWO_PAIR = new int[ARRAY_SIZE]; // TWO_PAIR | ((rank (2..kA) of the highest bit set) << TOP_SHIFT)
private static final int[] hiBotRank = new int[ARRAY_SIZE]; // (rank (2..kA) of the highest bit set) << BOT_SHIFT
private static final int[] hiRankMask = new int[ARRAY_SIZE]; // all bits except highest reset
private static final int[] hi2RanksMask = new int[ARRAY_SIZE]; // all bits except highest 2 reset
private static final int[] hi3RanksMask = new int[ARRAY_SIZE]; // all bits except highest 3 reset
private static final int[] hi5RanksMask = new int[ARRAY_SIZE]; // all bits except highest 5 reset
private static final int[] lo5RanksMask = new int[ARRAY_SIZE]; // all bits except lowest 5 8-or-better reset; 0 if not at least 5 8-or-better bits set
private static final int[] lo3RanksMask = new int[ARRAY_SIZE]; // all bits except lowest 3 8-or-better reset; 0 if not at least 3 8-or-better bits set
/**
* Greater than any return value of the HandEval evaluation methods.
*/
public static final int NO_8_LOW = STRAIGHT_FLUSH + (1 << VALUE_SHIFT);
private static final int[] loEvalOrNo8Low = new int[ARRAY_SIZE]; // 5 bits set in LS 8 bits, or NO_8_LOW */
private static int flushAndOrStraight7(final int ranks, final int c, final int d, final int h, final int s) {
int i, j;
if ((j = nbrOfRanks[c]) > 7 - 5) {
// there's either a club flush or no flush
if (j >= 5)
if ((i = straightValue[c]) == 0)
return FLUSH | hi5RanksMask[c];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
} else if ((j += (i = nbrOfRanks[d])) > 7 - 5) {
if (i >= 5)
if ((i = straightValue[d]) == 0)
return FLUSH | hi5RanksMask[d];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
} else if ((j += (i = nbrOfRanks[h])) > 7 - 5) {
if (i >= 5)
if ((i = straightValue[h]) == 0)
return FLUSH | hi5RanksMask[h];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
} else
/* total cards in other suits <= 7-5: spade flush: */
if ((i = straightValue[s]) == 0)
return FLUSH | hi5RanksMask[s];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
return straightValue[ranks];
}
/**
* Returns the value of the best 5-card high poker hand from 7 cards.
* @param hand bit mask with one bit set for each of 7 cards.
* @return the value of the best 5-card high poker hand.
*/
public static int hand7Eval(long hand) {
int i, j, ranks;
/*
* The low-order 52 bits of hand contains four 13-bit fields, one
* field per suit. The high-order 12 bits are clear. Get the
* respective fields into variables.
* We don't care which suit is which; we arbitrarily call them c,d,h,s.
*/
final int c = (int) hand & 0x1FFF;
final int d = ((int) hand >>> 13) & 0x1FFF;
final int h = (int) (hand >>> 26) & 0x1FFF;
final int s = (int) (hand >>> 39);
switch (nbrOfRanks[ranks = c | d | h | s]) {
case 2:
/*
* quads with trips kicker
*/
i = c & d & h & s; /* bit for quads */
return FOUR_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
case 3:
/*
* trips and pair (full house) with non-playing pair,
* or two trips (full house) with non-playing singleton,
* or quads with pair and singleton
*/
/* bits for singleton, if any, and trips, if any: */
if (nbrOfRanks[i = c ^ d ^ h ^ s] == 3) {
/* two trips (full house) with non-playing singleton */
if (nbrOfRanks[i = c & d] != 2)
if (nbrOfRanks[i = c & h] != 2)
if (nbrOfRanks[i = c & s] != 2)
if (nbrOfRanks[i = d & h] != 2)
if (nbrOfRanks[i = d & s] != 2)
i = h & s; /* bits for the trips */
return FULL_HOUSE | hiBotRank[i] | (i ^ hiRankMask[i]);
}
if ((j = c & d & h & s) != 0) /* bit for quads */
/* quads with pair and singleton */
return FOUR_OF_A_KIND | hiBotRank[j] | (hiRankMask[ranks ^ j]);
/* trips and pair (full house) with non-playing pair */
return FULL_HOUSE | hiBotRank[i] | (hiRankMask[ranks ^ i]);
case 4:
/*
* three pair and singleton,
* or trips and pair (full house) and two non-playing singletons,
* or quads with singleton kicker and two non-playing singletons
*/
i = c ^ d ^ h ^ s; // the bit(s) of the trips, if any, and singleton(s)
if (nbrOfRanks[i] == 1) {
/* three pair and singleton */
j = ranks ^ i; /* the three bits for the pairs */
ranks = hiRankMask[j]; /* bit for the top pair */
j ^= ranks; /* bits for the two bottom pairs */
return hiTopRankTWO_PAIR[ranks] | hiBotRank[j] | hiRankMask[(hiRankMask[j] ^ j) | i];
}
if ((j = c & d & h & s) == 0) {
// trips and pair (full house) and two non-playing singletons
i ^= ranks; /* bit for the pair */
if ((j = (c & d) & (~i)) == 0)
j = (h & s) & (~i); /* bit for the trips */
return FULL_HOUSE | hiBotRank[j] | i;
}
// quads with singleton kicker and two non-playing singletons
return FOUR_OF_A_KIND | hiBotRank[j] | (hiRankMask[i]);
case 5:
/*
* flush and/or straight,
* or two pair and three singletons,
* or trips and four singletons
*/
if ((i = flushAndOrStraight7(ranks, c, d, h, s)) != 0)
return i;
i = c ^ d ^ h ^ s; // the bits of the trips, if any, and singletons
if (nbrOfRanks[i] != 5) {
/* two pair and three singletons */
j = i ^ ranks; /* the two bits for the pairs */
return hiTopRankTWO_PAIR[j] | hiBotRank[hiRankMask[j] ^ j] | hiRankMask[i];
}
/* trips and four singletons */
if ((j = c & d) == 0)
j = h & s;
return THREE_OF_A_KIND | hiBotRank[j] | (hi2RanksMask[i ^ j]);
case 6:
/*
* flush and/or straight,
* or one pair and three kickers and two nonplaying singletons
*/
if ((i = flushAndOrStraight7(ranks, c, d, h, s)) != 0)
return i;
i = c ^ d ^ h ^ s; /* the bits of the five singletons */
return PAIR | hiBotRank[ranks ^ i] | hi3RanksMask[i];
case 7:
/*
* flush and/or straight or no pair
*/
if ((i = flushAndOrStraight7(ranks, c, d, h, s)) != 0)
return i;
return /* NO_PAIR | */hi5RanksMask[ranks];
} /* end switch */
return 0; /* never reached, but avoids compiler warning */
}
/**
* Returns the value of the best 5-card Razz poker hand from 7 cards.
* @param hand bit mask with one bit set for each of 7 cards.
* @return the value of the best 5-card Razz poker hand.
*/
public static int handRazzEval(long hand) {
// each of the following extracts a 13-bit field from hand and
// rotates it left to position the ace in the least significant bit
final int c = (((int) hand & 0x1FFF) << 1) + (((int) hand ^ 0x1000) >> 12);
final int d = (((int) hand >> 12) & 0x3FFE) + (((int) hand ^ (0x1000 << 13)) >> 25);
final int h = ((int) (hand >> 25) & 0x3FFE) + (int) ((hand ^ (0x1000L << 26)) >> 38);
final int s = ((int) (hand >> 38) & 0x3FFE) + (int) ((hand ^ (0x1000L << 39)) >> 51);
final int ranks = c | d | h | s;
int i, j;
switch (nbrOfRanks[ranks]) {
case 2:
/* AAAABBB -- full house */
i = c & d & h & s; /* bit for quads */
j = i ^ ranks; /* bit for trips */
// it can't matter in comparison of results from a 52-card deck,
// but we return the correct value per relative ranks
if (i > j)
return FULL_HOUSE | hiBotRank[i] | (j);
return FULL_HOUSE | hiBotRank[j] | (i);
case 3:
/*
* AAABBBC -- two pair,
* AAAABBC -- two pair,
* AAABBCC -- two pair w/ kicker = highest rank.
*/
/* bits for singleton, if any, and trips, if any: */
if (nbrOfRanks[i = c ^ d ^ h ^ s] == 3) {
/* odd number of each rank: AAABBBC -- two pair */
if (nbrOfRanks[i = c & d] != 2)
if (nbrOfRanks[i = c & h] != 2)
if (nbrOfRanks[i = c & s] != 2)
if (nbrOfRanks[i = d & h] != 2)
if (nbrOfRanks[i = d & s] != 2)
i = h & s; /* bits for the trips */
return hiTopRankTWO_PAIR[i] | hiBotRank[i ^ hiRankMask[i]] | (ranks ^ i);
}
if ((j = c & d & h & s) != 0) { /* bit for quads */
/* AAAABBC -- two pair */
j = ranks ^ i; /* bits for pairs */
return hiTopRankTWO_PAIR[j] | hiBotRank[j ^ hiRankMask[j]] | i;
}
/* AAABBCC -- two pair w/ kicker = highest rank */
i = hiRankMask[ranks]; /* kicker bit */
j = ranks ^ i; /* pairs bits */
return hiTopRankTWO_PAIR[j] | hiBotRank[j ^ hiRankMask[j]] | i;
case 4:
/*
* AABBCCD -- one pair (lowest of A, B, C),
* AAABBCD -- one pair (A or B),
* AAAABCD -- one pair (A)
*/
i = c ^ d ^ h ^ s; /* the bit(s) of the trips, if any,
and singleton(s) */
if (nbrOfRanks[i] == 1) {
/* AABBCCD -- one pair (C with ABD) */
/* D's bit is in i */
j = hi2RanksMask[ranks ^ i] | i; /* kickers */
return PAIR | hiBotRank[ranks ^ j] | j;
}
if ((j = c & d & h & s) == 0) {
/* AAABBCD -- one pair (A or B) */
i ^= ranks; /* bit for B */
if ((j = (c & d) & (~i)) == 0)
j = (h & s) & (~i); /* bit for A */
if (i < j)
return PAIR | hiBotRank[i] | (ranks ^ i);
return PAIR | hiBotRank[j] | (ranks ^ j);
}
/* AAAABCD -- one pair (A) */
return PAIR | hiBotRank[j] | i;
case 5:
return /* NO_PAIR | */ranks;
case 6:
return /* NO_PAIR | */lo5RanksMask[ranks];
case 7:
return /* NO_PAIR | */lo5RanksMask[ranks];
} /* end switch */
return 0; /* never reached, but avoids compiler warning */
}
private static int flushAndOrStraight6(final int ranks, final int c, final int d, final int h, final int s) {
int i, j;
if ((j = nbrOfRanks[c]) > 6 - 5) {
// there's either a club flush or no flush
if (j >= 5)
if ((i = straightValue[c]) == 0)
return FLUSH | hi5RanksMask[c];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
} else if ((j += (i = nbrOfRanks[d])) > 6 - 5) {
if (i >= 5)
if ((i = straightValue[d]) == 0)
return FLUSH | hi5RanksMask[d];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
} else if ((j += (i = nbrOfRanks[h])) > 6 - 5) {
if (i >= 5)
if ((i = straightValue[h]) == 0)
return FLUSH | hi5RanksMask[h];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
} else
/* total cards in other suits <= N-5: spade flush: */
if ((i = straightValue[s]) == 0)
return FLUSH | hi5RanksMask[s];
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
return straightValue[ranks];
}
/**
* Returns the value of the best 5-card high poker hand from 6 cards.
* @param hand bit mask with one bit set for each of 6 cards.
* @return the value of the best 5-card high poker hand.
*/
public static int hand6Eval(long hand) {
final int c = (int) hand & 0x1FFF;
final int d = ((int) hand >>> 13) & 0x1FFF;
final int h = (int) (hand >>> 26) & 0x1FFF;
final int s = (int) (hand >>> 39);
final int ranks = c | d | h | s;
int i, j, k;
switch (nbrOfRanks[ranks]) {
case 2: /* quads with pair kicker,
or two trips (full house) */
/* bits for trips, if any: */
if ((nbrOfRanks[i = c ^ d ^ h ^ s]) != 0)
/* two trips (full house) */
return FULL_HOUSE | hiBotRank[i] | (i ^ hiRankMask[i]);
/* quads with pair kicker */
i = c & d & h & s; /* bit for quads */
return FOUR_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
case 3: /* quads with singleton kicker and non-playing singleton,
or full house with non-playing singleton,
or two pair with non-playing pair */
if ((c ^ d ^ h ^ s) == 0) {
/* no trips or singletons: three pair */
i = hiRankMask[ranks]; /* bit for the top pair */
k = ranks ^ i; /* bits for the bottom two pairs */
j = hiRankMask[k]; /* bit for the middle pair */
return hiTopRankTWO_PAIR[i] | hiBotRank[j] | (k ^ j);
}
if ((i = c & d & h & s) == 0) {
/* full house with singleton */
if ((i = c & d & h) == 0)
if ((i = c & d & s) == 0)
if ((i = c & h & s) == 0)
i = d & h & s; /* bit of trips */
j = c ^ d ^ h ^ s; /* the bits of the trips
and singleton */
return FULL_HOUSE | hiBotRank[i] | (j ^ ranks);
}
/* quads with kicker and singleton */
return FOUR_OF_A_KIND | hiBotRank[i] | (hiRankMask[i ^ ranks]);
case 4: /* trips and three singletons,
or two pair and two singletons */
if ((i = c ^ d ^ h ^ s) != ranks) {
/* two pair and two singletons */
j = i ^ ranks; /* the two bits for the pairs */
return hiTopRankTWO_PAIR[j] | hiBotRank[hiRankMask[j] ^ j] | hiRankMask[i];
}
/* trips and three singletons */
if ((i = c & d) == 0)
i = h & s; /* bit of trips */
return THREE_OF_A_KIND | hiBotRank[i] | (hi2RanksMask[i ^ ranks]);
case 5: /* flush and/or straight,
or one pair and three kickers and
one non-playing singleton */
if ((i = flushAndOrStraight6(ranks, c, d, h, s)) != 0)
return i;
i = c ^ d ^ h ^ s; /* the bits of the four singletons */
return PAIR | hiBotRank[ranks ^ i] | hi3RanksMask[i];
case 6: /* flush and/or straight or no pair */
if ((i = flushAndOrStraight6(ranks, c, d, h, s)) != 0)
return i;
return /* NO_PAIR | */hi5RanksMask[ranks];
} /* end switch */
return 0; /* never reached, but avoids compiler warning */
}
/**
* Returns the value of a 5-card poker hand.
* @param hand bit mask with one bit set for each of 5 cards.
* @return the value of the hand.
*/
public static int hand5Eval(long hand) {
final int c = (int) hand & 0x1FFF;
final int d = ((int) hand >>> 13) & 0x1FFF;
final int h = (int) (hand >>> 26) & 0x1FFF;
final int s = (int) (hand >>> 39);
final int ranks = c | d | h | s;
int i, j;
switch (nbrOfRanks[ranks]) {
case 2: /* quads or full house */
i = c & d; /* any two suits */
if ((i & h & s) == 0) { /* no bit common to all suits */
i = c ^ d ^ h ^ s; /* trips bit */
return FULL_HOUSE | hiBotRank[i] | (i ^ ranks);
} else
/* the quads bit must be present in each suit mask,
but the kicker bit in no more than one; so we need
only AND any two suit masks to get the quad bit: */
return FOUR_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
case 3: /* trips and two kickers,
or two pair and kicker */
if ((i = c ^ d ^ h ^ s) == ranks) {
/* trips and two kickers */
if ((i = c & d) != 0)
return THREE_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
if ((i = c & h) != 0)
return THREE_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
i = d & h;
return THREE_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
}
/* two pair and kicker; i has kicker bit */
j = i ^ ranks; /* j has pairs bits */
return hiTopRankTWO_PAIR[j] | hiBotRank[j ^ hiRankMask[j]] | i;
case 4: /* pair and three kickers */
i = c ^ d ^ h ^ s; /* kicker bits */
return PAIR | hiBotRank[ranks ^ i] | i;
case 5: /* flush and/or straight, or no pair */
if ((i = straightValue[ranks]) == 0)
i = ranks;
if (c != 0) { /* if any clubs... */
if (c != ranks) /* if no club flush... */
return i;
} /* return straight or no pair value */
else if (d != 0) {
if (d != ranks)
return i;
} else if (h != 0) {
if (h != ranks)
return i;
}
/* else s == ranks: spade flush */
/* There is a flush */
if (i == ranks)
/* no straight */
return FLUSH | ranks;
else
return (STRAIGHT_FLUSH - STRAIGHT) + i;
}
return 0; /* never reached, but avoids compiler warning */
}
/**
* Returns the Ace-to-5 value of a 5-card low poker hand.
* @param hand bit mask with one bit set for each of 5 cards.
* @return the Ace-to-5 low value of the hand.
*/
public static int hand5Ato5LoEval(long hand) {
// each of the following extracts a 13-bit field from hand and
// rotates it left to position the ace in the least significant bit
final int c = (((int) hand & 0x1FFF) << 1) + (((int) hand ^ 0x1000) >> 12);
final int d = (((int) hand >> 12) & 0x3FFE) + (((int) hand ^ (0x1000 << 13)) >> 25);
final int h = ((int) (hand >> 25) & 0x3FFE) + (int) ((hand ^ (0x1000L << 26)) >> 38);
final int s = ((int) (hand >> 38) & 0x3FFE) + (int) ((hand ^ (0x1000L << 39)) >> 51);
final int ranks = c | d | h | s;
int i, j;
switch (nbrOfRanks[ranks]) {
case 2: /* quads or full house */
i = c & d; /* any two suits */
if ((i & h & s) == 0) { /* no bit common to all suits */
i = c ^ d ^ h ^ s; /* trips bit */
return FULL_HOUSE | hiBotRank[i] | (i ^ ranks);
} else
/* the quads bit must be present in each suit mask,
but the kicker bit in no more than one; so we need
only AND any two suit masks to get the quad bit: */
return FOUR_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
case 3: /* trips and two kickers,
or two pair and kicker */
if ((i = c ^ d ^ h ^ s) == ranks) {
/* trips and two kickers */
if ((i = c & d) != 0)
return THREE_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
if ((i = c & h) != 0)
return THREE_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
i = d & h;
return THREE_OF_A_KIND | hiBotRank[i] | (i ^ ranks);
}
/* two pair and kicker; i has kicker bit */
j = i ^ ranks; /* j has pairs bits */
return hiTopRankTWO_PAIR[j] | hiBotRank[j ^ hiRankMask[j]] | i;
case 4: /* pair and three kickers */
i = c ^ d ^ h ^ s; /* kicker bits */
return PAIR | hiBotRank[ranks ^ i] | i;
case 5: /* no pair */
return ranks;
}
return 0; /* never reached, but avoids compiler warning */
}
/**
* Returns the bitwise OR of the suit masks comprising <code>hand</code>; Ace is high.
* @param hand bit mask with one bit set for each of 0 to 52 cards.
* @return the bitwise OR of the suit masks comprising <code>hand</code>.
*/
public static int ranksMask(long hand) {
return (((int) hand & 0x1FFF) | (((int) hand >>> 13) & 0x1FFF) | ((int) (hand >>> 26) & 0x1FFF) | (int) (hand >>> 39));
}
/**
* Returns the bitwise OR of the suit masks comprising <code>hand</code>; Ace is low.
* @param hand bit mask with one bit set for each of 0 to 52 cards.
* @return the bitwise OR of the suit masks comprising <code>hand</code>.
*/
public static int ranksMaskLo(long hand) {
return (((((int) hand & 0x1FFF) << 1) + (((int) hand ^ 0x1000) >> 12)) | ((((int) hand >> 12) & 0x3FFE) + (((int) hand ^ (0x1000 << 13)) >> 25))
| (((int) (hand >> 25) & 0x3FFE) + (int) ((hand ^ (0x1000L << 26)) >> 38)) | (((int) (hand >> 38) & 0x3FFE) + (int) ((hand ^ (0x1000L << 39)) >> 51)));
}
/**
* Returns the 8-or-better low value of a 5-card poker hand or {@link #NO_8_LOW}.
* @param hand bit mask with one bit set for each of up to 7 cards.
* @return the 8-or-better low value of <code>hand</code> or {@link #NO_8_LOW}.
*/
public static int hand8LowEval(long hand) {
return loEvalOrNo8Low[
/* rotate each 13-bit suit field left to put Ace in LS bit */
((((int) hand & 0x1FFF) << 1) + (((int) hand ^ 0x1000) >> 12)) | ((((int) hand >> 12) & 0x3FFE) + (((int) hand ^ (0x1000 << 13)) >> 25))
| (((int) (hand >> 25) & 0x3FFE) + (int) ((hand ^ (0x1000L << 26)) >> 38))
| (((int) (hand >> 38) & 0x3FFE) + (int) ((hand ^ (0x1000L << 39)) >> 51))];
}
/**
* Returns the 8-or-better low value of the best hand from hole cards and 3 board cards or {@link #NO_8_LOW}.
* @param holeRanks bit mask of the rank(s) of hole cards (Ace is LS bit).
* @param boardRanks bit mask of the rank(s) of board cards (Ace is LS bit).
* @return the 8-or-better low value of the best hand from hole cards and 3 board cards or {@link #NO_8_LOW}.
* @see #ranksMaskLo
*/
public static int Omaha8LowEval(int holeRanks, int boardRanks) {
return loEvalOrNo8Low[lo3RanksMask[boardRanks & ~holeRanks] | holeRanks];
}
// The following exports of accessors to arrays used by the
// evaluation routines may be uncommented if needed.
// /**
// * Returns the parameter with all bits except its highest-order bit cleared.
// * @param mask an int in the range 0..0x1FC0 (8128).
// * @return the parameter with all bits except its highest-order bit cleared.
// * @throws IndexOutOfBoundsException if mask < 0 || mask > 0x1FC0.
// */
// public static int hiCardMask(int mask)
// {
// return hiRankMask[mask];
// }
//
// /**
// * Returns the number of bits set in mask.
// * @param mask an int in the range 0..0x1FC0 (8128).
// * @return the number of bits set in mask.
// * @throws IndexOutOfBoundsException if mask < 0 || mask > 0x1FC0.
// */
// public static int numberOfRanks(int mask)
// {
// return nbrOfRanks[mask];
// }
//
// /**
// * Returns the rank (2..14) corresponding to the high-order bit set in mask.
// * @param mask an int in the range 0..0x1FC0 (8128).
// * @return the rank (2..14) corresponding to the high-order bit set in mask.
// * @throws IndexOutOfBoundsException if mask < 0 || mask > 0x1FC0.
// */
// public static int rankOfHiCard(int mask)
// {
// return hiBotRank[mask] >> BOT_SHIFT;
// }
/** ********** Initialization ********************** */
private static final int ACE_RANK = 14;
private static final int WHEEL = 0x0000100F; // A5432
// initializer block
static {
int mask, bitCount;
int shiftReg, i;
int value;
for (mask = 1; mask < ARRAY_SIZE; ++mask) {
bitCount = 0;
shiftReg = mask;
for (i = ACE_RANK - 1; i > 0; --i, shiftReg <<= 1)
if ((shiftReg & 0x1000) != 0)
switch (++bitCount) {
case 1:
hiTopRankTWO_PAIR[mask] = TWO_PAIR | ((i + 1) << TOP_SHIFT);
hiBotRank[mask] = (i + 1) << BOT_SHIFT;
hiRankMask[mask] = 0x1000 >> (ACE_RANK - 1 - i);
break;
case 2:
hi2RanksMask[mask] = (shiftReg & 0x03FFF000) >> (ACE_RANK - 1 - i);
break;
case 3:
hi3RanksMask[mask] = (shiftReg & 0x03FFF000) >> (ACE_RANK - 1 - i);
break;
case 5:
hi5RanksMask[mask] = (shiftReg & 0x03FFF000) >> (ACE_RANK - 1 - i);
}
nbrOfRanks[mask] = bitCount;
bitCount = 0;
/* rotate the 13 bits left to get ace into LS bit */
/* we don't need to mask the low 13 bits of the result */
/* as we're going to look only at the low order 8 bits */
shiftReg = (mask << 1) + ((mask ^ 0x1000) >> 12);
value = 0;
for (i = 0; i < 8; ++i, shiftReg >>= 1)
if ((shiftReg & 1) != 0) {
value |= (1 << i); /* undo previous shifts, copy bit */
if (++bitCount == 5) {
lo5RanksMask[mask] = value;
break;
}
if (bitCount == 3)
lo3RanksMask[mask] = value;
}
loEvalOrNo8Low[mask] = (bitCount == 5) ? value : NO_8_LOW;
}
for (mask = 0x1F00/* A..T */; mask >= 0x001F/* 6..2 */; mask >>= 1)
setStraight(mask);
setStraight(WHEEL); /* A,5..2 */
}
private static void setStraight(int ts) {
/* must call with ts from A..T to 5..A in that order */
int es, i, j;
for (i = 0x1000; i > 0; i >>= 1)
for (j = 0x1000; j > 0; j >>= 1) {
es = ts | i | j; /* 5 straight bits plus up to two other bits */
if (straightValue[es] == 0)
if (ts == WHEEL)
straightValue[es] = STRAIGHT | (5 << BOT_SHIFT);
else
straightValue[es] = STRAIGHT | hiBotRank[ts];
}
}
}