Brooklyn 99 Monty Hall Problem JavaScript Solution

I’ve been learning how to code again since I stopped taking any kind of Computer Science courses back during my 1st Year of University, and I did this exercise for fun, and also because I became interested in the Monty Python problem because of Brooklyn 99. Here it is in video form…

For those who didn’t watch the video, the problem is basically this: There are 3 doors with prizes. Only one has the super amazing prize of a brand new car, while the other two had like minor prizes only. Anyway, you choose one door, but then the host of the show opens one of the other doors to show a minor prize and gives you the opportunity to switch doors, or stay with the door you originally chose. What do you do?

So the argument is basically about when probabilities kick in. Essentially, when you chose the first time, you had a 1/3 chance of choosing the right door, meaning the other two doors had a 2/3 chance of being wrong. The question then is, what happens to the probability when one of the other two doors is opened?

The two possibilities are (1, according to Captain Holt) the probabilities shift evenly to 50-50 between the two unopened doors, and (2, Kevin) the probabilities “concentrate” on the 2nd unopened door meaning your door still only has 33% chance of being right, while the 2nd unopened door now has the 67% chance that the two doors had.

TL;DR The correct answer is Kevin’s answer. That the probabilities “concentrate”. But I wanted to test it out. So I wrote a simple JavaScript program to do so.

Here’s my explanation through the code…

//Declare Counters
var GameCount = 1000000;
var LoopCounter = 0;
//Declare Arrays
var PrizeDoor=[GameCount];
var ChoiceDoor=[GameCount];
var OpenedDoor=[GameCount];
//Declare Win-Loss Counters
var LoserAnyway = 0;
var SwitchLoser = 0;
var NoSwitchLoser = 0;
var Loser = 0;
var Winner = 0;
var WinRatio = 0;

So here, I’m basically just declaring all the variables. The important thing here is that I am testing 2 scenarios. The first scenario is that the host knows exactly where the car is, and the second is where the host doesn’t know where the car is. This is important because in the first scenario, the host will always open an empty door, while the second scenario the possibility of you losing anyway because the hose opened the door with the major prize in it. Notice that the game is to be played 1 million times.

//Set Up Game
function GameSetup() {
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        PrizeDoor[LoopCounter] = Math.floor(Math.random()*3);
        ChoiceDoor[LoopCounter] = Math.floor(Math.random()*3);
    }
}

This code basically sets up the game by randomly assigning 0, 1, 2 to two arrays, the array for where the door prize is and the door chosen by the contestant. This is necessary so we can get through the huge number of games I wanted to do, so that we can get a huge sample to compare the statistics.

//Functions for Comparing Doors
function RandomSwitches(){
        if (OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter]){
            LoserAnyway++;
        } else if (PrizeDoor[LoopCounter]==ChoiceDoor[LoopCounter]){
            SwitchLoser++;
        } else {
            Winner++;
        }
}
function RandomDoesNotSwitch(){
        if (OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter]){
            LoserAnyway++;
        } else if (PrizeDoor[LoopCounter]==ChoiceDoor[LoopCounter]){
            Winner++;
        } else {
            NoSwitchLoser++;
        }
}

So from the name of the function here, this is the scenario where the host does not know which door is the prize. So the first possibility in the both functions is that when the door is initially opened, it already has the major prize in it. So there is not even an opportunity for switching, the contestant is a loser no matter what (variable LoserAnyway).

The first function then counts the number times the Prize Door is the Choice door, which means the person switched and lost. Then it counts the number of times the person switched and lost. The second function basically reverses this, compares the same thing as the first function, except when the PrizeDoor is the same as the ChoiceDoor, then the person is a winner because he did not switch (Winner). Then it counts how many times the contest loses for not switching (NoSwitchLoser)

function NotRandomSwitches(){
    if (ChoiceDoor[LoopCounter] == PrizeDoor[LoopCounter]){
        Loser++;
    } else {
        Winner++;
    }
}
function NotRandomDoesNotSwitch(){
    if (ChoiceDoor[LoopCounter] == PrizeDoor[LoopCounter]){
        Winner++;
    } else {
        Loser++;
    }
}

