Мне удалось создать алгоритм для проверки ранга покерной руки. Он работает на 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);
Так что теперь мне нужно иметь возможность отсортировать это в массив, где это:
Это должно быть быстро; циклы и итерации очень дороги. Это то, что я сейчас использую, и когда он пытается проанализировать, скажем, 15000 рук, это сказывается на сценарии.
Для вышесказанного я использовал:
У кого-нибудь есть примеры того, как я мог бы улучшить это? Может быть, даже на другом языке, который я мог бы, возможно, посмотреть и посмотреть, как это делается?
Вместо того, чтобы работать с дедупликацией и сортировкой массива, рассмотрите возможность использования битовой маски и установки битов в 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!
}
}
Рассмотрим реализацию 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)
«даст вам другие реализации.
Вы можете просто отсортировать карточки и зациклить их в массиве — всегда сохраняя последнюю карточку и сравнивая ее с текущей.
$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;
}
}
Вы можете пойти следующим образом, вам не нужно сортировать или что-то еще (при условии, что 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;