PHP 获取扑克的所有唯一棋盘结果
PHP Getting all unique board results for poker
我目前正在尝试制作一种扑克算法来确定赢得一手牌的机会。它需要非常快,因为它每次都必须经过数十万个不同的手。
我正在努力做的是能够让所有可能出现在公共牌面的独特牌。一个棋盘包含 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;
}
}
}
这确实为我提供了所有可能的棋盘组合。唯一的问题是它也让我得到重复的值,例如 boards:
广告 6d 4c
与
相同
4c 广告 6d
我可以 运行 array_unique() 在我的棋盘列表上,但问题是我的 forloop 必须循环 91020 手牌。这对我的算法来说太慢了。
我只是想知道是否有人对遍历可能的板有更好的想法。
将棋盘值存储在一个数组中,然后测试卡片值是否在列表中仍然很慢。有没有一种方法可以只通过独特的棋盘组合进行循环?
创建一个包含所有卡片的数组以从中提取卡片
为已使用的卡片创建一个空数组
当从包含所有卡片的数组中获取一张卡片时,将其添加到第二个数组并将其从第一个数组中删除(未设置),这样您就无法再次选择它...
$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
这样 $chosen_card 任何时候都只有未使用的卡片,$known_cards 已经拿过所有卡片。
你做的基本上没问题,但不是每次都从 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 种组合。您可以进一步修剪这些组合,因为对于某些牌来说花色并不重要,但这可能会变得非常复杂。
起初我误读了你的问题,并在下面给出了答案,这并没有完全解决你的具体问题。我没有删除它,因为它已经有一个 upvote,所以显然有人发现它有用。
创建一个包含所有卡片的数组。创建一个变量,其中包含剩余的卡片数量: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());
如果您只想要来自已知集合的所有独特组合,您可以实施以下算法:
$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);
我目前正在尝试制作一种扑克算法来确定赢得一手牌的机会。它需要非常快,因为它每次都必须经过数十万个不同的手。
我正在努力做的是能够让所有可能出现在公共牌面的独特牌。一个棋盘包含 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;
}
}
}
这确实为我提供了所有可能的棋盘组合。唯一的问题是它也让我得到重复的值,例如 boards:
广告 6d 4c
与
相同4c 广告 6d
我可以 运行 array_unique() 在我的棋盘列表上,但问题是我的 forloop 必须循环 91020 手牌。这对我的算法来说太慢了。
我只是想知道是否有人对遍历可能的板有更好的想法。
将棋盘值存储在一个数组中,然后测试卡片值是否在列表中仍然很慢。有没有一种方法可以只通过独特的棋盘组合进行循环?
创建一个包含所有卡片的数组以从中提取卡片
为已使用的卡片创建一个空数组
当从包含所有卡片的数组中获取一张卡片时,将其添加到第二个数组并将其从第一个数组中删除(未设置),这样您就无法再次选择它...
$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
这样 $chosen_card 任何时候都只有未使用的卡片,$known_cards 已经拿过所有卡片。
你做的基本上没问题,但不是每次都从 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 种组合。您可以进一步修剪这些组合,因为对于某些牌来说花色并不重要,但这可能会变得非常复杂。
起初我误读了你的问题,并在下面给出了答案,这并没有完全解决你的具体问题。我没有删除它,因为它已经有一个 upvote,所以显然有人发现它有用。
创建一个包含所有卡片的数组。创建一个变量,其中包含剩余的卡片数量: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());
如果您只想要来自已知集合的所有独特组合,您可以实施以下算法:
$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);