This is the second scenario where the host knows where the prize is and always make sure to open the empty door. It makes it significantly easier to code, because it removes one of the possibilities from above (the LoserAnyway variable). Again it’s a matter of comparing the ChoiceDoor vs the PrizeDoor and assigning the correct Winner or Loser variable.

// Scenario 1, Monty Hall doesn't know where the car is
//Contestant always switches
function RandomSwitch(){
    //Begin Comparing Doors
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
        //Make sure Opened Door is not Chosen Door
        if (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter]){
            do {
               OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
            }
            while (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter])
        }
        //Determine Results
        RandomSwitches();
    }
    //Calculate Win Ratio and Display Results
    WinRatio = (Winner / GameCount)*100;
    print("In this scenario, Monty Hall does not know where the car is and contestant always switches.")
    print("Contest won " +Winner + " times, switched and lost " + SwitchLoser + " times, and was never going to win " +LoserAnyway +" times.");
    print("Contest's win ratio is " +WinRatio +"%.");
}

So these codes are the meat of the calculations because now it’s going to run through the array and make make comparisons at different times depending on the scenario..

The basics goes as follows. They open with a for loops that will run as many times as the GameCount Variable is set. To test it out I started with just 10 games, then increased to 100, 1000, and eventually 1,000,000.

Then a random number is assigned to an OpenedDoor variable. Then it has to make checks to make sure the variable is valid. The first test of validity is if the OpenedDoor is the same as the ChosenDoor… if that is the case, the validty is failed and a new door is chosen. The second validity depends on the scenario. In this first scenario, the host does not know where the car is, so there is no second validity that needs to be checked.

The outcomes then are as follows. If the OpenedDoor is the PrizeDoor, then the contestant loses no matter what, and never had a chance to chose to switch. If it is not the PrizeDoor, the Contestant always switches in this scenario, and so it counts how many times he switched and won, and switched and lost.

// Scenario 2, Monty Hall doesn't know where the car is
//Contestant never switches
function RandomNoSwitch(){
    //Reset Win-Loss Counters
    LoserAnyway = 0;
    NoSwitchLoser = 0;
    Winner = 0;
    WinRatio = 0;
    //Begin Comparing Doors
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
        //Make sure Opened Door is not Chosen Door
        if (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter]){
            do {
               OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
            }
            while (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter])
        }
        //Determine Results
        RandomDoesNotSwitch();
    }
    //Calculate Win Ratio and Display Results
    WinRatio = (Winner / GameCount)*100;
    print();
    print("In this scenario, Monty Hall does not know where the car is and contestant never switches.")
    print("Contest won " +Winner + " times, didn't switch and lost " + NoSwitchLoser + " times, and was never going to win " +LoserAnyway +" times.");
    print("Contest's win ratio is " +WinRatio +"%.");
}

This second scenario is similar to the first in that the host does not know where the car is. But the contestant never switches. This makes the code a little easier, and the outcomes are: The OpenedDoor is the PrizeDoor and the contestant was a loser no matter what, the PrizeDoor is not the ChosenDoor in which case the contestant is the loser because he didn’t switch, and the PrizeDoor is the ChosenDoor in which case the contestant is the winner.

// Scenario 3, Monty Hall doesn't know where the car is/Contestant switches randomly
function RandomRandomSwitch(){
    //Begin Comparing Doors
    var CustChoice = 0;
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
        //Make sure Opened Door is not Chosen Door
        if (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter]){
            do {
               OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
            }
            while (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter])
        }
        //Determine Results
        CustChoice = Math.floor(Math.random()*2)
        if (CustChoice == 0){
            RandomSwitches();
        } else {
            RandomDoesNotSwitch();
        }
    }
    //Calculate Win Ratio and Display Results
    WinRatio = (Winner / GameCount)*100;
    print();
    print("In this scenario, Monty Hall does not know where the car is and contestant switches at random.")
    print("Contest won " +Winner + " times, switched and lost " + SwitchLoser + " times, and was never going to win " +LoserAnyway +" times.");
    print("Contest's win ratio is " +WinRatio +"%.");
}

