19
\$\begingroup\$

I have been making a Texas Hold'Em game as a part of an assessment, and I have been mulling over how to examine the 7 available cards and determine if hands exist.

The only possible method I can think of is to sort the cards numerically, then examine each possible group of 5 cards and check if they match a list of every single possible hand. That would take a long time snd would only be feasible for determining pairs, as the suit is irrelevant.

The cards are each strings, made up of a number/a/j/q/k, and a suit (char)3 (that makes a little spades symbol).

Does anyone have any suggestions, formulas, or links I could use to help create a hand-analysing system?

Don't worry about ranking hands against each other yet, that's a different kettle of fish.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Just pointing it out but the vector tag in its context is about linear algebra. Not the container. \$\endgroup\$
    – Sidar
    Commented Feb 13, 2013 at 18:58
  • \$\begingroup\$ @Sidar Feel free to edit the tags in the future if you believe they don't fit. If you hover over the tags and "Edit tags" option pops up (at least for me?), and you can edit just the tags without editing the question. \$\endgroup\$
    – House
    Commented Feb 13, 2013 at 19:14
  • \$\begingroup\$ @Byte56 I have this weird habit of thinking im not sure if i'm right so I do it passively trough a comment...That's why I didn't edit the post. Perhaps I missed something in the post, so I was waiting for his response. \$\endgroup\$
    – Sidar
    Commented Feb 13, 2013 at 19:44
  • \$\begingroup\$ There's also a nice article here that appeared in Game Developer a few years ago: cowboyprogramming.com/2007/01/04/programming-poker-ai \$\endgroup\$
    – celion
    Commented Feb 14, 2013 at 0:17
  • 1
    \$\begingroup\$ I did a implementation in java for fun a while back you can find it here: codereview.stackexchange.com/questions/10973/…. If you look in PokerHand.java you will find methods for testing each type of hand (eg isFullHouse). They only work if the cards are sorted first. \$\endgroup\$
    – bughi
    Commented Feb 16, 2013 at 19:17

8 Answers 8

20
\$\begingroup\$

I think you can find the majority of poker hands by simply making a couple of tables of how many cards in the hand there are of each rank and suit.

In other words, create an array mapping card ranks (numbers and A/J/Q/K) to the count of cards of that rank in your hand. If the player has a pair or three-of-a-kind, there will be an element in this array equal to 2 or 3, etc. They have a full house if there's one element that's 2 and another that's 3, and a straight if there are five consecutive elements equal to 1 in this array.

Likewise you can make a similar array of the count of cards of each suit, and use it to detect flushes.

Once you've detected the presence of a specific hand it's pretty easy to then go back and find the specific cards in the hand, for highlighting them in the UI or whatever you need to do.

In pseudocode:

int countByRank[13] = { 0 };        // Initialize counter to zero for each rank
for (cards in hand)
    countByRank[card.rank] += 1;    // Increment counter for this card's rank
if (countByRank.find(2))
    // There's a pair
else if (countByRank.find(3))
    // There's a three-of-a-kind
// etc...
\$\endgroup\$
0
18
\$\begingroup\$

It's a little tricky because there's so many combinations. Luckily you have a processor that can check a great number of combinations in a very short time.

You'll need a few different strategies, for detecting different types of hands. Luckily, a few of the different types can overlap strategies. I would search through, in order by rank of the hand.

  1. Straight flush
  2. Four of a kind
  3. Full house
  4. Flush
  5. Straight
  6. Three of a kind
  7. Two pair
  8. One pair
  9. High card

2, 3, 6, 7, 8 are all simple counting. Using a list of cards Ace to King, simply place the number of each value in the list, incrementing for each additional card found. Then check the list for 4s, if there's no 4s, you don't have a 4 of a kind. Check it for 3s, if there's no 3s, you don't have a 3 of a kind. If you have a 3, check for a 2 (indicating full house). And so on...

For 1, 5 you can use the same list and look for sequences where all cards have one or more entries in the list for a sequence of 5 cards. If they also have the same suit, it's a straight flush.

4 can have the same list setup but this time you're counting the suit. Look for numbers of 5 or higher.

Finally, 9, you have the highest card, which should be a simple matter of looking at the last highest value from one of your lists above.

You can break out once you've found a match if you search in order. Though it would be trivial to continue the search and find all the matches if you want to provide all that information to the user.


Essentially, you're filling buckets. Then checking the buckets for combinations. To illustrate:

enter image description here

