Skip to main content
GameDev.net gamedev.net
🔒 Locked

Poker/Texas Hold'em

Started by appel Aug 28, 2007 at 10:08 AM 10 replies 3k views
Original Post
appel
appel
Hello people, I'm doing a Texas Hold'em implementation of Poker. I've been studying the game and it's great. Texas Hold'em is just like regular poker, except that only 2 cards are dealt to each player, and then 5 "community" cards that are available to all players to use to make the best 5 card hand, that is they can use any of their 2 cards and any of the 5 cards on the table to create the best 5 card poker hand. My main problems I need to solve are the following: 1. Since the player has 7 cards, I need to figure out what combination of 5 cards out of 7 cards makes up the best possible hand. 2. Compare all best possible hands of each player, to figure out the winner. 3. Tell the player what kind of a hand he has, some don't know the rules and I want to print somewhere on the screen "You have a pair of aces", or "You have a flush, king high.". So I need to create a textual description of the hand. Since Texas Hold'em is a iterative game, that is; you start with 2 cards, then 3 cards are dealt to the table, then 1 more card, and then the final 1 card. So you have to create a textual description of the hand 4 times (when you have 2 cards, 5 cards, 6 cards and then 7 cards.) I hope this makes any sense. Anything will help me: - Articles - Tutorials - Code - Papers
Ravuya
Ravuya
Moving to For Beginners.
yaustar
yaustar
What is your current level of experience in programing?
Which languages do you know?
Steven Yau
[Blog] [Portfolio]
clb
clb
The task you're asking about could be separated to two subparts.

The first is the routine that evaluates a list of cards { 7c, 8c, 9c, Tc, Jc} and gives the best (or all) hand it matches to, for example { Straight Flush, Jack High }

An useful idea with ranking hands in many card games, not just in Poker, is to map all the possible hands to a number in the way that higher the number, the better the hand. So the second subtask is to map the rank of the hand { Straight Flush, Jack High } to its numerical value. The idea here is that you can after that use the normal <, ==, > comparisons to find the relative orderings of two hands. The mapping should be constructed so that it discards all the irrelevant information (e.g. 6th kicker) of the card list and retains only the necessary information which is packed suitably to the bits of an integer.

For example, for a straight flush you only need to store the highest rank of the card that makes that straight flush. For three of a kind, the rank of the threes matter most, then the higher kicker and finally the second kicker.

Try googling for "poker hand evaluator", I think you'll find a plenty of examples.
appel
appel
Thank you clb, I'm sure that will help.

Of course more pointers are welcome :)


This is for my final project for BSc. degree. I already have 6-7 years programming experience, and I've used Java primarily, but also C#, Perl, and PHP a lot. I've also taken courses on many other languages, smalltalk, scheme, prolog, sml etc. And I've been programming games for 2 years now.
JohnBolton
JohnBolton
There is a very good open source poker hand evaluation library called pokersource. It is very fast and very flexible.

I learned a lot about evaluating poker hands by looking at how it is implemented. In fact, it is so much better than what I was doing that I just dumped my code and used it instead. I have to warn you that the code is ugly because it is optimized (and because it is C, and because it is open source).
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
appel
appel
That C code is non-reusable, non-readable, and non-documented. Too bad if it's the "best" out there, means I'm in a bad spot!

Besides, I'm doing my application in Java, trying to understand what one of those C files are doing is impossible within my timeframe :)
Wan
Wan
I haven't done this, but my intuition says the following:

- Start testing from highest possible combination (straight flush) to lowest (one pair, and ultimately high card), because you only need the best possible hand.
- Make an algorithm that can sort the seven cards by rank and/or suit.
- Simply iterate through the cards to find the combinations. I could imagine the following pseudo-code for finding a straight (testing for other combinations would not differ that much):
int cards[7] = {2, 11, 8, 6, 8, 10, 5} // numbers representing rankint count = 1 // number of consecutive cardssort_cards_by_rank(&cards, ASC)for (int i = 1; i < 7; i++){  if ((cards - cards[i - 1]) != 1)  {    if (i > 3)      break; // no straight possible (need at least five cards)    else      count = 1; // reset counter, but keep looping  }  else  {    count++;  }}if (count >= 5)  print("straight")else  print("no straight")
You'll probably want to keep track of last card of the straight to compare it against someone else's straight, and it is would be wise to give a value to the result for easy comparison: say 1000 + total of ranks in the straight. In that case a flush could be represented using: 2000 + total of ranks, thus always resulting in a larger number than a straight. And so on..
appel
appel
Yes, I thought of the same.

There are basically 10 types of hands I can have:

