Poker Evaluation
March 26, 2000
by Pat McClellan
Dear Handyman,
I've been having a go at making a Poker (like) game using your Keeping a poker face article posted way back as a guide. I have the players' cards dealt out but now I need a way to evaluate who wins.
Gavin
Dear Gavin,
There are dozens of poker games, with variations in the sequence of the deal, whether cards are thrown away or passed, and whether wild cards are calculated into the evaluation of a hand. There are many more variations than I can handle here, so I'm just going to limit this article to a straight evaluation of a 5 card hand with no wild cards. I'm assuming that you know the order of scoring. I'll leave it to you to handle the dealing and discarding before the evaluation. I'm going to leave all of the betting functionality to you. Evaluating the hands is going to be complicated enough for a single article!
It's common to see single player "video poker" games, which are easily created in Shockwave. In fact, Gary Rosenzweig gives you step-by-step instructions for Video Poker in his new book, Advanced Lingo for Games. (Don't be thrown off by the title, it's not too advanced for anybody to understand and learn from.) In a single player game, you simply have to assess the hand and payoff based on the odds. You don't have to compare more than one hand, so it's not really suitable for multiplayer situations.
I'm going to set my demo up so that it assesses an individual player's score, then compares it to another player's score to determine the winner. In the case of a tie -- for example, both players have a pair of 8s, then we'll do as in real life and see who has the highest card other than the 8s. And if they both have the same high card, we'll look at the next highest, etc. Unlike the typical single player version where only a high pair constitutes a win, there will be a winner every time -- unless neither player has anything, and they happen to have the exact same values of cards in their hand (unlikely).
D7 download for Mac or Windows.
In that previous article, I used card names that were two characters: the second char was the suit (h, c, d, and s for hearts, clubs, diamonds, and spades, respectively); the first char was the value, and I used letters for 10, Jack, Queen, King and Ace. Unfortunately, we'll want to change this naming convention for our purposes. It's going to be important to be able to run simple math evaluations on the card values. So let's change the names of the face cards to integers, jack=11, queen=12, king=13, and ace=14. So now, for example, our card names for the hearts will be:
2:h, 3:h, 4:h, 5:h, 6:h, 7:h, 8:h, 9:h, 10:h, 11:h, 12:h, 13:h, 14:h
With this new naming convention, if we set the itemDelimiter = ":", we can refer to the value of a card as item 1 of its name, and the suit is item 2 of the name. (You'll want to make some changes to the deal card handlers from the previous article to accomodate the name change -- as I have in the demo.)
When a hand is dealt, a global variable will be set to a list of the cards in the hand. In this demo, gHand1 and gHand2 are the names of the globals. Typical values would be something like this:
gHand1 = ["8:H", "6:C", "12:C", "8:S", "11:C"]
gHand2 = ["3:H", "13:S", "7:S", "8:C", "4:D"]
When it comes time to evaluate the hands, each one is put through the pokerEval script. This script breaks down the hand into a list of its values (valList) and a list of its suits (suitList). (If you haven't downloaded the demo yet, now would be good time so you can follow along in the Lingo as I describe the process.)
The valList is passed to a handler called checkForMatches -- which checks for a single pair (#pair), two pair (#twoPair), 3-of-a-kind (#trips), and 4-of-a-kind (#quad). Those symbol names will be used to build a property list which shows the "score" of each hand. You can see that property list for the winning hand displayed in the demo above.
Let's look at that process for gHand1:
gHand1 = ["8:H", "6:C", "12:C", "8:S", "11:C"]
The sorted valList would be [6,8,8,11,12]. Because the checkForMatches handler will need to pull values out of the list -- but we'll need valList intact later -- we'll create a duplicate of the list to pass to the checkForMatches handler. checkForMatches accepts the "passList" and starts the process of looking for matches. It grabs the first value, 6, removes it from the passList and places it in a new list called currentList. Then it checks to see if there are any more entries with the same value in passList. If so, it continues to transfer them from the passList to the currentList until there are no more matches. Then, it counts how many items there are in currentList. If there are 2, then it's a #pair, three is a #trip, etc. The result is posted to the score list, along with the actual value of the match. So a pair of eights would show up like this:
score = [#pair:8]
Remember, the valList is included in the score because if the other player also has a pair of eights, we'll need to see who has the high card.
The checkForMatches handler keeps looking through the list until all the cards have been elimated. When it finds a pair, if there is already a pair, then the score should be updated to reflect #twoPair. In real poker, if two players both have two pair, then the one with the higher value pair wins. For example, if Joe has a pair of 10s and a pair of 3s, that beats Franco's pair of 9s and pair of 8s. So to come up with a way to compare scores, here's what the script does. Let's say that you've already found a pair of 3s (and because the valList is sorted, it'll always find the lowest valued pair first). When you're in the middle of the checkForMatches handler, score will look like this:
score = [#pair:3]
We continue the process and encounter the pair of 8s. Before adding that to the score, it checks to see if there's another pair already there. If so, it creates a new property, #twoPair. The value is calculated like this:
twoPairVal = (currentVal * 13) + firstPairVal
So for a pair of 8s and a pair of 3s, you'll have:
twoPairVal = (8 * 13) + 3
And you'd have a score like this:
score = [#pair:3, # twoPair: 107]
This formula gives us a single integer value which can be used to compare various combinations of two pair. Using this formula, a pair of aces and a pair of 2s will beat a player with a pair of kings and a pair of queens -- as it should. There's a similar formula for evaluating a full house (a combination of 3-of-a-kind and a pair.) In this case, I multiply the #trip value by 100 and add the pair value. It's necessary to change the multiplier by 100 because the value of the #trip is what determines the winner and it could be lower than the pair value.
After checking for matches, we need to check for straights and flushes. If there are any matches (in a 5 card hand), then there can't be any straights. So I only check for those if there were no matches found.
To check for straights, we simply need to look through the valList and see if each subsequent value is one more than the last. If not, we can exit the loop and we're done. If we make it through the whole list, then there must be a straight. There's one exception to this because an ace can be counted at the top or bottom of a straight. So, I do have an added check for that. If a straight is found, the high-card value is entered. For a 5, 6, 7, 8, 9 straight, you'd have this:
score = [#straight: 9]
Checking for a flush is super-easy. We just look through the suitList and test to see if any of the suits are different from the first suit there. If so, no flush. But if there is a flush, the high card becomes the value of the flush. If you had the 2, 3, 7, 9, and queen (12) of hearts, you'd have a score like this:
score = [#flush: 12]
If there is a flush, the checkForFlush looks to see if there's also a straight. If so, then the score is entered as a #straightFlush instead.
That takes care of building the score for a hand. Now we need to compare the scores of two hands. To do that, I made a handler called eval2hands. It sends gHand1 and gHand2 through the pokerEval process to render to score lists. Then it steps through a list of possible properties:
scoreProps = [# straightFlush, #quad, # fullHouse, #flush, #straight, #trip, #twoPair, #pair]
First it checks to see if either score list contains a straightFlush. If so, it compares the values for the two players. If only one player has the straightFlush, then the other player's #straightFlush value is -- which is less than the first player's score. If no #straightFlush is found, then it loops and checks for the next property, #quad. It does this looping through each of the properties until it finds one player that scores higher than the other.
Well, that's it. The demo that I've written should be easily modified for a wide range of uses. I'm particularly interested in seeing a multiplayer game (using the multiplayer xtra) where each player only sees his own cards. It could be expanded to evaluate as many hands as is practical in a real poker game. Anybody interested in trying it? Post your comments and ideas on the DOUGthreads forum.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.