I read a very interesting article on the NY Times today, linked from this /. article, about the Monty Hall Problem. The problem has apparently caused much embarrassment among mathematicians, and now psychologists, and it’s a very interesting read.
I couldn’t quite agree with the argument put forth, and I’m no mathematician, so I wrote a simple program to calculate some numbers for me… first, lets review the problem at hand:
- I present you with three closed doors. Behind one is a new car, the other two, a goat.
 - You choose one of the three doors, hoping it has a car.
 - I open one door exposing a goat.
 - You may keep your original door, or change your mind choosing the other closed door.
 - Open your door, if it’s the car, you can keep it.
 
So as impulsive humans, it’s easy to see, and think, that since I open one door, your final choice gives you a 50/50 shot at winning a car. The argument in the paper those posits that you should change your mind, since your original decision only had a 33% chance of being correct, and a 66% chance of being wrong.
The source for this simulation is included below. It very closely follows the steps I laid out above, resetting the doors at the start of the loop, randomly choosing which one contains a “car” (true value). The simulates a user’s choice (rand mod three), opens a door containing a goat, and then simulates the user randomly choosing to change their mind (rand mod 2). It totals how many times the user kept their original door and won a car, as well as how many times the user changed their minds and won a car.
I present the results here for you to mull over – I ran 75,000,000 iterations of the loop and got the following:
How many iterations: 75000000
In 75000000 runs, we won a car 44.4418% of the time.
	Used original choice and won a car 12499628 out of 37505245 times... 33.3277%
	Chose the other door and won a car 20831722 out of 37494755 times... 55.559%
Suggesting that your original choice is only correct 33% of the time – which makes perfect sense. However, after I open a door and narrow your choices down, you have about a 50% chance of winning the car when you change your mind.
Since your original choice was made out of three closed doors, you’ll win with that choice 33% of the time. However, when you change your mind you’re only choosing out of two closed doors, so you’ll win about 50% of the time.
Doesn’t add up, I know – but makes a certain bit of sense.
/**
 Monty Hall's game simulator… 
 Calculates win percentages when you keep your original door 
 or change your mind in a monty hall problem - 
    http://en.wikipedia.org/wiki/Monty_Hall_problem
 *
 Author: Timothy C. Fanelli
 Date: April 10, 2008
 **/ 
 include <cstdlib>
 include <cassert>
 include <ctime>
 include <iostream>
 using namespace std;
 int main() {
   int iterations;
   bool contents[] = { false, false, false };
   cout << "How many iterations: ";
   cin >> iterations;
   int changedDoorCount = 0;
   int correct[] = {0, 0};
   srand( time( 0 ) ); 
   for ( int i = 0; i < iterations; ++i ) {
     int goatOne, goatTwo;
     int carIdx = rand() % 3;
     // Setup the monty hall's doors: 
     contents[0] = false;
     contents[1] = false; 
     contents[2] = false; 
     contents[carIdx] = true; 
     if ( carIdx == 0 ) {
       goatOne = 1;
       goatTwo = 2; 
     }
    else if ( carIdx == 1 ) {   
       goatOne = 0;
       goatTwo = 2; 
    }  
    else {   
       goatOne = 0;
       goatTwo = 1;
     } 
    // So: 
    //   contents[carIdx]  == true 
    //   contents[goatOne] == false 
    //   contents[goatTwo] == false 
    assert( contents[carIdx] ); 
    assert( ! contents[goatOne] ); 
    assert( ! contents[goatTwo] ); 
    // Simulate an initial choice, then expose a goat: 
    int userChoice = rand() % 3; 
    int doorExposed = (goatOne==userChoice)?goatTwo:goatOne; 
    // Do we change doors? 
    bool changedDoors = rand() % 2; 
    if ( changedDoors ) {   
        changedDoorCount++;   
        // Pick the door that isn't the user's choice    
        // and isn't the exposedDoor... note:    
        //   
        // userChoice != doorExposed by design.   
        if ( userChoice == 0 )    
        { 
            if ( doorExposed == 1 )
               userChoice = 2; 
            else
               userChoice == 1;
        }
        else if ( userChoice == 1 )
        { 
            if ( doorExposed == 0 )
                userChoice = 2; 
            else
                userChoice = 0;
         }
         else   
         {
             if ( doorExposed == 0 )    
                userChoice = 1; 
             else    
                userChoice = 0;   
         }   
         assert( userChoice != doorExposed ); } 
         // Track how many times we chose correctly - 
         //   Increment correct[0] if we kept our original choice 
         //   Increment correct[1] if we chose the other door. 
         if ( contents[userChoice] ) {   
           correct[ changedDoors ]++; 
         }
    }
 
    double changedWinPercent = 
               100(correct[1]/static_cast(changedDoorCount));
    double originalWinPercent = 
              100(correct[0]/static_cast(iterations-changedDoorCount));
      double totalWinPercent = (correct[0]+correct[1]) / static_cast( iterations ) * 100;
 cout << "In " << iterations << " runs, we won a car " << totalWinPercent << "% of the time." << endl;
 cout << "\tUsed original choice and won a car " << correct[0] 
        << " out of " << iterations - changedDoorCount << " times… " 
        << originalWinPercent << "%" << endl;
 cout << "\tChose the other door and won a car " << correct[1] 
        << " out of " << changedDoorCount << " times… " 
        << changedWinPercent << "%" << endl;
 }
  
