Salutations, this is CrazyJugglerDrummer with a tutorial on how to make a poker hand evaluator in java. This program will be able to generate, evaluate, and compare poker hands. A basic understanding of OO design is required (making classes, and having them interact with one another. No inheritance or interfaces here. ) Random, ArrayLists, and static variables and methods are used on occasion, but they won't be a show stopper if you don't know what they are yet. I include quick descriptions in FOR BEGINNERS: notes.

So what do we need in OO poker? We have cards, decks, and hands. Card will be a class that contains a rank and suit variable, deck will be a container for cards, and hand will be where we evaluate and compare the poker hands.

So we have read-only suit and rank variables, a simple constructor, a toString method, and a rankAsString method. The class will be ultra fast as it knows which strings to output just by accessing indexes of static arrays. This array functions as a dictionary, allowing us to convert an int to the appropriate string quickly and easily. We don't even have to use String.ParseInt(). We could've made a switch statement that would find the appropriate string to output based on the suit and rank variables, but it would have to evaluate them every time. Accessing an array at a specific index is much faster. The rankAsString method is a utility method for taking a number and turning it into the appropriate string for the rank. (we'll use it later).

FOR BEGINNERS: NOTES ON STATIC KEYWORD. static methods and variables apply to a class as a whole, not any particular instance like instance methods and variables. We call getRank() on a specific card instance, created with new. But we would call rankAsString on the class, with "Card.rankAsString( 4 );". We have a static array to represent the different names of the suits. This array belongs to the class as a whole, not just one Card, so it can be accessed by the instance methods of each Card, and by the static methods of the class.

NOTE: Now we could've used short or even byte for the rank and suit variables, since there's only 4 possible values. But computers work much faster with 4 byte ints than 2 byte shorts, so what would be lost in extremely tiny bits of memory you'll gain in processing speed. Using ints instead of shorts is best practice in java.

Now we need a deck to hold our cards. I've made another tutorial showing many different ways of making a deck, but in this tutorial I'll just show the most efficient way.

We put the cards in the ArrayList of Cards, then randomly take 100 pairs of cards and switch them, shuffling our deck. To draw from the deck, we just return the first element/card, and then remove that card from the deck. All the randomization is done beforehand in the constructor (prior to any actually dealing of the cards), making our drawFromDeck method much simpler and less processor intensive.

NOTE FOR BEGINNERS: BRIEF TUTORIAL OF ARRAYLIST. ArrayList is an example of a "generic" in java. Generics are sort of like arrays because they store objects of a specific type (type between the <>). But ArrayList is an object, not just an array, so it has neat methods to help us out. We can automatically get its size with size(), remove or add an object with remove() or add(), get and set objects like an array with get() and set(), and maybe most helpful of all, if we need more space, it will just automatically grow for us (actually just copies its items into a bigger array, but it handles all of this so we don't have to). This makes features we commonly need with datastructures, like adding a new element, really easy to use. (with an array, to add a new element to the end we have to make an index variable that starts at zero. Each time we add an object at that index, we increment it to put us at a fresh spot so we can add more objects. Of course, we have to hope the array has enough space. You will see this technique used later.) To use an array list, we have to import java.util.ArrayList at the top of the soure file.

NOTE FOR BEGINNERS: SUMMARY OF RANDOM. Random is a neat little utility class we can use to generate random numbers. To use it, we import java.util.Random, then make a random with Random generator = new Random(). After we do this, we can use our Random instance "generator" to get random ints with nextInt(). If we pass an integer to nextInt(), it will give us a random intereger less than that int and greater than zero. So when we call generator.nextInt( 52 );, it gives us a random number between 0 and 51 that we can use as an index in our arrayList to swap two card, shuffling the deck.

Okay, that wasn't so bad, we've got cards that can describe them selves as a string and a deck that can hold them in an ArrayList and deal them out. But now we actually need to process them in a poker hand. The card holding mechanism will be similar to the deck, the bulk of the code will be in evaluating the hand's level. This is going to be pretty interesting, so bear with me.

We're going to have an array of 5 cards, and an array of 6 ints to represent the value of the hand. The first int will correlate to the type of the hand, 0 will be a high card, 1 a pair, with greater values for higher ranked hands. If we have a tie, the second value will have to determine the winner. How we find the second value will be unique to each type of hand: in a pair the higher pair wins, in a straight the higher top card wins, etc. If those values are equal, we move onto the next determining factor, like the highest card besides the pair, or the low pair of a two pair hand. Some hands will only have 2 determining factors, like a straight. The first value would be a straight's spot in the rank of poker hands (greater than 3 of a kind, less than a flush) and the second value would be the top card in the straight (7, jack, king, etc). For a high card, we'd have 0 as high card is the lowest ranked hand, and the next 5 values would be the ranks of the cards in the hand in descending order.

All righty, now with the dirty work, figuring out the actual value of our poker hand. Let's start with a pair situation. How would we figure out if there was a pair? If we had two cards of the same rank. So how will we implement this? We could cycle through the ranks, seeing if any of the ranks had 2 cards with its value. But then for 3 of a kind we'd have to do the same thing again. How about we make an array of ints starting at 0 with 13 slots (one for each rank), then go through the cards, with each card we increment the appropriate index of the array. Let's see a code representation:

(all the code from this point on is put in the Hand constructor where our comment was)

For simplicity's sake, we've used card ranks starting at 1 for ace instead of 0 for ace. If we used 0 for ace then we would be using 9 for 10, which is just confusing. Since our card ranks run 1-13, the first index of our array ( 0 ) will be empty.

Okay, so now we have our array of the card ranks, now we need to find if there are actually any pairs. We need to know if there is a pair, and if there is, what rank the pair is. So we make an int sameCards to record how many cards are of the same rank, and an int groupRank to hold the rank of the pair. We make an int sameCards because we may have more than 2 cards of the same value, maybe even 3 or 4 (hopefully not 5, unless our processor is a crooked dealer). We could've just made a bool isPair, but we want to know if there is a 3 or 4 of a kind as well.

int sameCards=1; //we know there will be at least one card of any rank
int groupRank=0;
for (int x=13; x>=1; x--) //loop going from 13 to 1
{
if ( ranks[x] > sameCards) //If more cards of rank x than sameCards
{
sameCards=ranks[x]; //set sameCards to that number of cards
groupRank=x; //and record the rank of the cards
}
}

sameCards starts at 1, so if we find a rank of which there are 2 cards, then we record 2 in sameCards and the rank (x) as groupRank. This will work fine if there's a pair, three of a kind, or four of a kind.

But wait a sec, let's say we have a full house. There is a pair of kings, so we record 2 as sameCards and 13 as groupRank. But we keep going through the other ranks, and if there was 3 fives, then we overwrite sameCards with 3 since the number of cards of that rank was more than the current value of sameCards. Similar situation: we have two pair, it records the first pair, but not the other one. We can do hands with one group of cards, but not hands with 2.We need a way to keep track of at least 2 different groups of cards, tracking the number of cards and the rank of each. Think about it a bit before moving on.

NOTE: this is definitely the most intense logic of the program, so if you don't get this at first, don't worry. The rest of the code is all a little easier, and you can come back to this part later.

my solution: all right, we have to keep track of 2 ranks of cards and how many cards are of each rank, so we'll have 2 variables to represent the ranks (largeGroupRank, smallGroupRank) and 2 to represent the number of cards that haave that rank (sameCards, sameCards2).

If ranks[x] is greater than sameCards, we assign the data there, otherwise if its greater than sameCards2, we assign the data there. Now I'm sure you all saw the nested if, so I guess I might as well tell you what its for. Say the if wasn't there: we find a pair of 8's, then we find three 5's. sameCards contains the pair of 8's, and since the three 5's is more than the two 8's, we overwrite sameCards. But the pair we found ealier is just overwritten and not recorded anywhere, when it should have been stuck into sameCards2. So the if statement checks if sameCards was previously assigned to something before overwriting it, and if it was, we take care of that.

Sample run: We find 2 queens, so we record that value in sameCards, since 2 is more than the 1 we initialized sameCards with. Then we find 2 7's, so we record that in the in sameCards2.

We find 3 Jacks, record those in sameCards, then find 2 threes, so we record them in sameCards2.

two 8's, then three 4's. We write the data from the two 8's into sameCards2, then put the data from the three 4's into sameCards1. All is well.

There's a little more to go, but you've made it over the hill; the rest of the code is all downhill from here.

WOO HOO! we've written the code to determine a pair, 2 pair, three of a kind, four of a kind, and a full house. The determinations left to do are whether we have a flush or a straight.

let's do a flush first. How do we find out if all the cards are the same suit? well, if 2 cards are not the same suit, then there's no flush, so let's try this. We hitch a ride on the loop that iterated through the cards recording their ranks:

We check to see if there is one card of 5 consecutive ranks. There's a loop to do straights up to king high, and we add a special separate if for an ace high straight, since the number of aces is contained in ranks[1].

YAY we've covered all the different types of hands! Now we need to start comparing them. We have what we need to determine the type of the hand, but we still need a little more data to fix ties between hands. Say we have a pair, we know that a pair is the second lowest ranked hand. If the hand we're comparing it to is also a pair, then we need to compare the rank of the pair. If the rank of the pair is equal, we need to go to the next highest card, then the next highest card, then the next highest card. The only thing we need now is the next highest cards in order.

int[] orderedRanks = new int[5];
int index=0;
if (ranks[1]==1) //if ace, run this before because ace is highest card
{
orderedRanks[index]=14; //record an ace as 14 instead of one, as its the highest card
index++; //increment position
}
for (int x=13; x>=2; x--)
{
if (ranks[x]==1) //we have already written code to handle the case of their being two cards of the same rank
{
orderedRanks[index]=x;
index++;
}
}

Now we have an array that will holds all the miscellaneous cards that don't mean anything else. (w00t!)

In our hand class, we a private array value, than held 6 ints. We are going to use this to contain the values of the hands. This array will hold all the data necessary to compare two poker hands. I mentioned our process of comparing before: "Say we have a pair, we know that a pair is the second lowest ranked hand. If the hand we're comparing it to is also a pair, then we need to compare the rank of the pair. If the rank of the pair is equal, we need to go to the next highest card, then the next highest card, then the next highest card."

This sets up a list of the things we need to compare. The most important thing is what kind of hand, so that will go in the first position. The rest of the positions will hold the data needed to break a tie between to hands of the same type. Take a look:

And we can add this method to display a summary of the hand: (This is also where we use that static rankAsString method in the Card class to convert an integer in to associate card rank e.g. 11 = "Jack")

Now that that exhaustive class is done, we can write some test code and see this stuff at work. Our first main method will test the randomness of the deck we made (discussed more in the past tutorial).

And there you have it, how to make a poker hand evaluator in java! I hope you've enjoyed this tutorial! Please post any and all comments, questions, and suggestions!

NOTE: This tutorial only covers how to make, evaluate, and compare poker hands (which I think was enough for one tutorial,). It does not actually tell how to make a full playable poker game. Making betting wouldn't be that difficult, but the AI involved for making realistic opponents is beyond this scope. This is a good basis for a poker game however, and if anyone completes the poker game with good, realistic AI and gameplay, they can go ahead and post that as a tutorial on DIC.

Here is the full code for each of the classes in the tutorial (for pasting into a compiler):

Thanks for the tutorial, but I still don't understand the pair method. If it compares a pair of 3 with a pair of king, the program makes the pair of 3 the victor. Please if someone can explain it to me. It'll be grateful.

This is great! I've just been trying to figure out how to evaluate player hands for my own card game and this will be immensely helpful once I figure out how to implement it into my own game structure.

The only thing I will need to change is working with a hand of 7 or 8 cards with groups of 3 and 4 cards in sets or runs as the requirement and working out what card to throw away out of the useless cards. Each set or run has to be minimum of 3 and max 4 cards in length and there has to be 2 groups for a winning hand with the remaining card with a value of 9 or less. I also have wild cards that act as any card to suit any purpose.

Thanks a lot for this mate you really helped me get started! could you take a look at http://www.dreaminco...1&#entry1269281
and see if you could help me with that pls! i really really appriciate it mate!
cheers!

Done this before however the way you implemented this was rather nice (the patched up code )
Cool tutorial! Looked very helpful for beginners to game programming with Java and could excite more people to give it a go

Hi,
I'm using your code at the moment, but slightly adjusted so it works without the package since I'm not to confident about that, and have got it all to work except the hand.java. I've edited it a fair bit so it should just display the hand you receive, however I keep getting the error non-static variable cards cannot be referenced from a static context. The code is below:

Hello. I enjoyed your tutorial, but when I tried using it, I got an error on line 20 "cards.add (new Card(a, ." The error said "Constructor Card in class pokergame.Card cannot be applied to given types; required: short,short
found: int,int reason: actual argument "int" cannot be converted to short by method invocation conversion. Is that just my computer? Maybe I need to od it a different way? please help...

So I've followed this tutorial and I'm having a problem with the output of the Hand.display in the main. Flush is the only thing that is showing up and I've looked over all the code, so I'm not sure what needs to be changed

Are you sure you put the display in the correct place? If you have followed the tutorial to the end, then I expect it to work fine.
If you cant sole your problem, please post the code which you have tried in Java forum and we will see what went wrong.