Monty Hall Simulation

A little program in RubyLanguage to simulate the MontyHallProblem. We were going to do it in PythonLanguage, but then we'd have to call it MontyPython.

  def randomDoor
return rand(3)
  end

def otherDoorThan(*forbiddenDoors) allowedDoors = [0,1,2] - forbiddenDoors return allowedDoors[rand(allowedDoors.size)] end

stayingWasRight = 0 changingWasRight = 0

1_000_000.times do prizeDoor = randomDoor() firstChosenDoor = randomDoor() montysDoor = otherDoorThan(prizeDoor, firstChosenDoor) secondChosenDoor = otherDoorThan(montysDoor, firstChosenDoor) case prizeDoor when firstChosenDoor then stayingWasRight += 1 when secondChosenDoor then changingWasRight += 1 else puts "Monty cheated!" end end

totalRuns = stayingWasRight + changingWasRight

puts "Absolute Numbers: Staying was right in #{stayingWasRight} cases Changing was right in #{changingWasRight} cases Total number of runs: #{totalRuns} Relative Numbers: Staying was right in #{100.0 * stayingWasRight / totalRuns}% cases Changing was right in #{100.0 * changingWasRight / totalRuns}% cases"

A run produced the following output:

  Absolute Numbers: 
Staying was right in  333810 cases
Changing was right in 666190 cases

Total number of runs: 1000000

Relative Numbers: Staying was right in 33.381% cases Changing was right in 66.619% cases

So this supports the notion, that changing is right in 2/3 of the cases. Or can you spot any problems in this program, similar to the problems some of the tables on MontyHallProblem have?


Writing my own MontyHallSimulation made the solution clearer to me. I was able to simplify it to something like this:

  prizeDoor = randomDoor();
  firstChosenDoor = randomDoor();

if prizeDoor == firstChosenDoor then stayingWasRight += 1 else changingWasRight += 1 end

And clearly, prizeDoor == firstChosenDoor only 1/3 of the time.

This is correct, but doesn't really show why the problem is different from NotTheMontyHallProblem. For that, see NotMontyHallSimulation -- AndrewMcGuinness

The only reason you could reduce the problem to above, is because you had done the analysis. So it isn't really a simulation, per se.

Here is a simulation done in lisp. It is somewhat redundant, as no analysis of the choices is done:

  (defun monty-hall (N)
    "simulate the 'Monty Hall' problem for N iterations"
    (defun pick-one (list)
      (nth (random (length list)) list))  
    (let ((stay-success 0)
          (switch-success 0))
      (dotimes (i N t)
        (let* ((doors (list 0 1 2))
               (prize-door (pick-one doors))
               (your-door  (pick-one doors))
               (monty-door  (pick-one (remove prize-door (remove your-door doors))))
               (switch-door (pick-one (remove monty-door (remove your-door doors)))))
          (cond ((equal your-door prize-door) (incf stay-success))
                ((equal switch-door prize-door) (incf switch-success)))))
      (list stay-success switch-success)))

and output for a run:

  * (monty-hall 100000000)
  (33337404 66662596)


A Java applet (with source code) is available here: http://www.rdrop.com/~half/Creations/Puzzles/LetsMakeADeal/monty.hall.applet.html

This applet lets you play the game manually, or the applet can play itself. There are three-door and six-door versions, and running win/lose statistics are displayed as you play.


Here's a version in Perl, loosely based on the Ruby version above, but altered slightly to allow for more than three doors (if desired).

 use strict;
 use warnings;

my $number_of_doors = 3; my $total_trials = 1_000_000;

sub random_door { return int rand $number_of_doors; }

sub door_other_than { my @forbidden = @_; my %doors; @doors{ 0 .. $number_of_doors - 1 } = (); for my $door (@forbidden) { delete $doors{$door}; } my @choose_from = keys %doors; return $choose_from[ int rand @choose_from ]; }

my $staying_was_right = 0; my $changing_was_right = 0;

for (1 .. $total_trials) { my $prize_door = random_door(); my $first_chosen_door = random_door(); my $montys_door = door_other_than($prize_door, $first_chosen_door); my $second_chosen_door = door_other_than($montys_door, $first_chosen_door); if ($prize_door == $first_chosen_door) { $staying_was_right++ } elsif ($prize_door == $second_chosen_door) { $changing_was_right++; } }

my $stay_percent = 100 * $staying_was_right / $total_trials; my $change_percent = 100 * $changing_was_right / $total_trials;

print <<END_TEXT; Total trials: $total_trials

Absolute numbers: Staying was right in $staying_was_right cases. Changing was right in $changing_was_right cases. Relative numbers: Staying was right in $stay_percent% cases. Changing was right in $change_percent% cases. END_TEXT


EditText of this page (last edited February 28, 2005) or FindPage with title or text search