蒙提霍尔问题模拟出现50/50概率异常,求代码问题排查
蒙提霍尔问题模拟代码bug排查
我计划开发蒙提霍尔问题的完整游戏作为副业项目,先做批量模拟来验证换门胜率应为66%,但3门场景下每次模拟都得到约50/50的概率,增加门数后换门胜率才上升。附上C#模拟代码,请求帮忙找出问题所在。
private void simulateButton_Click(object sender, EventArgs e) { int wins = 0; int losses = 0; int attempts = 0; int numberOfDoors = 3; // Main game loop. Number of simulations can easily be changed from 1000 for (int games = 0; games < 1000; games++) { List<Door> doors = new List<Door>(); for (int i = 0; i < numberOfDoors; i++) { doors.Add(new Door { Contents = "goat", Opened = false, PlayerChoice = false, }); } // Randomly pick a door for the car to be in Random random = new Random(); int doorNumWithCar = random.Next(0, numberOfDoors - 1); doors[doorNumWithCar].Contents = "car"; // I set player choice to always be door #1 to make it simpler doors[0].PlayerChoice = true; // Monty randomly removes one of the 2 doors not chosen by the player. // (obviously, he doesn't remove the door with the car) int doorMontyOpens; while (doors.Count != 2) { doorMontyOpens = -1; while (doorMontyOpens == -1) { int possibleDoorToBeShown = random.Next(1, doors.Count); if (doors[possibleDoorToBeShown].Contents != "car") { doorMontyOpens = possibleDoorToBeShown; } } // I just remove the door since that is essentially what Monty Hall is doing when // He reveals one of the goats doors.RemoveAt(doorMontyOpens); } // Since player choice is always door #1 (index 0) and there are only two doors left, // we only need to check door #2 at index 1. If it has the car, it is a win. If not, a loss. // This simulation only tests the case in which the player changes doors after Monty reveals // a door. So it SHOULD usually have about 667 wins and 333 losses. Why do I get 50/50??? if (doors[1].Contents == "car") { wins++; } else { losses++; } attempts++; this.winsTextbox.Text = $"{wins}"; this.lossesTextbox.Text = $"{losses}"; this.attemptsTextbox.Text = $"{attempts}"; } MessageBox.Show("Done!"); } public class Door { public string Contents { get; set; } public bool Opened { get; set; } public bool PlayerChoice { get; set; } }
问题根源
随机数范围错误
设置汽车所在门的代码int doorNumWithCar = random.Next(0, numberOfDoors - 1);存在逻辑错误。Random.Next(int minValue, int maxValue)是左闭右开区间,当numberOfDoors=3时,该调用仅会生成0或1,永远不会选中索引为2的第三扇门。这导致汽车只能出现在前两扇门中:- 汽车在0号门(玩家初始选择):Monty随机移除1或2号山羊门,换门后必然失败;
- 汽车在1号门:Monty只能移除2号山羊门,换门后必然成功;
两种情况各占50%概率,最终换门胜率自然是50%,与预期的66%不符。
循环内重复创建Random实例
在每次游戏循环中创建Random random = new Random();,由于Random默认使用系统当前时间作为种子,循环执行速度极快时,多次创建的Random会使用相同种子,导致生成的随机数重复,进一步影响模拟结果的准确性。
修复方案
- 将
Random实例移到游戏循环外,避免重复创建; - 修正随机数范围,确保覆盖所有门的索引:
private void simulateButton_Click(object sender, EventArgs e) { int wins = 0; int losses = 0; int attempts = 0; int numberOfDoors = 3; // 将Random实例移到循环外,确保随机数序列正常生成 Random random = new Random(); for (int games = 0; games < 1000; games++) { List<Door> doors = new List<Door>(); for (int i = 0; i < numberOfDoors; i++) { doors.Add(new Door { Contents = "goat", Opened = false, PlayerChoice = false, }); } // 修正随机数范围,覆盖0到numberOfDoors-1的所有索引 int doorNumWithCar = random.Next(0, numberOfDoors); doors[doorNumWithCar].Contents = "car"; // ... 其余代码保持不变 ... } MessageBox.Show("Done!"); }
内容的提问来源于stack exchange,提问作者mattjr747
相关产品推荐
相关产品推荐

