Public Domain Java Poker Hand Evaluator

IMPORTANT NOTE! The following code currently has a bug in it when comparing two two-pair hands (check the comments for the specific example of where this is an issue).  I have implemented a possible fix but need to do some math to make sure that the mapping of values to hands is correct.  If you would like to see my code revision in progress it is posted here.  Thanks in advance for any feedback on the effectiveness of my fix or any other possible fixes to this algorithm! IMPORTANT NOTE! So I was recently commissioned to do a simple function which could apply a value number to any 5+ hand of poker which could then be dirrectly compared with other hand scores to determing the best or winning hand.  The first thing I did was see if I could simply find a java function already written for this purpose.  However, it was difficult to find a single function that could produce the result the commissioner wanted.  Most were recursive functions of several different evaluation functions.  I did however find a function similar to what I needed at a site apltly named javaboutique.internet.com.  The specific project I found was here, and though the evaluation function did not return a value but rather manipulated payouts, I knew I could manipulate it to do my bidding.  Below is the actual function I wrote and since Kevin Kessler, the origional author, did not seem to put a licence along with his code, I am not going to try to assume any viral licences and just release this to the public domain, meaning you can use this regardless if you plan on making money with it or not.  I'm just fairly proud to have done something that seems to work.  If you see a bug, PLEASE post a comment and I'll correct the issue.  If you use it please consider showing me some love by donating to my paypal account :D!  Either way, here it is, it's in the public domain, and I hope to hear back from people using it soon!
import java.util.Arrays;

/**
 * @author David Cheeseman DePauw '08 - University of Colorado at Boulder '11-'12
 *
 *         Simple poker hand evaluator.
 *
 *         This static function will take a simple representation of a hand of
 *         poker and give it a score based on the best 5 card subset which will
 *         be comparable to other hands in terms of their rank.
 *
 *         Notes: I've run about a hundred hands through this thing with no sign
 *         of it being wrong so far. I'm confident it will work for your
 *         purposes but you may want to run your own tests to double check. My
 *         email is Nuvious@gmail.com if you find any bugs or errors.
 *
 *         To use either copy and paste the function into your class or simply
 *         copy this file to the same package directory and run
 *         PokerHandEval.scoreHand(hand). Being a static function it can be
 *         called without creating an instance of the class.
 */
public class PokerHandEval {

