patterncMinor
Is this an elegant/accurate simulation of the Monty Hall problem?
Viewed 0 times
thisproblemthesimulationaccurateelegantmontyhall
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!
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
#include
#include
#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 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;
}Solution
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
instead of
in C you always start from 0 and use
output:
for (int i = 0; i <= DOOR_COUNT; i++) {instead of
for (int i = 0; i < DOOR_COUNT; i++) {in C you always start from 0 and use
-
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
#include
#include
#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 < GROUP_COUNT; ++g) {
int wins = 0;
for (int i = 0; i < 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 < 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.Code Snippets
for (int i = 0; i <= DOOR_COUNT; i++) {for (int i = 0; i < DOOR_COUNT; i++) {#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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 < GROUP_COUNT; ++g) {
int wins = 0;
for (int i = 0; i < 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 < 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;
}: gcc -std=c99 mhall.c; ./a.out
No Change:
1000000 tests run
333875 win car.
Change:
1000000 tests run
667098 win car.Context
StackExchange Code Review Q#33256, answer score: 3
Revisions (0)
No revisions yet.