THE MONTY HALL PROBLEM
The television game show Let's Make a Deal was hosted by Monty Hall. The premise of the show was to give contestants the opportunity to make choices in order to win prizes. A typical opportunity would go like this:
Suppose you are a contestant on a game show, and you are given the choice of three doors: behind one door is a car; behind the other two are goats. You select a door, say Number 1, and the host, who knows what is behind each of the doors, opens another door, say Number 3, which has a goat. He then says to you, "Would you like to stay with door Number 1 or change your selection and go with door Number 2?"

Is it to your advantage to switch your choice?


Here is a program in C to simulate this situation.

// MONTY.C
// Simulate the Monty Hall problem
// Last revised April 26, 2012

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


#define FALSE		0
#define TRUE		(!FALSE)


#define DOOR_ONE	0
#define DOOR_TWO	1
#define DOOR_THREE	2

#define PRIZE_GOAT	0
#define PRIZE_CAR	1



int	get_random_door( void )
{
	switch( random() % 3 ) {
	case 0:		return( DOOR_ONE );
	case 1:		return( DOOR_TWO );
	case 2:		return( DOOR_THREE );
	}

	printf( "Bugcheck.\n" );
	exit( 0 );
}


void	do_random_seeding( void )
{
	time_t		time_now;


	time( &time_now );
	srandom((unsigned int) time_now );
}


char	*text_door( int door_value )
{
	switch( door_value ) {
	case DOOR_ONE:		return( "One" );
	case DOOR_TWO:		return( "Two" );
	case DOOR_THREE:	return( "Three" );
	}

	printf( "Bugcheck.\n" );
	exit( 0 );
}


char	*text_prize( int prize_value )
{
	switch( prize_value ) {
	case PRIZE_GOAT:	return( "Goat" );
	case PRIZE_CAR:		return( "Car" );
	}

	printf( "Bugcheck.\n" );
	exit( 0 );
}