	/**
	 * @param hand
	 *            A 2 dimensional array. Index 0 of each hand is the value of
	 *            the card and index 1 is the suit.
	 * @return A long-value representing the score of the hand.
	 */
	public static long scoreHand(int[][] hand) {
		int handSize = 5;

		/*
		 * If the hand is greater than the max hand size, re-partition the cards
		 * into subset hands with one less card. Then return the highest scoring
		 * subset. This will work recursively down to the maxHandSize. Due to
		 * how it branches throughout the recursion it result in an O(nlog(n))
		 * time. All loops and functions within the scoreHand() function run in
		 * O(n) time or O(nlog(n)) time and therefore will not add to the
		 * overall runtime of the scoreHand() function.
		 */

		if (hand.length > handSize) {
			// the hand is too big, partition it into smaller hands and return
			// the
			long maxScore = 0;
			long score = 0;
			for (int i = 0; i < hand.length; i++) {

				// create subset and get its score.
				int[][] subHand = new int[hand.length - 1][2];
				System.arraycopy(hand, 0, subHand, 0, i);
				System.arraycopy(hand, i + 1, subHand, i, hand.length - i - 1);

				score = scoreHand(subHand);

				// update score if needed
				if (score > maxScore) {
					maxScore = score;
				}
			}

			return maxScore;
		} else {
			// hand is the proper size
			long score, highCardHash, straightHash;
			int twoVal, threeVal;
			boolean flush, pair, two, three, straight, four;

			int[] suit = new int[hand.length];
			int[] value = new int[hand.length];

			flush = two = pair = three = straight = four = false;
			score = highCardHash = straightHash = threeVal = twoVal = 0;

			// Break cards into values and suits.
			for (int i = 0; i < hand.length; i++) {
				suit[i] = hand[i][1];
				value[i] = hand[i][0];
			}

			// Sort the values so they can be more easily analyzed.
			// If necessary, replace with custom sorting algorithm.
			Arrays.sort(value);

			/*
			 * Compute high card hash. This number can be added to any score
			 * accept the straight to determine high card rank.
			 */
			if (value[0] == 1) {
				// ace high
				for (int i = 1; i < value.length; i++) {
					highCardHash += Math.pow(14.0, (i - 1)) * value[i];
				}
				highCardHash += Math.pow(14.0, 4) * 14;
			} else {
				// non-ace-high
				for (int i = 0; i < value.length; i++) {
					highCardHash += Math.pow(14.0, i) * value[i];
				}
			}

			// Check for Flush
			if ((suit[0] == suit[1]) && (suit[0] == suit[2])
					&& (suit[0] == suit[3]) && (suit[0] == suit[4])) {
				flush = true;
			}

			// Check for straight
			straight = true;
			if (value[0] == 1 && value[1] == 10) {
				// check for possible ace high striaght
				for (int i = 2; i < value.length; i++) {
					if (value[i] != value[i - 1] + 1) {
						straight = false;
						break;
					}
				}

				// it was an ace high straight, therefore the straightHash is
				// equivelant to the highCardHash
				straightHash = highCardHash;
			} else {
				// check for any other straight
				for (int i = 1; i < value.length; i++) {
					if (value[i] != value[i - 1] + 1) {
						straight = false;
						break;
					}
				}

				// it was a regular non-ace-high-straight, therefore compute a
				// special hash which is similar to the high card hash but with
				// the ace value being 1 instead of 14.
				for (int i = 0; i < value.length; i++) {
					straightHash += Math.pow(14.0, i) * value[i];
				}
			}

			// Check for 4 of a kind
			if (((value[0] == value[1]) && (value[0] == value[2]) && (value[0] == value[3]))
					|| ((value[1] == value[2]) && (value[1] == value[3]) && (value[1] == value[4]))) {
				four = true;
			}

			if (!four) {
				// Check for 3 of a kind
				for (int i = 2; i < value.length; i++) {
					if ((value[i - 2] == value[i - 1])
							&& (value[i - 1] == value[i])) {
						three = true;
						if (value[i] == 1) {
							threeVal = 14;
						} else {
							threeVal = value[i];
						}
						break;
					}
				}

				// Check for pairs
				for (int i = 1; i < value.length; i++) {
					if (value[i - 1] == value[i]) {
						if (pair) {
							if (three && threeVal != value[i]) {
								two = true;
								if (value[i] > twoVal) {
									if (value[i] == 1) {
										twoVal = 14;
									} else {
										twoVal = value[i];
									}
								}
							} else if (!three) {
								two = true;
								if (value[i] > twoVal) {
									if (value[i] == 1) {
										twoVal = 14;
									} else {
										twoVal = value[i];
									}
								}
							}
						} else {
							if (three && threeVal != value[i]) {
								if (value[i] == 1) {
									twoVal = 14;
								} else {
									twoVal = value[i];
								}
								pair = true;
							} else if (!three) {
								if (value[i] == 1) {
									twoVal = 14;
								} else {
									twoVal = value[i];
								}
								pair = true;
							}
						}
					}
				}
			}

			// Compile Score, adding high card where appropriate
			if (straight && flush) {
				// straight flush
				score = (long) Math.pow(15.0, 15.0) + straightHash;
			} else if (four) {
				// four of a kind
				score = (long) Math.pow(15.0, 14.0) + highCardHash;
			} else if (three && pair) {
				// full house
				score = (long) Math.pow(15.0, 13.0) * threeVal + twoVal;
			} else if (flush) {
				// flush
				score = (long) Math.pow(15.0, 12.0) + highCardHash;
			} else if (straight) {
				// straight
				score = (long) Math.pow(15.0, 11.0) + straightHash;
			} else if (three) {
				// three of a kind
				score = (long) Math.pow(15.0, 10.0) * threeVal + highCardHash;
			} else if (two && pair) {
				// two pair
				score = (long) Math.pow(15.0, 9.0) * twoVal + highCardHash;
			} else if (pair) {
				// one pair
				score = (long) Math.pow(15.0, 8.0) * twoVal + highCardHash;
			} else {
				// high card
				score = highCardHash;
			}

			return score;
		}
	}
}
Download: PokerHandEval.java Simple Usage Notes:
  1. The function is scoreHand(int[][] hand) and takes a 2-dimensional array where the first index corresponds to a single card in the hand and the second indicies 0 and 1 correspond to the values and suit respectively.  The number of the suit merely has to be unique, but I reccomend the commissioner's own convention of using 1-4 for Spades, Diamonds, Clubs, and Hearts.
  2. Simply run PokerHandEval.scoreHand(hand) statically or copy the function into your class.  It would be very easy to turn this into a comparator to use in a list sorting operation (I may post this example sometime in the future myself).  A hand which is greater will return a larger score, we're not playing golf here.
27 Jan01:40

You are correct indeed. My

By David Cheeseman (not verified)

You are correct indeed. My algorithm wasn't even considering a lower pair when computing a score for a 2 pair hand. I've modified it a bit but need to check the mapping of hands again. It is difficult to map a hand to a long value without either overflowing the variable or overlapping different ranges of values mapped to unique hands. I don't have much time to devote to this (due to classes), but will try to test and update the code soon.

27 Jan01:15

I noticed a bug in this

By Ben (not verified)

I noticed a bug in this program for two pair values.
compare the below given arrays.

int [][] test1= {{11,3},{8,1},{11,2},{12,4},{8,3}} ;
int [][] test2={{11,3},{8,1},{11,2},{9,4},{9,3}} ;

regards

Ben

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
Halt! Humans only!
Image CAPTCHA
Enter the characters (without spaces) shown in the image.