Starting with an array, with a bucket for each card, iterate through the cards and count the instance of each card. Then you can easily iterate the array and check for certain combinations. In this example, it's clear that there's a 4 of a kind because one of the buckets has 4 items in it.

\$\endgroup\$
0
6
\$\begingroup\$

I bumped into this algorithm once. It multiplies prime numbers to determine hands and is a very interesting reading. Cactus Kev's Poker Hand Evaluator

\$\endgroup\$
4
  • 1
    \$\begingroup\$ That one is interesting, but I'm not sure you read all of it. That algorithm is for 5 cards. You may have found in in a Google search related to 7 cards, as the author states they have an algorithm for 7 cards, but aren't sharing it. See the grey text near the top of the page. So I'm not sure how useful that algorithm is for a 7 card set. \$\endgroup\$
    – House
    Commented Feb 13, 2013 at 21:32
  • 1
    \$\begingroup\$ Since there are only 21 different 5 card hands that can be made from a 7 card hand one option is to use a 5 card evaluator on each one, and pick the best. \$\endgroup\$
    – Adam
    Commented Feb 13, 2013 at 22:15
  • \$\begingroup\$ @Byte56 You're right, I remember I used it to 7 card but had to determine the best 5 card beforehand, which kinda of undermined the efficience. \$\endgroup\$
    – petervaz
    Commented Feb 14, 2013 at 3:03
  • \$\begingroup\$ The link on this answer has since rotted, and the domain picked up by a spammer. I've redirected the link to an archive of the original page, but to make this answer more robust it would be ideal to edit the answer to include a summary of the algorithm being proposed within the body of the answer itself. \$\endgroup\$
    – DMGregory
    Commented Nov 26, 2018 at 13:17
2
\$\begingroup\$

To supplement the excellent answers this question has already gotten, I thought it would be helpful to offer one of the most straightforward ways of comparing hands once the basic classification technique in place. First of all, you'll want to tag hands with their class, as numerous answers have suggested - most of your comparisons of 'is hand X better than hand Y?' can then be done just by comparing the two hands' classes and seeing which class is better. For the rest, you'll actually need to compare on a card-by-card basis, and it turns out that a little bit more work in classification will make this easier.

As the baseline case, consider the situation where both hands are 'high card' hands; in this case, you'd compare the two highest cards first, then (if they matched) the next two cards, etc. If you assume that each input hand is sorted from highest to lowest card, this approach leads to code that looks like this:

int CompareHandsOfSameClass(Hand h1, Hand h2) {
  for ( int i = 0; i < 5; i++ ) {
    if ( h1[i].rank > h2[i].rank ) {
      return -1;
    } else if ( h1[i].rank < h2[i].rank ) {
      return 1;
    }
  }
  return 0;
}