int	main( int argc, char *argv[] )
{
	int		round;
	int		door[ 3 ];
	int		number_of_rounds;
	int		door_with_car;
	int		stand_firm_car, stand_firm_goat;
	int		switch_door_car, switch_door_goat;
	int		print_trace_flag;
	int		first_choice_door, host_revealed_door, remaining_door;

	int		car_behind_door_count[ 3 ];
	int		first_choice_count[ 3 ];


	number_of_rounds = 1;

	if ( argc > 1 )
	{
		number_of_rounds = atoi( argv[1] );

		if ( number_of_rounds < 1 )
		{
			printf( "Must perform at least one round.\n" );
			exit( 0 );
		}
	}


	// If performing fewer than 20 rounds, show a detailed trace for each one

	print_trace_flag = ( number_of_rounds < 20 ) ? TRUE : FALSE;


	do_random_seeding();


	// Keep track of wins and losses for each choice

	stand_firm_car = 0;
	stand_firm_goat = 0;
	switch_door_car = 0;
	switch_door_goat = 0;


	// Keep track of random choices in case our random source is biased

	car_behind_door_count[ DOOR_ONE ] = 0;
	car_behind_door_count[ DOOR_TWO ] = 0;
	car_behind_door_count[ DOOR_THREE ] = 0;

	first_choice_count[ DOOR_ONE ] = 0;
	first_choice_count[ DOOR_TWO ] = 0;
	first_choice_count[ DOOR_THREE ] = 0;


	// Perform each event

	for ( round = 1; round <= number_of_rounds; round++ )
	{
		// Prepare each door prior to the event

		door[ DOOR_ONE ] = PRIZE_GOAT;
		door[ DOOR_TWO ] = PRIZE_GOAT;
		door[ DOOR_THREE ] = PRIZE_GOAT;


		// Place the car behind a random door

		door_with_car = get_random_door();
		door[ door_with_car ] = PRIZE_CAR;

		// Keep track of which door what chosen for statistical purposes
		car_behind_door_count[ door_with_car ]++;


		if ( TRUE == print_trace_flag )
		{
			printf( "Round %d:\n", round );
			printf( "  [ %4s ]  [ %4s ]  [ %4s ]\n",
				text_prize( door[ DOOR_ONE ] ),
				text_prize( door[ DOOR_TWO ] ),
				text_prize( door[ DOOR_THREE ] ) );
		}


		// Contestant selects a door

		first_choice_door = get_random_door();

		// Keep track of which door a contestant chooses for statistical purposes
		first_choice_count[ first_choice_door ]++;


		if ( TRUE == print_trace_flag )
		{
			printf( "  Contestant chooses door %s.\n",
				text_door( first_choice_door ));
		}


		// Host reveals a goat that is behind a door the contestant did not pick

		while( 1 )
		{
			host_revealed_door = get_random_door();

			// The host cannot reveal the door that the contestant chose

			if ( host_revealed_door == first_choice_door )
				continue;

			// The host must reveal a goat

			if ( PRIZE_GOAT != door[ host_revealed_door ] )
				continue;

			break;
		}

		if ( TRUE == print_trace_flag )
		{
			printf( "  Host reveals door %s as a %s.\n",
				text_door( host_revealed_door ),
				text_prize( door[ host_revealed_door ] ));
		}


		// Contestant stands firm

		if ( TRUE == print_trace_flag )
		{
			printf( "  Contestant does not switch and wins a %s.\n",
				text_prize( door[ first_choice_door ] ));
		}

		if ( PRIZE_CAR == door[ first_choice_door ] )
		{
			stand_firm_car++;
		}
		else
		{
			stand_firm_goat++;
		}


		// Determine the remaining door

		remaining_door = DOOR_ONE + DOOR_TWO + DOOR_THREE;
		remaining_door -= first_choice_door;
		remaining_door -= host_revealed_door;


		// Contestant switches to the other door

		if ( TRUE == print_trace_flag )
		{
			printf( "  Contestant switches and wins a %s.\n",
				text_prize( door[ remaining_door ] ));
		}

		if ( PRIZE_CAR == door[ remaining_door ] )
		{
			switch_door_car++;
		}
		else
		{
			switch_door_goat++;
		}
	}


	// Print summary information

	printf( "After %d roun%s:\n",
		number_of_rounds,
		( 1 == number_of_rounds ) ? "d" : "ds" );

	printf( "  Do not switch: Win %d, Lose %d, %f%%.\n",
		stand_firm_car, stand_firm_goat,
		100.0 * (float) stand_firm_car / (float) number_of_rounds );

	printf( "  Switch:        Win %d, Lose %d, %f%%.\n",
		switch_door_car, switch_door_goat,
		100.0 * (float) switch_door_car / (float) number_of_rounds );

	printf( "  Door with Car:      One: %d, Two: %d, Three: %d.\n",
		car_behind_door_count[ DOOR_ONE ],
		car_behind_door_count[ DOOR_TWO ],
		car_behind_door_count[ DOOR_THREE ] );

	printf( "  First Chosen Door:  One: %d, Two: %d, Three: %d.\n",
		first_choice_count[ DOOR_ONE ],
		first_choice_count[ DOOR_TWO ],
		first_choice_count[ DOOR_THREE ] );

	printf( "\n" );


	exit( 0 );
}


$ ./monty
Round 1:
  [  Car ]  [ Goat ]  [ Goat ]
  Contestant chooses door Two.
  Host reveals door Three as a Goat.
  Contestant does not switch and wins a Goat.
  Contestant switches and wins a Car.
After 1 round:
  Do not switch: Win 0, Lose 1, 0.000000%.
  Switch:        Win 1, Lose 0, 100.000000%.
  Door with Car:      One: 1, Two: 0, Three: 0.
  First Chosen Door:  One: 0, Two: 1, Three: 0.


$ ./monty 1000000
After 1000000 rounds:
  Do not switch: Win 332851, Lose 667149, 33.285100%.
  Switch:        Win 667149, Lose 332851, 66.714900%.
  Door with Car:      One: 333127, Two: 334321, Three: 332552.
  First Chosen Door:  One: 333071, Two: 334247, Three: 332682.

Comments to Webmaster