Is this an elegant/accurate simulation of the Monty Hall problem? I'm trying to simulate the Monty Hall problem, to statistically determine if there is any benefit to changing my choice after a door containing a goat is open (testing this guy's Monty Hall theory on YouTube).

So, does this manage to simulate it properly? (Just for the curious: Changing doors doesn't seem to have any benefit, but I want to make sure my simulator isn't flawed).  I also want style help, if possible!

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;time.h&gt;

#define DOOR_COUNT 3
#define TEST_COUNT 1000000

void InitRandom();
int RunTest(char change);
void RandomizeDoors();
int GetRandom(int floor, int roof);
void OpenGoatDoor (int choice);
int OtherDoor (int choice);
int ChoiceWasCar(int choice);

char doors[DOOR_COUNT+1];

int main (const char argc, const char **argv)
{
    int run[2], yes[2];
    InitRandom();

    run[0] = 0;
    run[1] = 0;
    yes[0] = 0;
    yes[1] = 0;
    // Control Group
    for (int i = 0; i &lt; TEST_COUNT; i++ ) {
        run[0]++;
        yes[0] += RunTest(0);
    }
    for (int i = 0; i &lt; TEST_COUNT; i++ ) {
        run[1]++;
        yes[1] += RunTest(1);
    }
    printf("Control Group:\n\t%d tests run\n\t%d yes.\n\n", run[0], yes[0]);
    printf("Other Group:\n\t%d tests run\n\t%d yes.\n\n", run[1], yes[1]);
}

void InitRandom()
{
    unsigned int iseed = (unsigned int)time(NULL);
    srand (iseed);
}

int RunTest(char change)
{
    RandomizeDoors();
    int choice = GetRandom(1, DOOR_COUNT);
    //printf("Choice is: %d\n", choice);
    OpenGoatDoor(choice);
    if (change) {
        choice = OtherDoor(choice);
    }
    return ChoiceWasCar(choice);
}

void RandomizeDoors()
{
    char n = GetRandom(1,DOOR_COUNT);
    for (int i = 0; i &lt;= DOOR_COUNT; i++) {
        doors[i] = n == i ? 1 : 0;
        //printf("Door %d is %d\n", i, doors[i]);
    }
//  printf("\n");
}

int GetRandom(int floor, int roof)
{
    int n;
    n = (rand()%(roof-floor));
    n += floor;
    return n;
}

void OpenGoatDoor (int choice)
{
    int doorCur = GetRandom(1, DOOR_COUNT);
    while ( doors[doorCur] == 1 || doorCur == choice ) {
        if (doorCur &gt; DOOR_COUNT) {
            doorCur = GetRandom(1, DOOR_COUNT);
        } else {
            doorCur++;
        }
    }
    //printf("Opened Door is %d\n", doorCur);
    doors[doorCur] = -1;
}

int OtherDoor (int choice)
{
    int doorCur = 1;
    while ( doorCur == choice || doors[doorCur] == -1 ) {
        doorCur++;
    }
    return doorCur;
}

int ChoiceWasCar(int choice)
{
    return doors[choice] == 1;
}
ok, so i ended up changing more than was strictly necessary, sorry.  as you probably know, it does pay to change doors, so your code did have a bug.  i didn't try to trace it down exactly, but i assume it was related to you having 4 doors instead of 3, which i guess was because you had

for (int i = 0; i &lt;= DOOR_COUNT; i++) {


instead of

for (int i = 0; i &lt; DOOR_COUNT; i++) {


in C you always start from 0 and use &lt; in loops.  it's the law.

[in general your code is super neat and pretty good.  you had a muddle with array indexing, which is very common, and didn't make use of enum, but apart from that, it was nice code.  edit: also, your general approach was fine.  this is a good way to test the problem.]

some other issues were:


the random number generation was strangely general, yet always picked a door.  it also started from 1, which i guess is related to the confusion over door array indexing.
it wasn't clear to me what the doors array contained at first.  when i understood i clarified it with an enum.
it wasn't clear to me what the two groups were ("control" didn't explain things).  when i understood i clarified things with another enum (note the GROUP_COUNT trick which gives the number of entries in the enum, excluding that).
given the group enum, there's no need to have two print statements - we can use an array of group names.  and there's no need for arrays of results, since we have everything in a loop now.
i clarified the logic in OpenGoatDoor - the code initialises the door to choice, which we know is "bad" so that the while is triggered and so we only need a single call to RandomDoor.
i tried to clarify the logic in OtherDoor but i am not sure i helped.
i don't think ChoiceWasCar is necessary - with the enum it's pretty clear what return doors[choice] == car means.


here's the modified code.  thanks for posting - i was bored and this was interesting to look at.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;time.h&gt;

#undef DEBUG
#define DOOR_COUNT 3
#define TEST_COUNT 1000000

typedef enum {goat, car, opened} door;
door doors[DOOR_COUNT];

typedef enum {nochange, change, GROUP_COUNT} group;
char *groupName[GROUP_COUNT] = {"No Change", "Change"};

void InitRandom();
int RunTest(group g);
void RandomizeDoors();
int RandomDoor();
void OpenGoatDoor(int choice);
int OtherDoor(int choice);

int main (void)
{
  InitRandom();

  for (group g = 0; g &lt; GROUP_COUNT; ++g) {
    int wins = 0;
    for (int i = 0; i &lt; TEST_COUNT; ++i) {
      wins += RunTest(g);
    }
    printf("%s:\n\t%d tests run\n\t%d win car.\n\n", 
           groupName[g], TEST_COUNT, wins);
  }
  return 0;
}

void InitRandom()
{
  unsigned int iseed = (unsigned int)time(NULL);
  srand (iseed);
}

int RunTest(group g)
{
  RandomizeDoors();
  int choice = RandomDoor();
  #ifdef DEBUG
  printf("Choice is: %d\n", choice);
  #endif
  OpenGoatDoor(choice);
  if (g == change) {
    choice = OtherDoor(choice);
  }
  return doors[choice] == car;
}

void RandomizeDoors()
{
  char carDoor = RandomDoor();
  for (int i = 0; i &lt; DOOR_COUNT; i++) {
    doors[i] = carDoor == i ? car : goat;
    #ifdef DEBUG
    printf("Door %d is %d\n", i, doors[i]);
    #endif
  }
  #ifdef DEBUG
  printf("\n");
  #endif
}

int RandomDoor()
{
  // this is very slightly biased, but we don't care.
  return rand() % DOOR_COUNT;
}

void OpenGoatDoor(int choice)
{
  int randomDoor = choice;
  while ( randomDoor == choice || doors[randomDoor] != goat) {
    randomDoor = RandomDoor();
  }
  #ifdef DEBUG
  printf("Opened Door is %d\n", randomDoor);
  #endif
  doors[randomDoor] = opened;
}

int OtherDoor(int choice)
{
  int otherDoor = choice;
  while ( otherDoor == choice || doors[otherDoor] == opened ) {
    otherDoor = (otherDoor + 1) % DOOR_COUNT;
  }
  return otherDoor;
}


for anyone following along at home, gcc needs -std=c99.

output:

: gcc -std=c99 mhall.c; ./a.out
No Change:
        1000000 tests run
        333875 win car.

Change:
        1000000 tests run
        667098 win car.