首页 > 解决方案 > 如何使用条件和循环来模拟 Monty Hall 问题?

问题描述

我开始学习编程,现在正在使用 c 和条件循环。我想对蒙蒂大厅的车后门问题进行交互式模拟(3扇门中的一扇后面有一辆车,另外两扇有山羊。用过的挑选一扇后,蒙蒂揭示了其他一扇后面有山羊它并允许用户切换到另一扇门)。根据我从 C Programming 中读到的 KN King 的现代方法,这应该可以通过一些函数、条件和循环来实现。但是我编写的代码在我的一个函数中无限循环,我不确定为什么,这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// A function that gets a valid door input from the user
int chooseDoor(){
    int choice = 0;
    while(choice < 1 || choice > 3){
        printf("Choose a door from 1 to 3: ");
        scanf("%d",&choice);
        printf("%d\n", choice);
    }
    return choice;
    }
// A function to get a valid yes or no response from the user
int validateYn(){
    char yn[1];
    fgets(yn,1,stdin);
    while(yn[0] != "Y" && yn[0] != "y" && yn[0] != "N" && yn[0] != "n"){
        printf("Error: Please enter Y or N: ");
        fgets(yn,1,stdin);}
    if(yn[0] == "Y" || yn[0] == "y"){
        return 1;}
    else{
        return 0;}}
int main(){
    bool play = true; //conditional boolean to repeat the game
    while(play){
        int car, shown, other, choice; //initialisers for the door with the car, door that monty will reveal, the remaining door and door chosen by player
        bool swap;
        car = rand()%3; //select a random door between 1 and 3
        choice = chooseDoor(); //call function to get user input of chosen door
        printf("You picked door #%d", choice);
        // A loop to find the lowest door that is not picked by the user and has a goat behind it
        for(int i = 0; i<3; ++i){
            if( i == car || i == choice){
                continue;}
            shown = i;
            break;}
        // A loop to find the remaining door besides the one revealed and the one user picks
        for(int i = 0; i<3; ++i){
            if( i == car || i == choice || i == shown){
                continue;}
            other = i;
            break;}
        printf("Monty opens door #%d, there's a goat!\nWould you like to switch to door #%d?", shown, other);
        swap = validateYn();
        // Change user choice if user says yes to swap
        if(swap){
            choice = other;}
        // win if user choice had car, lose otherwise 
        if(choice == car){
            printf("Monty opens door #%d, it's the car! You win!", car);}
        else{
            printf("Monty opens door #%d, there's a goat. You lose.", choice);}
        } 
        printf("Would you like to play again?");
        play = validateYn();
return 0;}

我的朋友还告诉我,switch语句应该会让事情变得更容易,但我不知道如何正确使用它们,谢谢

标签: cloopsconditional-statements

解决方案


您的代码中只有一个问题:您询问用户是否想在循环之外继续。有时它会发生,这不是很难解决的。您只需将最后一个用户交互代码块(最后一个 printf 和最后一个 scanf)移动到 while 循环括号内。

我将在此处附上完全有效的代码。我还做了一些更新和更改:

  • 更改了循环迭代。而不是 0..<3; ++i 现在是 1..<4; 我++
  • 用 getchar 更改了 fget,因为您只输入一个字符而不是字符串。
  • 添加了一个 fflush(stdin) 以释放输入缓冲区,然后您获取一个字符,因为当您获取不同类型的输入时,scanf 可能会发疯并显示混乱的结果。
  • 改变了随机性。现在种子将用 srand 和 time 改变每次迭代
#include <stdio.h>
#include <stdlib.h>
#include <time.h> 
#include <stdbool.h>

// A function that gets a valid door input from the user
int chooseDoor()
{
    int choice = 0;
    while (choice < 1 || choice > 3)
    {
        printf("Choose a door from 1 to 3: ");
        scanf("%d", &choice);
    }
    return choice;
}

// A function to get a valid yes or no response from the user
int validateYn()
{
    char yn;
    yn = getchar();
    while (yn != 'Y' && yn != 'y' && yn != 'N' && yn != 'n')
    {
        printf("Error: Please enter Y or N: ");
        yn = getchar();
    }
    if (yn == 'Y' || yn == 'y')
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

int main()
{
    srand((unsigned int) time(NULL)); // generating number with better randomness
    bool play = true; //conditional boolean to repeat the game
    while (play)
    {
        int car, shown, other, choice; //initialisers for the door with the car, door that monty will reveal, the remaining door and door chosen by player
        bool swap;

        car = 1 + rand() % 3;      //select a random door between 1 and 3
        choice = chooseDoor(); //call function to get user input of chosen door
        printf("You picked door #%d", choice);
        // A loop to find the lowest door that is not picked by the user and has a goat behind it
        for (int i = 1; i < 4; i++) 
        {
            if (i == car || i == choice)
            {
                continue;
            }
            shown = i;
            break;
        }
        // A loop to find the remaining door besides the one revealed and the one user picks
        for (int i = 1; i < 4; i++)
        {
            if (i == car || i == choice || i == shown)
            {
                continue;
            }
            other = i;
            break;
        }
        printf("\nMonty opens door #%d, there's a goat!\nWould you like to switch to door #%d? (y/n).\nChoose: ", shown, other);
        fflush(stdin);
        swap = validateYn();
        // Change user choice if user says yes to swap
        if (swap)
        {
            choice = other;
        }
        // win if user choice had car, lose otherwise
        if (choice == car)
        {
            printf("\nMonty opens door #%d, it's the car! You win!", car);
        }
        else
        {
            printf("\nMonty opens door #%d, there's a goat. You lose. ", choice);
        }
        printf("\n\nWould you like to play again?"); //here now it is inside the while loop
        play = validateYn();
    }
    return 0;
}

提示:尽量用缩进更清楚一点。下次您将能够轻松地捕捉到这种“括号和范围错误”。

此外,这是真的,您可以使用开关来执行此程序以使其变得容易。它们并不难使用。祝你好运!!

-丹尼


推荐阅读