📜 ⬆️ ⬇️

The calculation of the priority of combinations in Texas Hold'em (poker) for PHP

In this article I will talk about my method of calculating the priority of combinations in Texas Hold'em (poker with 2 pocket cards and 5 common). Conventionally, I will divide the article into 6 parts: Creating an array of cards, Calculation of a Straight, Calculation of a Flush and a Straight Flush, Calculation of Pair Combinations, Final Calculation, Display. I write the code in procedural style.

Objective: to get the output of the program readable result available for debugging and debugging at the stage of writing code. To achieve this goal, I make the difference between combinations of 1e + 2 (100) times.

An approximate view of what should come out in the end, where I consider the last 2 cards pocket and the first 5 common:
')

Create an array of maps


In the deck there are 4 suits and 13 virtues, therefore I will form an array of 7 numbers in the range [2–14, 102–114, 202–214, 302–314], and then operate the remainder of division by 100 (% 100) of these numbers. You can, of course, form an array of numbers in the range [2 - 14, 22 - 34, 42 - 54, 62 - 74], and then compare the residuals from division by 20 (% 20). But the readability of the first option in my face, so I will focus on it.

function cardsCreation() { $arrayCards = []; for ($i = 0; $i < 7; $i++) { $card = mt_rand(2, 14); //       2  14 $multiplier = mt_rand(0, 3); //    if (1 == $multiplier) { //   1,    100 $card = $card + 100; } else if (2 == $multiplier) { //   2,    200 $card = $card + 200; } else if (3 == $multiplier) { //   3,    300 $card = $card + 300; } if (!in_array($card, $arrayCards)) { //,      ,       $arrayCards = array_merge($arrayCards, [$card]); } else { //     ,  ,     $i--; } } return $arrayCards; } 

Determining and calculating a Street combination


A straight is a combination where the cards are in order. Therefore, it makes no sense to take into account when calculating all the cards that make up this combination, it suffices only the first card in seniority.

There are several options for determining and calculating a Street combination. I think most of them come down to the task of sorting out the remnants of dividing the members of the original array in descending order, and then somehow selecting the elements that make up the combination (in the case where more than 5 cards make a straight, you need to choose the largest).

The essence of my method for determining a straight comes down to the fact that after sorting, I will first check the first five cards for a straight, then the second and third. I also remember that ace, two, three, four and five also make a straight. Therefore, if there is an ace (value 14) in the set, I add the eighth element to the array - 1. And therefore in this case, you need to check the fourth five of the cards.

 function straight(array $arrayCards) { $newArrayCards = []; $ace = false; foreach ($arrayCards as $arrayCard) { $newArrayCards = array_merge($newArrayCards, [$arrayCard % 100]); //       100 if(14 == $arrayCard % 100) { //     , 2, 3, 4, 5 $ace = true; } } if($ace == true) { $newArrayCards = array_merge($newArrayCards, [1]); //    ,    1 } rsort($newArrayCards); //       $count = 0; //,    1  ,         = 1 $length = 4; //,       $result = 0; //  $begin = 0; // ,      for($i = 1; $i <= $length; $i++) { if (-1 == ($newArrayCards[$i] - $newArrayCards[$i - 1])) { $count++; } if($length == $i) { if(4 == $count) { //$count == 4,   $result = $newArrayCards[$begin] * 1e+8; } else if($length < 6 or (6 == $length and $ace == true)) {//  ,      $length++; // ,     $begin++; // ,     $i = $begin; //   for  $i   1 ($i++  for) $count = 0; //  } } } return $result; } 

Definition and calculation of combinations of Flash and Street Flash


Flush - a combination of cards of the same suit. When calculating you need to consider all the cards that make up the combination.

When calculating a straight flush, as in the calculation of a straight, you can only consider the highest card of the combination.

To determine the flush, run loop through the array. In the loop, create 4 auxiliary arrays (by the number of suits). In the first array I will put all cards of the first suit, in the second - the second, etc. If there is no suit, the corresponding array will be empty. If the number of elements in the array is greater than or equal to 5, then this suit formed a flush.

Flush is more priority than straight, so it is logical to check whether the combination of a straight flush formed exactly in the flash function. Also, I think it is clear that it is inconvenient to write a separate function that checks both the straight and the flush. It is better to write a function that checks an array for a flash, and in it to call a function that checks a flash for a straight.

If the flush does not form a straight flush, sort the remainder of the division by 100 (% 100) of the original array. Next, multiply the first five members of the resulting array by 1 + 10, 1 + 8, 1 + 6, 1 + 4, 1 + 2, respectively.

I will build a function by definition of a straight flush based on a function by definition of a straight, with the only difference that it is necessary to take into account that an array with less than 7 elements can come into the function (I’m sending only those cards that make up the flush).

Function to determine Flash:

 function pokerFlush(array $arrayCards) { $suit1 = []; //  $suit2 = []; //  $suit3 = []; //  $suit4 = []; //  foreach ($arrayCards as $arrayCard) { // 4 ,      if($arrayCard >= 2 and $arrayCard <= 14) { $suit1 = array_merge($suit1, [$arrayCard]); } else if($arrayCard >= 102 and $arrayCard <= 114) { $suit2 = array_merge($suit2, [$arrayCard]); } else if($arrayCard >= 202 and $arrayCard <= 214) { $suit3 = array_merge($suit3, [$arrayCard]); } else { $suit4 = array_merge($suit4, [$arrayCard]); }} if(count($suit1) >= 5) { //        5 $result = straightFlush($suit1); //        if(0 == $result) {//    foreach ($suit1 as $key1 => $s1) {//     100 $suit1[$key1] = $s1 % 100; } rsort($suit1); //    $result = $suit1[0] * 1e+10 + $suit1[1] * 1e+8 + $suit1[2] * 1e+6 + $suit1[3] * 1e+4 + $suit1[4] * 1e+2; } } else if (count($suit2) >= 5) { //        5 $result = straightFlush($suit2); if(0 == $result) { foreach ($suit2 as $key2 => $s2) { $suit2[$key2] = $s2 % 100; } rsort($suit2); $result = $suit2[0] * 1e+10 + $suit2[1] * 1e+8 + $suit2[2] * 1e+6 + $suit2[3] * 1e+4 + $suit2[4] * 1e+2; } } else if (count($suit3) >= 5) { //        5 $result = straightFlush($suit3); if(0 == $result) { foreach ($suit3 as $key3 => $s3) { $suit3[$key3] = $s3 % 100; } rsort($suit3); $result = $suit3[0] * 1e+10 + $suit3[1] * 1e+8 + $suit3[2] * 1e+6 + $suit3[3] * 1e+4 + $suit3[4] * 1e+2; } } else if (count($suit4) >= 5) { //        5 $result = straightFlush($suit4); if(0 == $result) { foreach ($suit4 as $key4 => $s4) { $suit4[$key4] = $s4 % 100; } rsort($suit4); $result = $suit4[0] * 1e+10 + $suit4[1] * 1e+8 + $suit4[2] * 1e+6 + $suit4[3] * 1e+4 + $suit4[4] * 1e+2; } } else { $result = 0; } return $result; } 

The function for determining a Street Flush (similar to a Street, only it is necessary to take into account that the number of elements in an array can be not only 7, but also 5 and 6, and that the returned result of this function should be more):

 function straightFlush(array $arrayCards) { $newArrayCards = []; $ace = false; foreach ($arrayCards as $arrayCard) { $newArrayCards = array_merge($newArrayCards, [$arrayCard % 100]); if (14 == $arrayCard % 100) { $ace = true; } } if ($ace == true) { $newArrayCards = array_merge($newArrayCards, [1]); } rsort($newArrayCards); $count = 0; $length = 4; $result = 0; $begin = 0; for ($i = 1; $i <= $length; $i++) { if (-1 == ($newArrayCards[$i] - $newArrayCards[$i - 1])) { $count++; } if ($length == $i) { if (4 == $count) { $result = $newArrayCards[$begin] * 1e+16; } else if ((7 == count($arrayCards) and ($length < 6 or (6 == $length and $ace == true))) or (6 == count($arrayCards) and ($length < 5 or (5 == $length and $ace == true))) or //     = 6 (5 == count($arrayCards) and (5 == $length and $ace == true))) { //     = 5 $length++; $begin++; $i = $begin; $count = 0; } } } return $result; } 

Definition and calculation of pair combinations


There are five pair combinations: four of a kind (4 cards of the same value), full house (3 cards of the same value and 2 cards of another value), a triple (3 cards of the same value), two pairs (2 cards of the same value and 2 cards of another value), a pair (2 cards of the same value).

When calculating, it is important to remember that in a full house combination, the main one is a combination of three cards, and two of the second cards, that is, for example, a combination of 3 twos and 2 dozens will be considered as 3 * 1e + 12 + 10 * 1e + 10, and not on the merits of the cards.

And also when calculating pair combinations you need to consider the problems:

1. The fact that more than 5 cards form a combination.
2. The fact that we may have a situation in which combinations of more than one.

To count the matching cards I will use three counters that will count the pair cards in the deck. Where the counter is 1 - 2 cards are involved in the combination, where the counter is 2 - 3 cards, where 3 - 4 cards.

Consider all possible combinations of counters:

100 - couple
110 - 2 pairs
111 - 3 pairs (need to convert to view 110 (two pairs))
200 - three
210 - full house
120 - full house (needs to be converted to view 210 (full house))
211 (121, 112) - full house + pair (must be converted to the form 210 (full house))
220 - 2 triples or a full house + 1 card (you need to convert to the form 210 (full house))
300 - quads
310 (130) - caret + pair (need to convert to mind 300 (caret))
320 (230) - four of a kind + three (need to convert to a kind of 300 (four of a kind))
Next, I will make the final calculation of pair combinations.

 function couple(array $arrayCards) { $newArrayCards = []; foreach ($arrayCards as $arrayCard) { $newArrayCards = array_merge($newArrayCards, [$arrayCard % 100]); //       100 } rsort($newArrayCards); //       $count1 = 0; //    $count2 = 0; //    $count3 = 0; //    $match1 = 0; //     $match2 = 0; //     $match3 = 0; //     for($i = 1; $i < count($newArrayCards); $i++) { if ($newArrayCards[$i] == $match1 or $match1 == 0) { //   if ($newArrayCards[$i] == $newArrayCards[$i - 1]) { $match1 = $newArrayCards[$i]; $count1++; } } else if ($newArrayCards[$i] == $match2 or $match2 == 0) { //   if ($newArrayCards[$i] == $newArrayCards[$i - 1]) { $match2 = $newArrayCards[$i]; $count2++; } } else if ($newArrayCards[$i] == $match3 or $match3 == 0) { //   if ($newArrayCards[$i] == $newArrayCards[$i - 1]) { $match3 = $newArrayCards[$i]; $count3++; } } } //   111  110 (2 )  211  210 ( ) if(($count1 == 1 or $count1 == 2) and $count2 == 1 and $count3 == 1) { $count3 = 0; } //   121   211   ,    210 ( ) else if($count2 == 2 and $count1 == 1 and $count3 == 1) { $support = $match2; $match2 = $match1; $match1 = $support; $count1 = 2; $count2 = 1; $count3 = 0; } //   112   211   ,    210 ( ) else if($count3 == 2 and $count1 == 1 and $count2 == 1) { $support = $match3; $match2 = $match1; $match1 = $support; $count1 = 2; $count3 = 0; } //   220  210 ( ) else if($count1 == 2 and $count2 == 2 and $count3 == 0) { $count2 = 1; } //   120  210 ( ) else if ($count1 == 1 and $count2 == 2 and $count3 == 0) { $support = $match1; $match1 = $match2; $match2 = $support; $count1 = 2; $count2 = 1; } //320  300  310  300 else if($count1 == 3 and ($count2 == 2 or $count2 == 1)) { $count2 = 0; } //230  320    300  130  310    300 else if($count2 == 3 and($count1 == 2 or $count1 == 1)) { $support = $match2; $match2 = $match1; $match1 = $support; $count1 = 3; $count2 = 0; } // if ($count1 == 3) { $count1 = 1e+14; } //  else if ($count1 == 2 and $count2 == 1) { $count1 = 1e+12; $count2 = 1e+10; } // else if ($count1 == 2 and $count2 == 0) { $count1 = 1e+6; } //2  else if ($count1 == 1 and $count2 == 1) { $count1 = 1e+4; $count2 = 1e+2; } // else if ($count1 == 1 and $count2 == 0) { $count1 = 1e+2; } $result = $match1 * $count1 + $match2 * $count2;// $match1  $match2   0,     return $result; } 

Final settlement


Now we have functions that check the array of cards for straight, flush, straight flush and pair combinations. I will call them together and calculate the final result, I also remember about the calculation of the high card.

Calculation of the high card:

1. Determine the highest and lowest priority pocket cards. To do this, compare them with the remnants of division by 100 (% 100).
2. I will add the lowest priority divided by 100 to the highest priority map.

 function priority(array $arrayCards) { //     if($arrayCards[5] % 100 > $arrayCards[6] % 100) { //,      -  $highCard1 = $arrayCards[5] % 100; $highCard2 = $arrayCards[6] % 100; } else { $highCard1 = $arrayCards[6] % 100; $highCard2 = $arrayCards[5] % 100; } $flush = pokerFlush($arrayCards); //     $straight = straight($arrayCards); //     $couple = couple($arrayCards); //     //      if($flush >= 1e+16) { $result = $flush; //  } else if($couple >= 1e+14 and $couple < 1e+16) { $result = $couple; // } else if($couple >= 1e+12 and $couple < 1e+14) { $result = $couple; //  } else if($flush >= 1e+10) { $result = $flush; // } else if($straight >= 1e+8 and $straight < 1e+10) { $result = $straight; // } else if($couple >= 1e+6 and $couple < 1e+8) { $result = $couple; // } else if($couple >= 1e+4 and $couple < 1e+6) { $result = $couple; //  } else if($couple >= 1e+2 and $couple < 1e+4) { $result = $couple; // } else { $result = $highCard1 + $highCard2 * 1e-2; //  } return $result; } 

About the display


I brought the result to the browser, using the following sprite (I took a picture from the site: fondhristianin.ru/?p=2941 ), as background-image for a div.



The width and height for the div were set equal to the size of one map, i.e. if the image size is 572px * 328px (as in this case), the number of cards is 13 in width, 5 in height, and 44px * 65.6px in width and height. Then I changed the background-position in view of the previously formed array map.

Calculate the background-position for any of the divs along the x axis

 100/12 * ($arrayCards[$i] % 100 - 2) 

where $ arrayCards is a previously formed array.
$ i - the serial number of the card.

Explanation of the calculation:
In the series of 13 cards, the beginning of the 1st card is 0%, the beginning of the 13th card is 100%, therefore the position difference is 100% / 12 (and not 13). We give the number of cards from the form [2-14, 102-114, 202-214, 302-314] to [0-12]. To do this, take the remainder of the card number and subtract 2. 2. Multiply the resulting number by the difference in position.

Calculate background-position for any of the divs on the y-axis

 100/4 * floor($arrayCards[$i] / 100) 

Explanation of the calculation:
In the row of 5 cards, the beginning of the 1st card is 0%, the beginning of the 5th card is 100%, therefore the difference of positions is 100% / 4 (and not 5). We give the number of cards from the form [2-14, 102-114, 202-214, 302-314] to [0-3]. To do this, divide the card number by 100 and round it down (you can use a simple rounding operation, it will work in the same way). Multiply the resulting number by the position difference.

Source: https://habr.com/ru/post/335540/


All Articles