You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:55:28