1

I'm starting to learn programming and am working with c and conditional loops right now. And I wanted to make an interactive simulation of the Monty hall car behind doors problem(One of the 3 doors has a car behind it, the other 2 have goats. After the used picks one, Monty reveals one of the others with the goat behind it and allows the user to switch to the other door). According to what I've read from C Programming a modern approach by K.N. King, this should be possible with a few functions, conditionals and loops. But The code I've written loops infinitely in one of my functions and I'm not sure why, here's my code:

#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;}

My friend also told me that a switch statement should make things easier, but I have no idea how to use them right, thanks

PileUp120
  • 13
  • 2

1 Answers1

1

there is only one problem in your code: you ask to the user if he wants to continue outside of the loop. Sometimes it happens, that's nothing so difficult to solve. You just need to move the last user interaction block of code (last printf and last scanf), inside the while loop brackets.

I'm going to attach you here the code that fully works. I also made some update and changes:

  • Changed for loops iteration. Instead of 0..<3; ++i now is 1..<4; i++
  • Changed the fgets with a getchar, since you are taking in input only one char and not a string.
  • Added a fflush(stdin) to free input buffer after that you take a char, since when you take different kind of input, the scanf could go crazy and show up messy result.
  • Changed the randomness. Now the seed will change each iteration with srand and 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;
}

Tip: Try to be a little bit more clear with indentation. You will be able to catch this kind of "brackets and scope errors" easily next time.

Furthermore that's true you could do this program with a switch to make it easy. They aren't so difficult to use. Good Luck!!

-Denny

D. Caruso
  • 163
  • 2
  • 9
  • 1
    Great code, but small remarks: `srand((unsigned int) time(NULL));` is called in a loop. `fflush(stdin);` is undefined behavior. – KamilCuk Jan 30 '20 at 11:32
  • Thank you for suggestion, just moved the srand(...) outside the loop. What do you mean with undefined behavior about the fflush? @KamilCuk – D. Caruso Jan 30 '20 at 11:38
  • [Using fflush(stdin)](https://stackoverflow.com/questions/2979209/using-fflushstdin) – KamilCuk Jan 30 '20 at 11:39