If Monty opened his door randomly, then indeed his action does not help the contestant, for whom it makes no difference to switch or to stick. But Monty's action is not random. He knows where the prize is, and acts on that knowledge. That injects a crucial piece of information into the situation. Information that the wise contestant can take advantage of to improve his or her odds of winning the grand prize. By opening his door, Monty is saying to the contestant "There are two doors you did not choose, and the probability that the prize is behind one of them is 2/3. I'll help you by using my knowledge of where the prize is to open one of those two doors to show you that it does not hide the prize. You can now take advantage of this additional information. Your choice of door A has a chance of 1 in 3 of being the winner. I have not changed that. But by eliminating door C, I have shown you that the probability that door B hides the prize is 2 in 3." (source)But it's beginning to look like either these authors made my same mistake or they're all using the same ambiguous device to emphasize that the selection conveys information. I'm tempted to write a script to settle this by brute force, but the more I think about how such a script would look, the more I realize I might have been (gasp) wrong that the intention behind the opened door could possibly matter and these sources just happened to be wrong in the same way such that I didn't have a motive to check my thinking. Regardless, I will be as embarrassed as promised if I do turn out wrong.
repeat many times:Here's the algorithm if the host does not know which door has the money:
— The prize is placed behind a random door.
prizeDoor ← random(1...3)
— Player picks first door.
choice ← 1
— Host opens a door.
switch prizeDoor:
case 1: openDoor ← random(2..3)
case 2: openDoor ← 3
case 3: openDoor ← 2
— Player switches.
if openDoor = 2: choice ← 3
if openDoor = 3: choice ← 2
— Did the player win?
if choice = prizeDoor: wins ← wins + 1
repeat many times:With the first simulation the player will win 2/3 of the time. With the second simulation he will win 1/2 of the time.
— The prize is placed behind a random door.
prizeDoor ← random(1...3)
— Player picks first door.
choice ← 1
— Host opens a door randomly.
switch prizeDoor:
case 1: openDoor ← random(2..3)
case 2: openDoor ← random(2..3)
case 3: openDoor ← random(2..3)
— Oops! The host opened the winning door.
if openDoor = prizeDoor:
restart
— Player switches.
if openDoor = 2: choice ← 3
if openDoor = 3: choice ← 2
— Did the player win?
if choice = prizeDoor: wins ← wins + 1
Runs when Monty knows where the prize is:Notice that the only difference between the two functions is the
Wins: 666421 (66.6%)
Losses: 333579 (33.4%)
Runs when Monty has no idea where the prize is:
Wins: 333649 (50.0%)
Losses: 333406 (50.0%)
switch statement—i.e., how Monty chooses which door to open.import java.io.*;
import java.util.*;
public class Simulation {
public static final int ITERATIONS = 1000000;
public static void main(String[] arguments) {
montyHallKnowing (ITERATIONS);
montyHallUnknowing(ITERATIONS);
}
private static void montyHallKnowing(int iterations) {
Random random = new Random();
int wins = 0, losses = 0;
for (int i = 0; i < iterations; ++i) {
// The prize is placed behind a random door.
int prizeDoor = random.nextInt(3) + 1;
// The player picks the first door.
int playerChoice = 1;
int openDoor = 0;
// The host opens a door.
switch (prizeDoor) {
case 1: openDoor = random.nextInt(2) + 2; break;
case 2: openDoor = 3; break;
case 3: openDoor = 2; break;
}
// Oops! The host opened the winning door.
if (openDoor == prizeDoor) {
continue;
}
// The player decides to switch.
if (openDoor == 2) playerChoice = 3;
if (openDoor == 3) playerChoice = 2;
if (playerChoice == prizeDoor) wins += 1;
else losses += 1;
}
System.out.printf("Results when Monty knows where the prize is:%n");
System.out.printf(" Wins: %d (%.1f%%)%n", wins, wins / ((double) wins + losses) * 100);
System.out.printf(" Losses: %d (%.1f%%)%n", losses, losses / ((double) wins + losses) * 100);
System.out.printf("%n");
}
private static void montyHallUnknowing(int iterations) {
Random random = new Random();
int wins = 0, losses = 0;
for (int i = 0; i < iterations; ++i) {
// The prize is placed behind a random door.
int prizeDoor = random.nextInt(3) + 1;
// The player picks the first door.
int playerChoice = 1;
int openDoor = 0;
// The host opens a door at random.
switch (prizeDoor) {
case 1: openDoor = random.nextInt(2) + 2; break;
case 2: openDoor = random.nextInt(2) + 2; break;
case 3: openDoor = random.nextInt(2) + 2; break;
}
// Oops! The host opened the winning door.
if (openDoor == prizeDoor) {
continue;
}
// The player decides to switch.
if (openDoor == 2) playerChoice = 3;
if (openDoor == 3) playerChoice = 2;
if (playerChoice == prizeDoor) wins += 1;
else losses += 1;
}
System.out.printf("Results when Monty has no idea where the prize is:%n");
System.out.printf(" Wins: %d (%.1f%%)%n", wins, wins / ((double) wins + losses) * 100);
System.out.printf(" Losses: %d (%.1f%%)%n", losses, losses / ((double) wins + losses) * 100);
System.out.printf("%n");
}
}// Oops! The host opened the winning door.
if (openDoor == prizeDoor) {
continue;
} That is, it throws out all such situations as well. (This is why the sample simulation numbers Khalad gave for unknowing Monty, 333649 and 333406, do not add up to 1000000.)
posted by martinrebas at 9:01 PM on March 18, 2007