Monty Hall问题模拟Java程序输出异常,请求排查代码问题
Monty Hall问题Java模拟程序错误排查
我做了一个模拟Monty Hall悖论的Java练习项目,但输出结果不符合预期。Monty Hall悖论规则:游戏中有三扇门,一扇后是汽车,另外两扇是山羊。玩家选一扇门后,主持人(知道门后情况)打开一扇有山羊的门,然后问玩家是否换门。理论上换门的胜率是2/3,不换是1/3,但我的程序每次运行结果(误差±1%)如下:
Games where initial choice was changed: Won: 49% Lost: 50% Games where initial choice was not changed: Won: 49% Lost: 50%
以下是我的代码,请帮忙找出问题:
Main类代码
public class Main { public static void main(String[] args) { int won = 0; int lost = 0; int wonChanged = 0; int lostChanged = 0; int passes = 100000; for (int i = 0; i < passes; i++) { MontyHall problem = new MontyHall(); int choice = problem.getRandom(); if (problem.isCar(choice)) { won++; } else { lost++; } } for (int i = 0; i < passes; i++) { MontyHall problem = new MontyHall(); int choice = problem.getRandom(); int hostChoice = problem.hostChoice(); // Choice is changed choice = problem.otherDoor(choice, hostChoice); if (problem.isCar(choice)) { wonChanged++; } else { lostChanged++; } } System.out.println("1,000,000 tests were done for each case. These are the results:\n"); System.out.println("Games where initial choice was changed: " + "\nWon: " + wonChanged / (passes / 100) + "%" + "\nLost: " + lostChanged / (passes / 100) + "%"); System.out.println("\nGames where initial choice was not changed: " + "\nWon: " + won / (passes / 100) + "%" + "\nLost: " + lost / (passes / 100) + "%"); } }
MontyHall类代码
public class MontyHall { private char[] doors; private final char car = 'C'; private final char goat = 'G'; public MontyHall() { doors = new char[3]; // Puts car behind a random door int index = getRandom(); doors[index] = car; // Puts goats behind the other two doors for (int i = 0; i < doors.length; i++) { if (doors[i] != car) { doors[i] = goat; } } } public int getRandom() { Random rand = new Random(); return rand.nextInt(2) + 1; } public int hostChoice() { int index = getRandom(); // Ensures the host opens a goat door while (doors[index] != goat) { index = getRandom(); } return index; } public int otherDoor(int a, int b) { int newChoice = 0; for (int i = 0; i < doors.length; i++) { if (!(doors[i] == a || doors[i] == b)) { newChoice = i; } } return newChoice; } public boolean isCar(int i) { return (doors[i] == car); } }
错误分析及修正
1. getRandom()方法范围错误
当前getRandom()返回rand.nextInt(2)+1,只会生成1或2,但数组doors的索引是0、1、2,这导致:
- 初始化时永远不会把汽车放在索引0的门
- 玩家永远选不到索引0的门,直接破坏了三扇门的概率模型
修正:让随机数覆盖三扇门的索引:
public int getRandom() { Random rand = new Random(); return rand.nextInt(3); // 生成0、1、2,对应三扇门的索引 }
2. hostChoice()方法未排除玩家选择的门
主持人核心规则是不能打开玩家已选的门,当前代码只判断门后是山羊,允许打开玩家选的门(如果玩家选的是山羊),完全不符合游戏规则,导致换门逻辑失效。
修正:传入玩家选择,排除该门后再选山羊门:
// 修改方法参数,传入玩家选择 public int hostChoice(int playerChoice) { int index; do { index = getRandom(); // 主持人不能选玩家的门,也不能选有汽车的门 } while (index == playerChoice || doors[index] == car); return index; }
同时在Main类调用时传入玩家选择:
int hostChoice = problem.hostChoice(choice);
3. otherDoor()方法逻辑完全错误
当前代码把char类型的门内容和int类型的门编号做比较,完全不匹配。正确逻辑是找到既不是玩家选的门,也不是主持人打开的门,应该比较门的索引(编号)而非门后内容。
修正:
public int otherDoor(int playerChoice, int hostChoice) { for (int i = 0; i < doors.length; i++) { if (i != playerChoice && i != hostChoice) { return i; } } return -1; // 理论上不会执行到这里 }
4. 输出统计的整数除法精度问题
当前wonChanged / (passes / 100)是整数除法,会截断小数部分,改为浮点数除法可以提升显示精度:
// 示例:用格式化字符串输出百分比 String changedWinRate = String.format("%.1f%%", (double)wonChanged / passes * 100); String noChangeWinRate = String.format("%.1f%%", (double)won / passes * 100);
修正后的预期结果
修正后运行程序,应该得到符合理论的结果:
Games where initial choice was changed: Won: ~67% Lost: ~33% Games where initial choice was not changed: Won: ~33% Lost: ~67%
内容的提问来源于stack exchange,提问作者daytripper
相关产品推荐
相关产品推荐