1. Royal Flush
2. Straight Flush
3. Four of a kind
4. Full House
5. Flush
6. Straight
7. Three of a Kind
8. Two Pairs
9. Pair
10. High Card


I could start by checking for a Royal Flush, then work my way downwards. This is probably the EASY part.


Tricky part:

Figuring out what 5-card-hand out of those 7 cards are the best.

(nCr) 7C5 = 21 possible combinations (if I learned anything at all in statistics math class)

I would probably want to loop through each of those possible combinations and assign some score/value to it, in order to get the highest ranked hand the player can form.


I would like to assign some meaningful score to each hand, not just I "invented" out of thin air. I'm thinking this has been done million times before.
Deuce81
Deuce81
I would just rank the 10 types of hands and run through them, checking to see if any combination of the cards qualify for the particular hand. Once that is done, you have your best hand available. I don't really get what you mean by having a meaningful score for each hand. Could you elaborate?
clb
clb
WanMaster's algorithm for straights is unfortunately a bit too pseudo. It has to be run twice, for Ace low straight (setting A=1) and for Ace high straight (setting A=14). Also, it doesn't detect a straight for the case { 1, 2, 3, 3, 4, 5, 6 }, since the redundant 3 breaks the progression and the counter is erroneously reset.

But the rules of thumb WanMaster mentioned are good, sorting the list first eases up checking for straights a lot, although with binary arithmetic you could do a slightly faster check. Unless you're writing an AI that wants to iterate over hundreds of thousands of hands quickly, you probably don't want to concern about this.

"1. Since the player has 7 cards, I need to figure out what combination of 5 cards out of 7 cards makes up the best possible hand."

Unless you want to actually tell the player, for example by highlighting, the cards that make up the winning hand, you don't really need to answer this problem.
(Although after you have all the checks in your hand evaluator in place, getting the cards that make up that hand is quite easy.)

Tackling this problem as WanMaster said, by looking at the possible hand types in descending order, Straight Flush first, then Four of a kind, etc. is a practical approach. Sort the list, check for a five-card progression (the above algorithm works fine if you fix the few flaws there), to get a straight. Augment that check so that it also matches the suit to check for straight flush. I recommend a convention to always represent A=14, for example. So you don't have to have so many edge cases.

The rest of the stuff is quite easy. Just create an array of counts of the occurrences of different ranks. This can be done by iterating once over the card list and increment the correct position in the array.
After that, by looping over the array it's simple to see if there's a four of a kind, threes, a full house or anything else.
Similarly, count the number of occurrences of all suits to check for a flush. (for optimization might want to do this before checking for a straight flush)

Then have the algorithm output the result. You could use something like this:
struct HandRank
{
HandType type; // enum, higher numerical value=better
Rank ranks[5]; // integer on the range [2,14]
};

You use the values in ranks array to give the additional details, for example:
When type=StraightFlush, ranks[0]=The highest card, ranks[1 to 4]=0 since the straight flush is uniquely determined by the highest card.
type=Flush, ranks[n]=Nth highest card in the hand of the color that matches the flush.
type=Full house, ranks[0]=the rank of the three of a kind, ranks[1]=the rank of the pair, ranks[2 to 4]=0.

For each hand type, think about "what matters" for that type of hand, and store into ranks[0] the rank that is used for comparison first, ranks[1] the rank that is compared to if ranks[0] are equal for two given hands, etc.

"2. Compare all best possible hands of each player, to figure out the winner."

Now, in Java, you could implement a method that compares two HandRank structures A and B with each other, by first checking A.type vs B.type. If there's a tie, check A.ranks[0] vs B.ranks[0]. If there's a tie still, then A.ranks[1] vs B.ranks[1] and so on. If all give a tie, the hands are equal.

For a more efficient comparison. I pack the data in the HandRank structure into a single 32-bit integer, something like this:

[xxxxxxxx TTTT0000 11112222 33334444]
T=the hand rank type: 8=straight flush, 0=high card
0=ranks[0]
..
4=ranks[4]

That works nicely, because ranks 2<=x<=14 nicely fit into four bits. This allows me to do the conventional <, <=, ==, !=, >=, > on any two hand ranks.

"3. Tell the player what kind of a hand he has"
Well, with the HandRank structure, it's really simple, for example, what would this say?
type = TwoPair, ranks[0]=9, ranks[1]=4, ranks[2]=13, ranks[3 and 4]=0.

This is all really simple, perhaps only the straight flush & straight checks have a few edge cases. It starts to get interesting only after you add a few jokers in your deck. ;)
appel
appel
Great help clb, thanks. Looks like this is gonna solve my problem :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.