參考
問題
起因是想測試一下酒館戰棋十二胖頭魚大亂鬥先後手的勝率,測試代碼如下:
#include<cstdio>
#include<cstdlib>
#include<ctime>
#define TIMES 1000000
#define PRINT 0
//先手方勝負平的總場數
int win, draw, lose;
//score:先手方存活隨從數減後手方存活隨從數,1M次模擬總和
//combat:發生戰鬥的次數,1M次模擬總和
int score, combat;
//p1爲先手玩家,p2後手
//當前發動進攻的隨從編號
int p1cur, p2cur;
//剩餘隨從數
int p1rem, p2rem;
//當前所有隨從狀態,1爲有聖盾,0爲無聖盾,-1爲死亡
int p1sta[6], p2sta[6];
//將rand()的隨機數映射爲隨從編號的表格
int p1tab[6], p2tab[6];
/*
一開始從0到5一一對應,
若一方隨從只剩1、2、4號,則
tab[0] = 1; tab[1] = 2; tab[2] = 4
此時若rand()隨機結果爲1,則2號隨從參戰
*/
//true爲先手方進攻,false爲後手方進攻
void battle(bool first);
//交戰的雙方隨從編號
void battle(int p1no, int p2no);
//勝負判定
bool wlcheck();
void printcur();
int main()
{
win = draw = lose = 0;
score = combat = 0;
int t = 0;
srand(time(0));
while (t++ < TIMES)
{
//千萬不要把srand(time(0))寫在這裏
p1cur = p2cur = 5;
p1rem = p2rem = 6;
for (int i = 0; i < 6; i++)
{
p1sta[i] = p2sta[i] = 1;
p1tab[i] = p2tab[i] = i;
}
while (1)
{
battle(1);
if (wlcheck())break;
printcur();
battle(0);
if (wlcheck())break;
printcur();
}
}
printf("先手勝率:%f%%\n後手勝率:%f%%\n平局率:%f%%\n平均存活隨從數:%f\n平均戰鬥次數:%f\n",
(double)win * 100 / TIMES,
(double)lose * 100 / TIMES,
(double)draw * 100 / TIMES,
(double)score / TIMES,
(double)combat / TIMES);
}
void battle(bool first)
{
if (first)
{
//首先找出下一個進攻隨從的編號
do {
if (p1cur == 5)p1cur = 0;
else p1cur++;
} while (p1sta[p1cur] == -1);
//然後令其和一個隨機敵方戰鬥
battle(p1cur, p2tab[rand() % p2rem]);
}
else
{
do {
if (p2cur == 5)p2cur = 0;
else p2cur++;
} while (p2sta[p2cur] == -1);
battle(p1tab[rand() % p1rem], p2cur);
}
}
void battle(int p1no, int p2no)
{
combat++;
//戰鬥結果判定,一方若有隨從死亡,修改存活隨從數rem,修改tab表格的對應關係
if (--p1sta[p1no] == -1)
{
p1rem--;
int i = -1;
while (p1tab[++i] != p1no);
while (i < p1rem) p1tab[i++] = p1tab[i + 1];
}
if (--p2sta[p2no] == -1)
{
p2rem--;
int i = -1;
while (p2tab[++i] != p2no);
while (i < p2rem) p2tab[i++] = p2tab[i + 1];
}
//恢復其他存活隨從的聖盾
for (int i = 0; i < 6; i++)
{
if (p1sta[i] == 0 && p1no != i)p1sta[i] = 1;
if (p2sta[i] == 0 && p2no != i)p2sta[i] = 1;
}
}
bool wlcheck()
{
if (p1rem == 0 && p2rem == 0)
{
draw++; return true;
}
else if (p1rem == 0)
{
lose++; score -= p2rem; return true;
}
else if (p2rem == 0)
{
win++; score += p1rem; return true;
}
else return false;
}
void printcur()
{
if (!PRINT)return;
for (int i = 0; i < 6; i++)
printf("%d ", p1sta[i]);
printf("\n");
for (int i = 0; i < 6; i++)
printf("%d ", p2sta[i]);
printf("\n\n");
}
結果
多次運行結果相差不大,後手勝率稍微領先一點點。
結論
使用srand(time(0))
初始化隨機數發生器時一定要寫在循環之外,否則如果循環每次執行時間小於1s,則獲得的隨機數就是完全相同的一組。