Monty Hall Paradox

Empirically verifies the Monty Hall Paradox for an arbitrary number of doors.

Monty Hall was a game show host for Let's Make A Deal. They would often play a game where the contestant was first asked to choose a door - one had a great prize behind it and the others had humorous booby prizes representing a loss. Once a door was chosen, the host would eliminate one of the two remaining doors - one he knew to be a losing door - and then offer the contestant the opportunity to stay with their original choice or switch to the other door. The contestant would nearly always opt to stay with their original choice believing the odds to be no better by switching; however, statistical probability states that the contestant's odds actually double by switching.

This code is designed to take an arbitrary number of doors and run numerous verification tests on them. A door is picked at random to be the winner and again randomly to be the contestant's original choice. A losing door is then randomly eliminated from those remaining and the wins & losses resulting from each choice are added to a running tally. We can then see for ourselves if it's a 50/50 chance as intuition suggests or the 2:1 in favor of switching as per the math.

(Guess which one wins...)
 


/* cc -lm -o montyhall montyhall.c */

/* Change the number of doors here */
#define DOORS 3

/* --- End of config section --- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define STAY 0
#define SWITCH 1
#define WIN 0
#define LOSE 1

struct door_struct {
	short int winner;
	short int open;
	short int initial_pick;
};

int main(int argc, char **argv) {
	int rngseed;
	char rngbytes[sizeof(rngseed)];
	FILE* afile;

	short int x, doornum;
	struct door_struct doors[DOORS];
	unsigned long long int iter, t[2][2];
	double stats[2];

	/* Init the tallies - 1st # is wins & 2nd # is losses */
	bzero(t, sizeof(t));

        /* Seed the RNG for random sampling & noise */
	printf("Seeding RNG...\n");
	afile = fopen("/dev/urandom", "r");
	fgets(rngbytes, sizeof(rngbytes), afile);
	memcpy((void*)&rngseed, (void*)rngbytes, sizeof(rngseed));
	fclose(afile);
	srand48(rngseed);

	/* Run forever */
	for(iter=0; ; iter++) {
		/* Initialize the doors */
		bzero(doors, sizeof(doors));

		/* Generate 3 doors and randomly pick 1 as the "winner" */
		doornum = (short int)floor(drand48() * (double)DOORS);
		for (x=0; x<DOORS; x++) doors[x].winner = x == doornum ? 1 : 0;

		/* Pick an initial door */
		x = (short int)floor(drand48() * (double)DOORS);
		doors[x].initial_pick = 1;

		/* Open a door */
		doornum = (short int)floor(drand48() * (double)DOORS);
		while (doornum == x || doors[doornum].winner) doornum = (doornum+1) % DOORS;
		doors[doornum].open = 1;

		/* Tally wins & losses by staying or switching */
		for (x=0; x<DOORS; x++) {
			/* Update the stay tally */
			if (doors[x].initial_pick) {
				if (doors[x].winner) t[STAY][WIN]++;
				else t[STAY][LOSE]++;

			/* Update the switch tally */
			} else {
				if (!doors[x].open) {
					if (doors[x].winner) t[SWITCH][WIN]++;
					else t[SWITCH][LOSE]++;
				}
			}
		}

		/* Display the updated tally stats */
		stats[STAY] = 100.0 * (double)t[STAY][WIN] / (double)(t[STAY][WIN] + t[STAY][LOSE]);
		stats[SWITCH] = 100.0 * (double)t[SWITCH][WIN] / (double)(t[SWITCH][WIN] + t[SWITCH][LOSE]);
		printf("Iteration: %llu | Stay: %.3f | Switch: %.3f\r", iter, stats[STAY], stats[SWITCH]);
	}

	return 0;
}
Files: