【问题标题】:Monty Hall Game蒙蒂霍尔游戏
【发布时间】:2014-10-10 18:00:45
【问题描述】:

我是一名新程序员,目前正在学习 Java。我在这里有一个基于游戏 Let's make a deal & monty hall 问题 (https://www.youtube.com/watch?v=mhlc7peGlGg) 的游戏,我一直遇到此代码的逻辑问题。一切似乎都正常,除了我似乎无法让 user_door 切换到另一扇门并确定他们是否正确地成为赢家。如果有人可以帮助我理解我在这里做错了什么,我很乐意借此机会学习,谢谢!

import java.util.Random;
import java.util.Scanner;
public class GameShow {

public static void main(String[] args) {
    Scanner scan = new Scanner (System.in);
    Random generator = new Random();

    // Initialize Variables
    int user_door,
        open_door,
        other_door,
        prize_door;

    // Generate random value 1-3
    prize_door = generator.nextInt(3)+1;
    open_door = prize_door;

    while(open_door == prize_door){
        open_door = generator.nextInt(3)+1;
    }

    other_door = open_door;

    while (other_door == open_door || other_door == prize_door){
        other_door = generator.nextInt(3)+1;
    }

    // Begin Game
    System.out.println("*** Welcome to the game show! ***");  
    System.out.println("Select the door (1, 2, or 3): ");
    user_door = scan.nextInt();


    // User Validation
        if (user_door > 3 || user_door < 0) {
            System.out.println("Please select door 1, 2, or 3");
            user_door = scan.nextInt();
        } else if(user_door == 1 || user_door == 2 ||  user_door == 3) {

    //Continue Game
    System.out.println("\nIn a moment, I will show you where the prize is located,");
    System.out.println("but first I will show you what is behind one of the other doors");

    //Continue Dialogue
    System.out.println("\nBehind door number " + open_door + " are goats!");
    System.out.println("You selected door number " + user_door);
    System.out.println("\nWould you like to switch your door(y/n)? ");

    //User Input Yes or No
    char userReply = scan.next().charAt(0);

    //If statement with nested while statements for user input
        if (userReply == 'y'){
                user_door = other_door;
                } while(userReply != 'y' && userReply != 'n')
                {
                    //User Validation
                    System.out.println("Please enter either y/n");
                    userReply = scan.next().charAt(0);
                } 

    System.out.println("The prize is behind door number: " + prize_door); 

    //Check to see if user won or lost
        if(user_door == prize_door){
            System.out.println("Congratulations! You won the prize!");
            } else {
                    System.out.println("Sorry. You lost.");
                    }       

        }
    }
}

【问题讨论】:

  • 您是否尝试过附加调试器并逐行逐行执行代码,以查看程序究竟在哪一点偏离了您对它应该做什么的期望?
  • 你在使用 Eclipse 吗?
  • 我目前正在对您的工作进行代码审查。跟踪问题的时间有点长,所以我会在几分钟内解释一些您可以优化的内容。
  • 如果您使用的是 Eclipse,要查看变量,请转到 Window -> Show View -> Variables,或者按 Alt+Shift+Q,V
  • 如果您担心班上的其他人共享您的代码,请不要在 Internet 上的公共站点上发布您的代码。在您得到答案后试图编辑所有相关人员的答案以避免其他人学习您所做的相同事情是违反 SO 政策的。除此之外,人们也可以通过查看编辑历史来查看源代码。

标签: java logic probability


【解决方案1】:

我同意 Srikanth 上面所说的。缺少的是您测试用户回复的部分。您应该切换“if”和“while”语句。这将有助于解决您的门开关问题。

之前

 if (userReply == 'y')
     {
     user_door = other_door;
     }  
 while(userReply != 'y' && userReply != 'n')
     {
     //User Validation
     System.out.println("Please enter either y/n");
     userReply = scan.next().charAt(0);
     } 

改成

 while(userReply != 'y' && userReply != 'n')
    {
        //User Validation
        System.out.println("Please enter either y/n");
        userReply = scan.next().charAt(0);
    }
 if (userReply == 'y')
    {
     user_door = other_door;
    } 

您执行此操作的方式仅检查第一次输入字符的时间。如果他们做错了并试图再做一次,那么它不会切换门,因为你已经通过了程序的那部分。

【讨论】:

  • 感谢您的提示!
【解决方案2】:

您永远不会正确分配另一扇门。您分配的另一扇门是一个随机数,而且您的实现也没有正确描述蒙蒂霍尔问题。

一个破坏程序的例子

假设奖品门 = 1,打开门 = 2,然后其他门 = 3 默认情况下。

假设用户选择了 2 号门。那么,当 2 号门打开时,实际上还有 2 个可能的其他门:1 号和 3 号。

Monty Hall 问题的一个关键部分是打开了一扇用户没有选择的门。

当你选择用户的门时,你需要确定other_door是什么。这段代码有点难以理解,所以我将回顾一下我在尝试找到您的问题时发现的一些问题。

