84 Monopoly Odds
这个游戏就是小时候玩的大富翁,掷骰子来决定前进步数,到了某个方格可能会触发一些事件,转移到某个方格。
问题如果无限玩这个游戏,那么走到哪三个格子的概率最大呢?
一个比较正规的做法是建立一个四十乘四十的矩阵,是概率转移矩阵,记录每个格子转移到其他格子的概率,这个矩阵自乘成若干次收敛之后,用初始状态,一个四十维的向量,和矩阵相乘,得到最终的四十维的向量,选择三个概率最高的格子。
但是我觉得一个一个算概率太麻烦,也就是填充概率转移矩阵很麻烦。下面采用模拟游戏的方法,掷骰子一百万次,然后计算每个格子出现的次数,得到一个近似概率。
下面写贴出整个代码,然后通过注释的方式解释玩法、算法。
private static readonly int Rolls = 1_000_000;
// some special positions
private static readonly int Go = 0;
private static readonly int Jail = 10;
private static readonly int Go2Jail = 30;
private static readonly int C1 = 11;
private static readonly int E3 = 24;
private static readonly int H2 = 39;
private static readonly int R1 = 5;
private static readonly int[] Community = [2, 17, 33];
// Next corresponds to Chance
private static readonly int[] Chance = [7, 22, 36];
private static readonly int[] NextRailway = [15, 25, 5];
private static readonly int[] NextUtility = [12, 28, 12];
// record the counts
int[] board = new int[40];
Random random = new();
int doubles = 0;
int current = 0;
// position of special card
int chanceIndex = 0;
int communityIndex = 0;
for (int i = 0; i < Rolls; i++)
{
int dice1 = random.Next(1, 5);
int dice2 = random.Next(1, 5);
// handle scenario: double
doubles = (dice1 == dice2) ? doubles + 1 : 0;
if (doubles > 2)
{
current = Jail;
doubles = 0;
}
else
{
// move forward
current = (current + dice1 + dice2) % 40;
// handle Chance
if (current == Chance[0] || current == Chance[1] || current == Chance[2])
{
// use special card
chanceIndex++;
chanceIndex %= 16;
// go to Railway or Utility
int index = 0;
if (current == Chance[1])
{
index = 1;
}
else if (current == Chance[2])
{
index = 2;
}
switch (chanceIndex)
{
case 0:
current = Go;
break;
case 1:
current = Jail;
break;
case 2:
current = C1;
break;
case 3:
current = E3;
break;
case 4:
current = H2;
break;
case 5:
current = R1;
break;
case 6:
case 7:
current = NextRailway[index];
break;
case 8:
current = NextUtility[index];
break;
case 9:
current -= 3;
break;
}
}
// handle Community Chest
if (current == Community[0] || current == Community[1] || current == Community[2])
{
switch (communityIndex)
{
case 0:
current = Go;
break;
case 10:
current = Jail;
break;
}
communityIndex++;
communityIndex %= 16;
}
if (current == Go2Jail)
{
current = Jail;
}
}
board[current]++;
}
int[] order = board.Select((item, indx) => new { Item = item, Index = indx })
.OrderByDescending(x => x.Item)
.Select(x => x.Index)
.ToArray();
string modalString = "";
for (int i = 0; i < 3; i++)
{
if (order[i] < 10)
{
modalString += "0";
}
modalString += order[i].ToString();
}