В настоящее время я пытаюсь создать покерный алгоритм, который определяет вероятность выигрыша руки. Он должен быть очень быстрым, потому что каждый раз придется проходить через сотни тысяч разных рук.
То, что я изо всех сил пытаюсь сделать, — это иметь возможность собрать все уникальные руки, которые могли бы появиться на доске. Доска содержит 5 карт.
Каждый раз, когда на доске появляется карта, эта карта не может появиться снова.
Итак, что я делал, чтобы получить все возможные комбинации досок, так это перебрать все возможные результаты, используя циклы for.
Для этого примера я собираюсь получить только первые 3 карты доски.
Код выглядит примерно так:
// $card_set_count is the amount of cards left in the deck after taking away the
// user's hand cards.
for($i=0;$i<$card_set_count;$i++) {
// First known card
$known_card1 = $card_set[$i];
for($j=0;$j<$card_set_count;$j++) {
// Second known card
$known_card2 = $card_set[$j];
// Skip the card if we already have it out
if($known_card1 == $known_card2) continue;
for($k=0;$k<$card_set_count;$k++) {
// Third Known Card
$known_card3 = $card_set[$k];
// Skip card if the card is already out
if($known_card3 == $known_card2 || $known_card1 == $known_card3) continue
// Create board
$board = array();
$board[] = $known_card1;
$board[] = $known_card2;
$board[] = $known_card3;
}
}
}
Это дает мне все возможные комбинации досок. Единственная проблема в том, что он тоже дает мне дублирующиеся значения, например, доски:
Ad 6d 4c
такой же как
4c Ad 6d
Я мог бы запустить array_unique () в моем списке плат, но проблема здесь заключается в том, что мой forloop перебрал 91020 рук. Это очень медленно для моего алгоритма.
Мне просто интересно, есть ли у кого-то лучшая идея перебрать возможные доски.
Сохранение значений платы в массиве и последующее тестирование, чтобы увидеть, находится ли значение карты в списке, все еще очень медленное. Есть ли способ зацикливания только через уникальные комбинации досок?
То, что вы делаете, в принципе нормально, но вместо итерации от 0 до $card_set_count
каждый раз, вторая карта должна быть выбрана только из карт, которые идут после первой карты, а третья карта должна быть выбрана только из карт, которые идут после второй карты, например:
for($i=0;$i<$card_set_count - 2;$i++) {
for($j=$i + 1;$j<$card_set_count - 1;$j++) {
for($k=$j + 1;$k<$card_set_count;$k++) {
$board = array();
$board[] = $card_set[$i];
$board[] = $card_set[$j];
$board[] = $card_set[$k];
// evaluate hand ...
}
}
}
Если в колоде осталось 50 карт, это дает 19600 комбинаций. Вы можете обрезать эти комбинации дальше, потому что для некоторых рук костюм не важен, но это может быть очень сложно.
Сначала я неправильно прочитал ваш вопрос и дал ответ ниже, который не полностью решает вашу конкретную проблему. Я не удалил его, потому что у него уже было возражение, поэтому кто-то, по-видимому, нашел его полезным.
Создайте массив со всеми картами. Создайте переменную с количеством оставшихся карт: cardsLeft = 52
, Затем, когда вам нужно выбрать карту, выберите случайным образом от карты 1 до 52, поменяйте местами выбранную карту с картой 52 и установите cardsLeft
на 51. Следующая карта, которую вы выбираете из карты 1 на 51, поменяйте местами на карту 51, установите cardsLeft
до 50 и так далее …
Всякий раз, когда вам нужно начать новую игру с новой колодой, просто сбросьте cardsLeft на 52. Нет необходимости повторно инициализировать или перетасовывать массив.
Я не использовал php годами, но вот пример в Javascript; это довольно очевидно. Запустите фрагмент кода, чтобы нарисовать покерную комбинацию для трех игроков (см. Вывод в консоли).
function Deck() {
this.cards = [];
this.left = 52;
for (var suit = 0; suit < 4; suit++) {
for (var number = 0; number < 13; number++) {
this.cards.push("23456789TJQKA".charAt(number) + "cdhs".charAt(suit));
}
}
}
Deck.prototype.draw = function() {
if (this.left == 0) this.shuffle();
var pick = Math.floor(Math.random() * this.left);
var swap = this.cards[pick];
this.cards[pick] = this.cards[--this.left];
this.cards[this.left] = swap;
return swap;
}
Deck.prototype.shuffle = function() {
this.left = 52;
}
var d = new Deck();
document.write("player 1: " + d.draw() + "," + d.draw() + "<BR>");
document.write("player 2: " + d.draw() + "," + d.draw() + "<BR>");
document.write("player 3: " + d.draw() + "," + d.draw() + "<BR>");
document.write("flop: " + d.draw() + "," + d.draw()+ "," + d.draw() + "<BR>");
document.write("turn: " + d.draw() + "<BR>");
document.write("river: " + d.draw());
создать массив со всеми картами, из которых можно вытащить карты
создать пустой массив для уже использованных карт
при получении карты из массива со всеми картами добавьте ее во второй массив и удалите ее из массива кулаков (не задано), чтобы вы не могли выбрать ее снова …
$chosen_card = array_rand($card_set); // just choosing a card randomly to simulate whatever way you currently pick one
$known_cards[] = $card_set[$chosen_card]; // copy the card to the know_cards array
unset($card_set[$chosen_card]); // remove cards from unused cards
Таким образом, $ selected_card имеет только неиспользованные карты в любое время, а $ known_cards имеет все уже взятые карты.
Если вам просто нужны все уникальные комбинации из известного набора, вы можете реализовать следующий алгоритм:
$card_set = [1,2,3,4,5];
$k = 3;
$n = count($card_set);
$combs = [];
$stack = [[[],0,0]];
while (!empty($stack)){
$params = array_pop($stack);
$current_hand = $params[0];
$i = $params[1];
$len = $params[2];
if ($len == $k){
array_push($combs,$current_hand);
} else {
if ($i < $n - 1){
array_push($stack,[$current_hand,$i + 1,$len]);
}
if ($i < $n){
array_push($current_hand,$card_set[$i]);
array_push($stack,[$current_hand,$i + 1,$len + 1]);
}
}
}
print_r($combs);