Проверьте на покер прямо

Мне удалось создать алгоритм для проверки ранга покерной руки. Он работает на 100% правильно, но очень медленно. Я анализировал код, и функция проверки прямой — одна из самых медленных его частей.

Итак, мой вопрос: есть ли лучший способ вычислить, делает ли рука стрит?

Вот некоторые детали:

7 карт, 2 от владельца, 5 с доски. А может быть высоким или низким.

Каждой карточке присваивается значение:
2 = 2
3 = 3
..
9 = 9
Т = 10
J = 11
Q = 12
К = 13
А = 14

В скрипте есть массив всех 7 карт:

$cards = array(12,5,6,7,4,11,3);

Так что теперь мне нужно иметь возможность отсортировать это в массив, где это:

  • отбрасывает дубликаты
  • заказывает карту от низшей к высшей
  • возвращает только 5 последовательных карт, т.е. (3,4,5,6,7)

Это должно быть быстро; циклы и итерации очень дороги. Это то, что я сейчас использую, и когда он пытается проанализировать, скажем, 15000 рук, это сказывается на сценарии.

Для вышесказанного я использовал:

  • сбросить дубликаты (используйте array_unique)
  • заказывать карты от низшего к высшему (используйте sort ())
  • вернуть только 5 последовательных карт (используйте цикл for для проверки значений карт)

У кого-нибудь есть примеры того, как я мог бы улучшить это? Может быть, даже на другом языке, который я мог бы, возможно, посмотреть и посмотреть, как это делается?

3

Решение

Вместо того, чтобы работать с дедупликацией и сортировкой массива, рассмотрите возможность использования битовой маски и установки битов в 1, где установлено значение карты. Битовая маска работает как структура данных Set и имеет дополнительные преимущества при обнаружении смежных элементов.

for ($i = 0; $i < count($cards); $i++) {
$card = $cards[$i];
// For each card value, set the bit
if ($card == 14) {
// If card is an ace, also set bit 1 for wheel
$cardBitmask |= 0x2;
}
$cardBitmask |= (1 << $card);
}

// To compare, you simply write a for loop checking for 5 consecutive bits
for($i = 10; $i > 0; $i--)
{
if ($cardBitmask & (0x1F << $i) == (0x1F << $i)) {
// Straight $i high was found!
}
}
4

Другие решения

Рассмотрим реализацию Java на эта ссылка. Я включил это здесь:

public static boolean isStraight( Card[] h )
{
int i, testRank;

if ( h.length != 5 )
return(false);

sortByRank(h);      // Sort the poker hand by the rank of each card

/* ===========================
Check if hand has an Ace
=========================== */
if ( h[4].rank() == 14 )
{
/* =================================
Check straight using an Ace
================================= */
boolean a = h[0].rank() == 2 && h[1].rank() == 3 &&
h[2].rank() == 4 && h[3].rank() == 5 ;
boolean b = h[0].rank() == 10 && h[1].rank() == 11 &&
h[2].rank() == 12 && h[3].rank() == 13 ;

return ( a || b );
}
else
{
/* ===========================================
General case: check for increasing values
=========================================== */
testRank = h[0].rank() + 1;

for ( i = 1; i < 5; i++ )
{
if ( h[i].rank() != testRank )
return(false);        // Straight failed...

testRank++;   // Next card in hand
}

return(true);        // Straight found !
}
}

Быстрый поиск в Google по запросу «проверить покер» (desired_lang)«даст вам другие реализации.

1

Вы можете просто отсортировать карточки и зациклить их в массиве — всегда сохраняя последнюю карточку и сравнивая ее с текущей.

$cards = array(12,5,6,7,4,11,3);
sort($cards);

$last = 0;
$count = 0;
$wheel = false;
foreach ($cards as $card) {
if ($card == $last) {
continue;
} else if ($card == ++$last) {
$count++;
} else {
if ($last == 6) $wheel = true;
$count = 1;
$last = $card;
}

if ($count == 5 || ($card == 14 && $wheel)) {
echo "straight $last";
$straight = range($last - 4, $last);
break;
}
}
1

Вы можете пойти следующим образом, вам не нужно сортировать или что-то еще (при условии, что 2 — 2, а 14 — туз):

$cards = [12,5,6,7,4,11,3];

function _inc(&$i) {
if ($i == 14)
$i = 2;
else
$i++;
return $i;
}

$straight = false;
for($i = 2; $i <= 14; $i++) {
$ind = $i;
if (!in_array($ind, $cards)) continue;
$s = [$ind, _inc($ind), _inc($ind), _inc($ind), _inc($ind)];
$straight = count(array_intersect($s, $cards)) == count($s);
if ($straight) break;
}

print $straight;
0
По вопросам рекламы [email protected]