## The Monty Hall Problem

You’ve surely heard of this one. It’s a really tough one to wrap your head around. I’ll describe the problem in order to solve it, but it’s worth looking into the background of the “Ask Marilyn” incident if you’re not familiar with it.

The story shows that it’s not just hacks like myself that find this stuff non-intuitive. Lots of highly educated, very smart people got tricked by this one.

The problem is based on an old game show, “Let’s Make a Deal”. The host of the show was named Monty Hall. The contestant is shown three doors. Behind two doors are goats. Behind one is A NEW CAR!!!

The contestant chooses a door. If he chooses the one with THE NEW CAR, he gets to keep the car. If he chooses a goat door, he gets a goat. The unspoken assumption being that he’d rather have a car.

But… before the chosen prize is revealed, Monty Hall opens one of the two remaining doors, revealing a goat!

There are now two doors remaining. The one that the contestant chose, and one other one. Monty asks the contestant if he wants to stay with his choice, or if he’d like to switch to the other door.

What should he do?

To clarify, what should he do in order to optimize his chances of winning THE NEW CAR? Are the odds of winning the car better if he sticks with his original choice? Are they better if he switches? Does it just not matter?

Intuition tells us that it doesn’t matter. There are two doors. One has a goat, one has a car. The odds are 50/50. Doesn’t really matter if he sticks with the first choice or switches. The odds are the same.

The truth though? He should absolutely switch. It will significantly improve his odds of winning. In fact, he’s twice as likely to win if he switches than if he sticks with his original choice.

## But why???

If you want a deep explanation… I mean really deep, just head over to the Monty Hall Problem page on wikipedia. But I’ll give my take on it.

When the contestant first chose a door, he had a 1 in 3 chance of winning the car. That’s pretty straightforward.

When Monty opens a door, he is not randomly opening a door. He’s opening a door with a goat behind it, always. So he is using his knowledge of what’s behind each door to change the nature of the game.

Let’s say we have doors A, B, and C. A and B have goats, C has a car.

There are three possible scenarios:

- Contestant chooses door A. Monty will open door B. If contestant switches doors, he wins.
- Contestant chooses door B. Monty opens A. If contestant switches, he wins.
- Contestant chooses door C. Monty opens either A or B. It doesn’t matter. If contestant switches, he loses.

So in two of the three scenarios, switching is the winning move.

Even though I’ve worked out the logic of this myself many times and done it in code more than once, it still feels vaguely magical.

## Bring on the Code

Let’s start by playing the game 1000 times in a for loop. And we’ll start by setting up the three doors with goats behind them and swapping out a car on one of them.

// we'll play the game 1000 times. for (let i = 0; i < 1000; i++) { // create 3 doors with goats behind them. let doors = ["goat", "goat", "goat"]; // randomly choose one door and put a car behind it. let winner = Math.floor(Math.random() * 3); doors[winner] = "car"; console.log(doors); }

This outputs the 1000 random door configurations. Something like this:

[ 'car', 'goat', 'goat' ] [ 'car', 'goat', 'goat' ] [ 'goat', 'car', 'goat' ] [ 'car', 'goat', 'goat' ] [ 'goat', 'car', 'goat' ] [ 'car', 'goat', 'goat' ] [ 'goat', 'car', 'goat' ] [ 'car', 'goat', 'goat' ] [ 'car', 'goat', 'goat' ] ...

Now let’s have the contestant make a choice – 0, 1 or 2. Just to check ourselves, let’s see whether he wins a car and add up how many times he wins. Out of 1000 games, he should win somewhere close to 333.

let wins = 0; // we'll play the game 1000 times. for (let i = 0; i < 1000; i++) { // create 3 doors with goats behind them. let doors = ["goat", "goat", "goat"]; // randomly choose one door and put a car behind it. let winner = Math.floor(Math.random() * 3); doors[winner] = "car"; // console.log(doors); // choose a door and count how many wins we get let choice = Math.floor(Math.random() * 3); if (doors[choice] === "car") { wins++; } } // should be around 333 console.log(wins);

That checks out for me.

Next, we let Monty open a door to reveal a goat. There are probably plenty of clever ways to code this, but I’ll just loop through the three doors and choose one that is not the same as what the contestant chose, and make sure that it’s a goat door.

... // now monty chooses another door (must be a goat!) let montyChoice; for (let j = 0; j < 3; j++) { if (j != choice && doors[j] === "goat") { montyChoice = j; break; } } console.log(doors[montyChoice]); ...

Just to check myself, I logged what’s behind Monty’s door. Sure enough, nothing but goats.

Now we have the contestant’s choice and Monty’s choice. We can add the code back in that calculates how many times the contestant wins the car…

let wins = 0; // we'll play the game 1000 times. for (let i = 0; i < 1000; i++) { // create 3 doors with goats behind them. let doors = ["goat", "goat", "goat"]; // randomly choose one door and put a car behind it. let winner = Math.floor(Math.random() * 3); doors[winner] = "car"; // console.log(doors); // choose a door and count how many wins we get let choice = Math.floor(Math.random() * 3); // now monty chooses another door (must be a goat!) let montyChoice; for (let j = 0; j < 3; j++) { if (j != choice && doors[j] === "goat") { montyChoice = j; break; } } // console.log(doors[montyChoice]); // contestant does not switch if (doors[choice] === "car") { wins++; } } console.log(wins);

This isn’t any different than the first time we counted the wins. I consistently get numbers in the low 300s. Of course, because the fact that Monty opens a door doesn’t change the fact that there was a 1 in 3 chance of the contestant winning.

But let’s see what happens if the contestant switches doors. Again, you can get fancy here, but I’ll go brute force, looping through the doors till I find the one that is neither the contestant’s choice nor Monty’s choice. And I’ll count how many times he wins with that choice.

let wins = 0; // we'll play the game 1000 times. for (let i = 0; i < 1000; i++) { // create 3 doors with goats behind them. let doors = ["goat", "goat", "goat"]; // randomly choose one door and put a car behind it. let winner = Math.floor(Math.random() * 3); doors[winner] = "car"; // console.log(doors); // choose a door and count how many wins we get let choice = Math.floor(Math.random() * 3); // now monty chooses another door (must be a goat!) let montyChoice; for (let j = 0; j < 3; j++) { if (j != choice && doors[j] === "goat") { montyChoice = j; break; } } // console.log(doors[montyChoice]); // contestant does not switch // if (doors[choice] === "car") { // wins++; // } // contestant switches let newChoice; for (let j = 0; j < 3; j++) { if (j != choice && j != montyChoice) { newChoice = j; break; } } if (doors[newChoice] === "car") { wins++; } } console.log(wins);

Running this I get numbers in the upper 600s! Winning roughly 2 out of 3 times, exactly as predicted.

## Summary

So there you go. The code proves things out. But it still feels a bit magical.

I did think of another though experiment that helps to make it make sense. Let’s say there were four doors – three goats, one NEW CAR. Contestant chooses one, and Monty Hall opens *two* of them to reveal *two goats*. Or better yet, there are *ten* doors. Contestant chooses one and Monty opens *eight*. The only way he’d lose by switching is if he had chosen the car to begin with. And there was only a 1 in 10 chance he did that. So if he switches now, he’s got a 9 out of 10 chance of winning! That helps my brain a bit. But still seems a bit magical.