奖门生成

// Generate random value 1-3
prize_door = generator.nextInt(3)+1; //assigns a value to the prize
open_door = prize_door;

while(open_door == prize_door){
    open_door = generator.nextInt(3)+1; //assigns a value to the door to open, not the prize
}

other_door = open_door;

while (other_door == open_door || other_door == prize_door){
    other_door = generator.nextInt(3)+1; //assigns the last value to this
}

此代码正确分配了prize_door,但其余部分还不需要完成。我们可以将其实现简化为。

prize_door = generator.nextInt(3) + 1; //we know what the prize is

这比 3 个变量更容易管理,并且对随机性的依赖性更小。我们只需要跟踪选择者的门,以及奖品后面的门。

打开用户的大门

user_door = -1; //instantiate to -1 here

// User Validation
while (user_door > 3 || user_door < 0) {
    System.out.println("Please select door 1, 2, or 3");
    user_door = scan.nextInt();
}

如果我在被告知不要输入 4 后尝试输入,您的用户验证将失败。您应该将它们锁定在循环中,直到它们选择一扇门。

这也消除了您对 if 的需求,因为一旦离开循环,数字将是 1、2 或 3

开门

此时,我们已经实例化了两个数字。

System.out.println("\nBehind door number " + open_door + " are goats!");
System.out.println("You selected door number " + user_door);

在最初的 Monty Hall 游戏中,您应该打开一扇选择者尚未选择的门。用户的门永远不会打开。在这种情况下,我们有两个输入,user_door 和 Prize_door 使用俗气的逻辑,我们可以通过将它们加在一起来确定打开哪扇门,或者你可以做一个 true if 来验证。我会介绍俗气的,因为它写起来更快而且仍然有意义。

if(prize_door + user_door == 4) { // 1 and 3
    open_door = 2;
}
else if(prize_door + user_door == 5) { // 2 and 3
    open_door = 1;
}
else { //1 and 2
    open_door = 3;
}

非俗气的选项是:

boolean oneIsTaken = false;
boolean twoIsTaken = false;

if(prize_door == 1 || user_door == 1) {
    oneIsTaken = true;
}
if(prize_door == 2 || user_door == 2) {
    twoIsTaken = true;
}

if(oneIsTaken && twoIsTaken) {
    open_door = 3;
}
else if(oneIsTaken) {
    open_door = 2;
}
else {
    open_door = 1;
}

获得可以切换到的门

使用打开的门和用户的原始门,我们可以选择切换的门,因为这两个不是你要切换的门。

if(open_door + user_door == 4) { // 1 and 3
    user_door = 2;
}
else if(open_door + user_door == 5) { // 2 and 3
    user_door = 1;
}
else { //1 and 2
    user_door = 3;
}

判断用户是否中奖

和以前一样:

    if(user_door == prize_door){
        System.out.println("Congratulations! You won the prize!");
        } else {
                System.out.println("Sorry. You lost.");
                }       

    }

这个没有问题。

【讨论】:

  • 感谢您的帮助!我会尝试解决这个问题并尝试实现它
  • 但是……这也是错误的。 A:整个实现,无论是俗气还是不俗气,都没有考虑到用户在第一次时选择了正确门的场景。如果我选择2号门,后面也有奖品,那么if(prize_door + user_door == 4) { // 1 and 3 open_door = 2; }那扇门也会打开! B:如果您选择了正确的门,则应随机选择其他两扇门中的一扇。如果我选择门 2,门 3 打开,我知道奖品在门 1 后面,因为如果奖品也在门 2 后面,门 1 就会打开!
【解决方案3】:

我已经做了一些代码优化,重要的是我已经解决了它。您在代码中犯的错误将在下面解释。

import java.util.Random;
import java.util.Scanner;

public class table {

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        Random generator = new Random();

        // Initialize Variables
        int user_door, open_door, other_door, prize_door;

        // Generate random value 1-3
        prize_door = generator.nextInt(3) + 1;
        other_door = prize_door;

        // Begin Game
        System.out.println("*** Welcome to the game show! ***");

        // User Validation
        do{
            System.out.println("Select the door (1, 2, or 3): ");
            user_door = scan.nextInt();
        }while(user_door > 3 || user_door < 0);
        do{
            open_door = generator.nextInt(3)+1;
        }while(open_door == prize_door || open_door == user_door);

        System.out.println("\nIn a moment, I will show you where the prize is located,");
        System.out.println("but first I will show you what is behind one of the other doors");
        System.out.println("\nBehind door number " + open_door+ " are goats!");
        System.out.println("You selected door number " + user_door);
        char userReply;
        do{
            System.out.println("\nWould you like to switch your door(y/n)? ");
            userReply = scan.next().charAt(0);
        }while(userReply!='y' && userReply!='n');       

        int user_duplicate = user_door;
        if (userReply == 'y') {
            do{
                user_door = generator.nextInt(3)+1;
            }while(user_door == open_door || user_door == user_duplicate);
        }

        System.out.println("The prize is behind door number: " + prize_door);

        if (user_door == prize_door) {
            System.out.println("Congratulations! You won the prize!");
        } else {
            System.out.println("Sorry. You lost.");
        }
    }
}