Alright, so I’m not going to go through the other 2 scenarios line by line. The basic difference is that in this case, the host knows where the car is and so the OpenedDoor is never the PrizeDoor. Each scenario still has the same situations where the Contestant never switches or always switches. The main fun of the code is determining which condition needs to be checked first in the If Structure to ensure the correct result.

Anyway the results are…

In this scenario, Monty Hall does not know where the car is and contestant always switches.
Contest won 332709 times, switched and lost 332849 times, and was never going to win 334442 times.
Contest’s win ratio is 33.2709%.

In this scenario, Monty Hall does not know where the car is and contestant never switches.
Contest won 332849 times, didn’t switch and lost 333261 times, and was never going to win 333890 times.
Contest’s win ratio is 33.2849%.

In this scenario, Monty Hall knows where the car is and contestant always switches.
Contest won 667151 times, didn’t switched and lost 332849 times
Contest’s win ratio is 66.7151%.

In this scenario, Monty Hall knows where the car is and contestant never switches.
Contest won 332849 times, didn’t switched and lost 667151 times
Contest’s win ratio is 33.2849%.

// Scenario 3, Monty Hall knows where the car is/Contestant always switches
function NotRandomSwitch(){
    //Reset Counters
    Loser = 0;
    Winner = 0;
    WinRatio = 0;
    //Begin Comparing Doors
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
        //Make sure Opened Door is not Chosen Door
        if (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter] && OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter]){
            do {
               OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
            }
            while (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter] && OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter])
        }
        //Determine Results
        NotRandomSwitches();
    }
    //Calculate Win Ratio and Display Results
    WinRatio = (Winner / GameCount)*100;
    print();
    print("In this scenario, Monty Hall knows where the car is and contestant always switches.")
    print("Contest won " +Winner + " times, didn't switched and lost " + Loser + " times");
    print("Contest's win ratio is " +WinRatio +"%.");
}

// Scenario 5, Monty Hall knows where the car is/Contestant never switches
function NotRandomNoSwitch(){
    //Reset Counters
    Loser = 0;
    Winner = 0;
    WinRatio = 0;
    //Begin Comparing Doors
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
        //Make sure Opened Door is not Chosen Door
        if (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter] && OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter]){
            do {
               OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
            }
            while (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter] && OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter])
        }
        //Determine Results
        NotRandomDoesNotSwitch();
    }
    //Calculate Win Ratio and Display Results
    WinRatio = (Winner / GameCount)*100;
    print();
    print("In this scenario, Monty Hall knows where the car is and contestant never switches.")
    print("Contest won " +Winner + " times, didn't switched and lost " + Loser + " times");
    print("Contest's win ratio is " +WinRatio +"%.");
}
    
// Scenario 4, Monty Hall knows where the car is/Contestant never switches
function NotRandomRandomSwitch(){
    //Declare Variable
    var CustChoice = 0;
    //Reset Counters
    Loser = 0;
    Winner = 0;
    WinRatio = 0;
    //Begin Comparing Doors
    for(LoopCounter = 0; LoopCounter < GameCount; LoopCounter++){
        OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
        //Make sure Opened Door is not Chosen Door
        if (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter] && OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter]){
            do {
               OpenedDoor[LoopCounter] = Math.floor(Math.random()*3);
            }
            while (OpenedDoor[LoopCounter] == ChoiceDoor[LoopCounter] && OpenedDoor[LoopCounter] == PrizeDoor[LoopCounter])
        }
        //Determine Results
        CustChoice = Math.floor(Math.random()*2)
        if (CustChoice == 0){
            NotRandomSwitches();
        } else {
            NotRandomDoesNotSwitch();
        }
    }
    //Calculate Win Ratio and Display Results
    WinRatio = (Winner / GameCount)*100;
    print();
    print("In this scenario, Monty Hall knows where the car is and contestant randomly switches.")
    print("Contest won " +Winner + " times, didn't switched and lost " +Loser + " times");
    print("Contest's win ratio is " +WinRatio +"%.");
}
    
GameSetup();
RandomSwitch();
RandomNoSwitch();
NotRandomSwitch();
NotRandomNoSwitch();

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s