I am currently trying to make a poker algorithm that determines the chance of winning a hand. It needs to be extremely fast because it will have to loop through hundreds of thousands of different hands each time.
What I'm struggling to do is to be able to get all the unique hands that could possible come up in a board. A board contains 5 cards.
Each time a card comes up on the board, that card cannot come up again.
So what I've been doing to get all the possible board combinations is loop through all possible results using for loops.
For this example, I'm going to get only the first 3 cards of the board.
The code is something like this:
// $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;
}
}
}
This does get me all possible board combinations. The only problem is it gets me duplicate values too, for example the boards:
Ad 6d 4c
is the same as
4c Ad 6d
I could run array_unique() on my list of boards, but the problem comes here with my forloop having to loop through 91020 hands. This is super slow for my algorithm.
I was just wondering if someone had a better idea of looping through the possible boards.
Storing the board values in an array and then testing to see if the card value is in the list is still very slow. Is there a way of looping only through unique board combinations?
What you're doing is basically ok, but instead of iterating from 0 to $card_set_count
each time, the second card should only be picked from the cards that come after the first card, and the third card should only be picked from the cards that come after the second card, like this:
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 ...
}
}
}
With 50 cards left in the pack, that gives 19600 combinations. You could prune these combinations further, because for some hands the suit isn't important, but this may get very complicated.
At first I misread your question, and gave the answer below, which doesn't fully address your specific problem. I haven't deleted it because it already had an upvote, so someone apparently found it useful.
Create an array with all the cards. Create a variable with the number of cards still left: cardsLeft = 52
. Then, when you need to pick a card, choose at random from card 1 to 52, swap the chosen card with card 52, and set cardsLeft
to 51. Next card, you choose from card 1 to 51, swap it with card 51, set cardsLeft
to 50, and so on...
Whenever you need to start a new game with a new deck, just reset cardsLeft to 52. No need to re-initialize or shuffle the array.
I haven't used php in years, but here's an example in Javascript; it's quite self-explanatory. Run the code snippet to draw a poker hand for three players (see output in console).
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());