在获得user_door 之前,您应该只分配prize_door,获得user_door 之后,您必须分配open_door,如果您选择换门,还必须分配other_door

【讨论】:

  • 根据您的建议,我现在可以正常工作了,我看到了我的错误所在,非常感谢您的帮助!
  • 好@Lowki,顺便说一句,在您的其他Java程序中使用do while循环,因为它对最小化您的代码非常有帮助。
【解决方案4】:

让我们通过示例逐步了解您的代码的作用

import java.util.Random;
import java.util.Scanner;
public class GameShow {

public static void main(String[] args) {
Scanner scan = new Scanner (System.in);
Random generator = new Random();

// Initialize Variables
int user_door,
    open_door,
    other_door,
    prize_door;

// Generate random value 1-3
prize_door = generator.nextInt(3)+1; 

假设生成器将 2 分配给 price_door

open_door = prize_door;

while(open_door == prize_door){
    open_door = generator.nextInt(3)+1;
}

让我们假设在循环之后生成器将 1 分配给 open_door

other_door = open_door;

while (other_door == open_door || other_door == prize_door){
    other_door = generator.nextInt(3)+1;
}

让我们假设在循环之后生成器将 3 分配给 other_door

// Begin Game
System.out.println("*** Welcome to the game show! ***");  
System.out.println("Select the door (1, 2, or 3): ");

让我们回忆一下变量的值 open_door = 1other_door = 3prize_door = 2

user_door = scan.nextInt();
// User Validation
    if (user_door > 3 || user_door < 0) {
        System.out.println("Please select door 1, 2, or 3");
        user_door = scan.nextInt();
    } else if(user_door == 1 || user_door == 2 ||  user_door == 3) {

假设用户输入 1 user_door = 1

//Continue Game
System.out.println("\nIn a moment, I will show you where the prize is located,");
System.out.println("but first I will show you what is behind one of the other doors");

//Continue Dialogue
System.out.println("\nBehind door number " + open_door + " are goats!");

在这里,您正在打开与user_door = 1 相同的门 1 (open_door = 1)

根据游戏逻辑哪个是错误的

System.out.println("You selected door number " + user_door);
System.out.println("\nWould you like to switch your door(y/n)? ");

//User Input Yes or No
char userReply = scan.next().charAt(0);

//If statement with nested while statements for user input
    if (userReply == 'y'){
            user_door = other_door;
            } while(userReply != 'y' && userReply != 'n')
            {
                //User Validation
                System.out.println("Please enter either y/n");
                userReply = scan.next().charAt(0);
            } 

System.out.println("The prize is behind door number: " + prize_door); 

//Check to see if user won or lost
    if(user_door == prize_door){
        System.out.println("Congratulations! You won the prize!");
        } else {
                System.out.println("Sorry. You lost.");
                }       

    }
}
}

您需要根据用户的输入更改门的选择,因为作为主持人,您知道汽车/黄金在哪里以及程序中缺少的山羊在哪里

您应该在游戏开始前修复prize_door,您正在做的正确但open_doorother_door应该根据user_door来决定

【讨论】:

  • 好吧,我可以看到我错过了对用户输入的测试,为此我可以像使用 prize_door 一样使用 while 循环,对吗?另外,感谢您抽出宝贵时间提供帮助!欣赏它
  • 您的印象是主持人(程序)不应该知道奖品和山羊在哪里,这是不正确的。主人总是知道奖品在哪里,山羊在哪里,所以应该第一次使用生成器来修复奖品门,稍后根据奖品门确定其他两个门(不需要循环和生成器)直接使用它们不需要对于循环和生成器,一个简单的 if 将完成类似 IF (prize_door == 1) other_doors[] = {2,3} 的工作
  • 我现在明白我的错误在哪里,感谢您帮助我更好地掌握这一点! :)
【解决方案5】:

很多答案,很多东西被指出是错误的或无效的(但不知何故,没有人会以这种方式随机化 3 个元素,而不是仅仅基于随机化器将它们改组一次),但没有人明确地解决了这个问题:“。 ..除了我似乎无法让 user_door 切换到另一扇门..”

三个门标记为prize_dooropen_doorother_dooruser_door 可以是其中任何一个。这是错误的,但无论如何。

if (userReply == 'y')
    user_door = other_door;

这里使用的语句将user_door更改为other_door(非奖品闭门)的具体值,而不考虑user_door的值是什么。它应该将其从 prize_door 更改为 other_door,反之亦然。

if (userReply == 'y')
{
    if (user_door == other_door)
        user_door = prize_door;
    else
        user_door = other_door;
}

除非user_door == open_door的情况,确实不应该存在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-13
    • 2012-10-18
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 1970-01-01
    • 2010-11-17
    • 2021-03-29
    相关资源
    最近更新 更多