To evaluate Poker hands probably the most common thing you're going to do is loop through the data structure (could be an array, list, whatever) and compare the cards to each other. For example here's some pseudo-Java to compare a straight:
for (int i = 1; i < /* length of hand */; i++) {
if (/* rank for card i is not 1 greater
than rank for card i - 1 */) {
/* not a straight */
}
}
Note that the above assumes the structure is sorted which I'll get to. Also since Poker hands are so different there's not really a 'best way' to do all of them. You will have to write a routine for each one. So I would recommend you come up with some abstraction that helps you out. What I would do is use Enum. Here's a basic example:
enum PokerHand {
STRAIGHT {
@Override
boolean matches(List<Card> hand) {
for (int i = 1; i < hand.size(); i++) {
if (
card.get(i).getRank() !=
card.get(i - 1).getRank() + 1
) {
return false;
}
}
return true;
}
},
FOUR_OF_A_KIND {
@Override
boolean matches(List<Card> hand) {
int[] rankCount = new int[14];
/* count up the ranks in the hand */
for (Card card : hand) {
rankCount[card.getRank()]++;
}
boolean foundHasOne = false;
boolean foundHasFour = false;
/* now evaluate exclusively
* there must be only a 1 count and a 4 count
*/
for (int i = 1; i < rankCount.length; i++) {
if (rankCount[i] == 1) {
if (!foundHasOne) {
foundHasOne = true;
} else {
return false;
}
} else if (rankCount[i] == 4) {
if (!foundHasFour) {
foundHasFour = true;
} else {
return false;
}
} else if (rankCount[i] != 0) {
return false;
}
}
return true;
}
},
ROYAL_FLUSH {
final int[] rfRanks = {
1, 10, 11, 12, 13
};
@Override
boolean matches(List<Card> hand) {
for (int i = 0; i < rfRanks.length; i++) {
if (rfRanks[i] != hand.get(i).getRank())
return false;
}
return true;
}
};
abstract boolean matches(List<Card> hand);
}
Of course the above does not cover all Poker hands, just a few examples. Also I don't play Poker so those could be a little wrong but the point is to show some evaluation examples.
As I said before this becomes much simpler if you sort your lists ahead of time. java.util.Collections
and java.util.Arrays
have utility methods for this so it is fairly trivial. Just make sure to make a copy before sorting if you don't want the sort to persist after you check the hands.
/* make a shallow copy */
List<Card> sortedHand = new ArrayList<Card>(playerHand);
/* sort based on rank */
Collections.sort(sortedHand, new Comparator<Card>() {
@Override
public int compare(Card card1, Card card2) {
int rank1 = card1.getRank();
int rank2 = card2.getRank();
if (rank1 > rank2) {
return 1;
if (rank1 < rank2)
return -1;
return 0;
}
});
See Comparator#compare for a description of how that works but that's basically it to sort.
Using an enum or something like it then makes the evaluation fairly trivial logically.
Now what I recommend is to make a method for the evaluation because then you can conveniently return the constant for what the hand is.
static PokerHand evaluateHand(List<Card> hand) {
for (PokerHand potential : PokerHand.values()) {
if (potential.matches(hand))
return potential;
}
/* imply there is not a matching hand */
return null;
}
So after you make your copy of the hand and have sorted it you can call to evaluate it:
PokerHand evaluated = evaluateHand(sortedHand);
if (evaluated != null) {
/* it's a recognized hand */
}
You don't have to make a method, you could do something like the following:
PokerHand evaluated = null;
for (PokerHand potential : PokerHand.values()) {
if (potential.matches(sortedHand)) {
evaluated = potential;
break;
}
}
if (evaluated != null) {
/* it's a recognized hand */
}
But using helper methods helps organize your code.
I hope that helps. If you also need to score the hands to decide if there is a winner, just add another method to the enum that returns a score. Then see which one is the biggest.