Now, the good news: it turns out that this lexicographical ordering, suitably tweaked, works for comparing two hands in any of the classes, as long as their class is the same. For instance, since the way of comparing pairs is to compare the pairs first, then the other three cards, you can sort your hand to put the pair first (or even one card of the pair first!) and run this same comparison. (So, for instance, a hand like A9772 would be stored as either 77A92 or, better yet, 7A927; the hand A9972 would be stored as 9A729, and comparing with the above code you'd start by pitting 7 against 9 and find that A9972 won). A hand of two pair would be stored with the higher of the two pairs first, then the lower, then the 'kicker' (so, e.g., A9977 would store as 97A97); three of a kind would be stored with one card of the three first, then the kickers, then the other cards (e.g., A7772 would be 7A277); a full house would be stored with one of its three and then one of its two (e.g., 99777 would be stored as 79779); and straights and flushes can both be stored in 'direct lexicographical' order since they're both compared just like high-card hands are. This leads to a straightforward outer comparator function that works for all classes of hands with the already-given function:

// Compare two hands, returning -1/0/+1 as hand 1 is less than, equal to,
// or greater than hand 2. Note that this function assumes the hands have
// already been classified and sorted!
int CompareHands(Hand h1, Hand h2) {
  if ( h1.handClass > h2.handClass ) {
    return -1;
  } else if ( h1.handClass < h2.handClass ) {
    return 1;
  } else {
    return CompareHandsOfSameClass(h1, h2);
  }
}

Hopefully this will be of some help!

\$\endgroup\$
1
\$\begingroup\$

There are some parallelisations possible using suitable card representations and bit-twiddling. For example, this Java code evaluates 7-card hards returning an integer which can be used for comparing two hands. It could be adapted to report the type of the hand in a more user-friendly way. The core ideas come from Cactus Kev's page referenced in an earlier answer.

If you're only interested in possible implementations for naming the hand in various languages rather than efficiency and code clarity, you could also look at the Name the poker hand challenge on codegolf.SE.

\$\endgroup\$
1
\$\begingroup\$

First, you need to know the rank and suit of all the cards; trivial but necessary.

Then, spin through these 7 cards and create two histograms; one by rank (using an array with 13 indexes, all initialized to zero and incremented by 1 if and when a card in the hand with that rank is found) and one by suit (using an array of four elements constructed similarly as for rank). These are linear operations and you can do both operations for each card for only one set of traversals.

You can then determine whether any of the following hands exist by simply examining each histogram for buckets matching the criteria, and/or a simple follow-up test:

  • Pair: Does exactly one rank bucket have a value of exactly 2, with no other bucket having a value above 1 and no flush?
  • Two Pair: Do two or more rank buckets have a value of exactly 2, with no bucket having more than 2 and no flush? (obviously three pair is not a hand, but it's a possibility given seven cards; the strongest two pair is the player's hand)
  • TOAK: Does exactly one bucket have a value of exactly 3, with no other bucket having a value greater than 1 and no flush?
  • Straight: Do five consecutive rank buckets have a value of 1 or more with no flush? (Don't forget that Aces are both high and low; you could use a rank histogram of 14 elements and count Aces in two buckets if you'd like)
  • Flush: Does any suit bucket have 5 or more cards? (if so, scan the hand for cards of that suit and choose the top 5)
  • Full House: Does any one rank bucket have a value of 3 and any other bucket have a value of 2 (with 7 cards, a flush is impossible with a full house unless you're playing with a Pinochle deck)
  • Four of a Kind: Does any one rank have a value of 4? (no other combination should be possible)
  • Straight Flush: Is there both a straight and a flush indicated by the histograms? If so, is there at least one card in the indicated flush suit with a rank matching each rank of the indicated straight? (this is probably the most computationally expensive, but it should be simple to count how many consecutive ranks there are, and you should only have to scan the hand once for 5 concecutive ranks, twice for 6 and three times for 7)

You can, quite naturally, combine several of these checks:

  • Is there a flush?
  • Is there a straight?
    • If there are both, is it a straight flush?
    • If it's a straight flush, does it have both an Ace and a King?
  • Is there a four-of-a-kind?
  • How many three-of-a-kinds are there? (Two, it's a full house. One, check pairs)
  • How many pairs are there? (With two or more, it's two pair. With one, if there's also a three it's a full house, otherwise it's a pair)
  • None of the above (high card).

Basically, if the answers to these yield any hand, set the resulting "hand strength" value to the strength of the hand found, if the value is not already higher. For instance, if you have a full house, strength 7 of 9, then you also have a three of a kind, strength 4, and a pair, strength 2.

There are a few shortcuts and fast outs, but overall it's not really that expensive to just run all the checks.

\$\endgroup\$
0
\$\begingroup\$

You can do poker hands relatively easily with a simple iterative approach.

For each card, check if there is one or two or three others with the same face to check for pair or three/four of a kind.

Full houses are similar. Or if you find both a pair and three of a kind that aren't the same face, flag a full house as found.

For flushs, check each suit to see if there are five of the same suit.

Checking straight is easy, even if unsorted. For each card, check if there is one higher, and repeat until five consecutive cards are found or not.

Royal flushes and straight flushes can be found similarly to straights. Royal flushes have some extra conditions in that lower valued cards can be ignored.

Yes, this approach is inefficient, but for most poker games, that is irrelevant. You're checking a tiny handful of players every half minute or so, not checking thousands of hands per second.

Better methods exist but may take more time to code, and you likely have more important things to spend time/money on that'll make for a better game from players' perspective besides cleverness and efficiency of an algorithm.

\$\endgroup\$
0
\$\begingroup\$

a simple way to find pairs, double pairs, toaks, full houses, pokers etc is the following:

compare each card with each other in a nested loop like this one:

int matches=0;
for (int i=0;i<5;i++)
   for (int j=0;j<5;j++)
      if (i!=j && cardvalue(card[j])==cardvalue(card[i])) matches++;

matches will hold the following:
2 for a pair
4 for two pairs
6 for toak
8 for a fullhouse
12 for a poker

to speed optimise this: it's not needed to run the j-loop up to 5, it can be run to i-1. the comparison "i!=j" can then be removed, the values for match are then halved (1=pair, 2=2pair etc.)

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .