|
|
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?"
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. |