我开始自学 C 语言,并决定构建一个计算扑克赢率的程序。我正在尝试使用 Monte Carlo 计算净值,但我得到了错误的结果。
这里有一个例子:我持有 JsTs(黑桃 J 和黑桃 10)。我有两个对手,我要分配特定的手牌范围。第一个对手只玩 AA(任何 A-A 口袋,总共 6 种不同的组合),第二个对手玩 KK+(任何 A-A 或 K-K 口袋)。因此,计算过程首先从对手范围中随机选择一个范围(对于对手 1,这始终是 AA)。然后我确定该范围内的不同组合(Ah Ac、Ah Ad、Ah As 等)并随机选择该范围内的组合之一。所以我对两个对手都这样做。然后我随机选择五张牌并评估玩家手牌和对手手牌。然后我看看我是赢了还是平局并记录结果。
所以我这样做了 1000 万次,我的赢率为 20.5%,但应该是 19.1%。这是我的代码的 main() 函数:
int main()
{
randctx rctx;
Deck[4][13];
randinit(&rctx, TRUE);
numberOfOpponents = 2;
//opponent ranges selected
rangeIsSelected[0][0]= 1;
rangeIsSelected[1][0]= 1;
rangeIsSelected[1][14]= 1;
//player cards
Player_Card_Flush[0] = 0;
Player_Card_Rank[0] = 8;
Player_Card_Flush[1] = 0;
Player_Card_Rank[1] = 9;
//insert player cards to dealt cards
Deck[Player_Card_Flush[0]][Player_Card_Rank[0]] = 1;
Deck[Player_Card_Flush[1]][Player_Card_Rank[1]] = 1;
checkForErrors(0);
if (impossibleError==1) {
printf("Impossible to calculate equity");
return;
}
gamesSimulated = 0;
totalTies = 0;
totalWins = 0;
int opponentToBeDealt = 0;
//let's see what ranges are selected by opponents
for (int i=0; i<numberOfOpponents; i++) {
findSelectedRanges(i);
}
//beginning of Monte Carlo method
while (gamesSimulated<maxTrials) {
int b = 0;
int opponentsDealt = 0;
//randomly select hand for opponents
while (opponentsDealt<numberOfOpponents) {
opponentCardsForMonteCarlo(opponentToBeDealt);
opponentsDealt += 1;
if (opponentsDealt==numberOfOpponents) break;
if (opponentToBeDealt==numberOfOpponents-1) {
opponentToBeDealt = 0;
}
else {
opponentToBeDealt += 1;
}
}
//randomly choose 5 board cards
while (b<5) {
int randomCardTag = rand(&rctx) % 52;
randomCardFlush[b] = randomCardTag / 13;
randomCardRank[b] = randomCardTag % 13;
//if this card hasn't been dealt then add to dealt cards
if (Deck[randomCardFlush[b]][randomCardRank[b]]==0) {
Deck[randomCardFlush[b]][randomCardRank[b]] = 1;
b++;
}
}
//evaluate hands (this function also removes random opponent hands when it's done)
calculateMonteCarloEquity();
//remove random board cards from dealt cards
for (int x=0; x<b; x++){
Deck[randomCardFlush[x]][randomCardRank[x]]=0;
}
}
因为我已经编写了自己的评估代码,所以我首先怀疑这一点,但是当我使用完全相同的代码进行详尽枚举时,我得到了正确的结果(通过 PokerStove 确认)。然后我开始看看我为对手发牌的方式是否有任何偏见。这是我的输出:
对手 1 手牌 作为交流电:1665806次 作为啊:1667998次 作为广告:1666631次 Ac啊:1665767次 Ac广告:1666595次 啊广告:1667203次
对手 2 手牌 作为 Ac:833847 次 作为啊:833392次 作为广告:832396次 Ac啊:833406次 广告:834542次 啊广告:833703次 Ks Kc:832585次 Ks Kh:835641次 Ks Kd:832483次 Kc Kh:833013次 Kc Kd:831558次 Kh Kd:833434次
这对我来说看起来很随机。我还查看了公共(public)牌,似乎也没有任何偏差,基本上所有牌都发了大约 1,08xxxx 百万次,除了 As - 271 812 次,Ac - 272 856 次,Ah - 271 898 次,Ad - 272 062 次,Ks - 815 113,Kc - 816 871,Kh - 814 955 次,Kd - 814 866 次,当然还有 Js - 0 次和 Ts - 0 次。我还尝试创建一个未处理卡数组,这样我的随机板卡就不会是 rand(&rctx) % 52,而是根据情况 rand(&rctx) % 46,rand(&rctx) % 45 等(基本上我只选择来自未发牌)。但是,这不会对结果产生太大影响。
我使用的是 ISAAC 随机数生成器,尽管我使用内置的 rand() 函数几乎得到了相同的结果。我试过像 randinit(&rctx, time(NULL))
这样随时间播种,但最终结果差别不大。是的,我知道时间对于加密目的来说是一个糟糕的种子,但对于像这样的模拟应该没问题。
所以我已经没有想法了,也许有人能看到我遗漏的东西?
编辑 这是我的权益计算代码
void calculateMonteCarloEquity() {
opponentsBeaten = 0;
opponentsTied = 0;
opponentsLost = 0;
//remove all opponent cards from dealt cards, because we need 7 dealt cards to evaluate hand
for (int x=0; x<numberOfOpponents; x++) {
Deck[opponentCardFlush[x][0]][opponentCardRank[x][0]] = 0;
Deck[opponentCardFlush[x][1]][opponentCardRank[x][1]] = 0;
}
//at this point we have 5 board cards and 2 player cards left in dealt cards
//so let's evaluate that hand
Evaluate_Hand();
playerHandScore = Hand_Score;
//now remove player hand form dealt cards
Deck[Player_Card_Flush[0]][Player_Card_Rank[0]] = 0;
Deck[Player_Card_Flush[1]][Player_Card_Rank[1]] = 0;
//let's evaluate opponent hands and save their scores
for (int x=0; x<numberOfOpponents; x++) {
//insert opponent x hand to dealt cards
Deck[opponentCardFlush[x][0]][opponentCardRank[x][0]] = 1;
Deck[opponentCardFlush[x][1]][opponentCardRank[x][1]] = 1;
Evaluate_Hand();
opponentHandScore[x] = Hand_Score;
//remove opponent x hand from dealt cards when evaluated
Deck[opponentCardFlush[x][0]][opponentCardRank[x][0]] = 0;
Deck[opponentCardFlush[x][1]][opponentCardRank[x][1]] = 0;
}
//compare opponent hand scores with player hand score
for (int x=0; x<numberOfOpponents; x++) {
if (playerHandScore > opponentHandScore[x]) {
opponentsBeaten += 1;
continue;
}
else if (playerHandScore == opponentHandScore[x]) {
opponentsTied += 1;
continue;
}
else if (playerHandScore < opponentHandScore[x]) {
opponentsLost += 1;
continue;
}
}
//if player beats all opponents he wins the hand
if (opponentsBeaten==numberOfOpponents) {
totalWins += 1;
}
//if player doesn't beat all the opponents, but neither loses to anyone, there must be a tie
if (opponentsLost==0 && opponentsBeaten!=numberOfOpponents) {
totalTies += 1/(opponentsTied+1);
}
//one game has been evaluated
gamesSimulated += 1;
playerEquity = (totalWins+totalTies)/gamesSimulated;
//let's insert player cards back to dealt cards
Deck[Player_Card_Flush[0]][Player_Card_Rank[0]] = 1;
Deck[Player_Card_Flush[1]][Player_Card_Rank[1]] = 1;
if (gamesSimulated>=maxTrials) return;
}
最佳答案
你已经为对手 2 分配了 AA 和 KK 的相同概率。
在现实生活中,AA KK 比 AA AA 更有可能。与KK的组合有6种,与AA的组合只有一种。
关于c - 计算扑克 Assets 的蒙特卡洛方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21015352/