Pages

Friday, December 02, 2022

Let's code the Monty Hall Problem

Kareem mentioned the Monty Hall problem today, which I hate. I can't thread my head around it.

I've seen decent explanations. Kareem says...

And yet, most of us struggle to understand how it’s not just a 50/50 chance. The reason it’s not is because once Monty chooses a door to reveal the goat, he’s given us additional information we didn’t have before.

A better comment for visualizing this comes from Jichael Mackson on this YouTube video:

I think the easiest way to understand it is, that you pretend Monty doesnt open any doors, but you get the chance to open ALL the remaining doors or stay with your first pick.

That's really the problem in a nutshell.

But am I a little hard-headed? Yes.

// `oneMoreThanMax` or `numberOfZeroChoices`
// ie, returns whole numbers (start w/ 0), not natural numbers (start w/ 1)
function getRandomInt(oneMoreThanMax) {
    return Math.floor(Math.random() * oneMoreThanMax);
}

var runs = 10000;
var doors = [0, 1, 2];
var wins = 0;
var losses = 0;

for (var i = 0; i < runs; i++) {
    var door = getRandomInt(3);
    var pick = getRandomInt(3);
    var whichMonty = getRandomInt(2);

    var remainingDoors = doors.filter((x) => x !== door && x !== pick);
    var monty = remainingDoors[remainingDoors.length === 1 ? 0 : whichMonty];
    var switched = doors.filter((x) => x !== monty && x !== pick)[0];

    console.log(`
Prize:    ${door}
original: ${pick}
monty:    ${monty}
switch:   ${switched}`);

    if (switched === door) {
        wins++;
        console.log(`WIN!!!! ${wins}`);
    } else {
        losses++;
        console.log(`fail ${losses}`);
    }
}

console.log(`wins: ${wins} and losses: ${losses}`);

Good heavens, that works out like the mathematicians say it should. It's always (so far for me; I mean at some point it could skew insanely once or twice) not so amazingly close to 67% wins, 33% losses.

Okay, okay, but let's be a pain and let Player 2 enter the game, where player #2 comes in after Monty has narrowed things down to two doors and picks between the still closed doors randomly.

Replace everything AFTER the var switched line with this:

    var closedDoors = doors.filter((x) => x !== monty);
    var player2 = closedDoors[getRandomInt(2)];

    console.log(`
Prize:    ${door}
original: ${pick}
monty:    ${monty}
switch:   ${switched}
p2:       ${player2}`);

    if (player2 === door) {
        p2wins++;
        console.log(`p2 WIN!!!! ${p2wins}`);
    } else {
        p2losses++;
        console.log(`fail ${p2losses}`);
    }
}

console.log(`p2wins: ${p2wins} and p2losses: ${p2losses}`);

That's 50/50.

So, semantically, the issue is explaining Kareem's take. Why does knowing one door was Monty's selection skew the odds? What knowledge does that convey?

Mackson's line still seems to work best here and the math in the video doesn't hurt either. What we've done is pass all the doors except for the initial selection through a selection machine that removes every bad door if the batch included the prize, and every bad door but one selected randomly in the 33% chance (or 1% chance in the hundred-door woods) the original pick hides the prize.

Fully 2/3rds (or 99% in our 100-door model) of the doors were passed through this selection machine. Do you want the results of the selection machine or the one door you removed from the selection machine's process?

You want the results of the selection machine (Monty) processing all but one door.

And you hope you were paying attention earlier if you're Player 2.