Unveiling the Monty Hall Problem: A JavaScript Simulation

Vardan HakobyanVardan Hakobyan
4 min read

Photo by Joshua Hoehne on Unsplash

Have you ever pondered the Monty Hall problem? This classic probability puzzle has baffled both mathematicians and casual thinkers for years. Today, we’re going to demystify this counterintuitive puzzle using the power of JavaScript.

The Monty Hall Problem: A Quick Recap

Imagine this scenario:

  1. You’re on a game show facing three closed doors.

  2. Behind one door lies a shiny new car; behind the other two, just goats.

  3. You pick a door (let’s call it Door A), hoping for the car.

  4. The host, Monty Hall, who knows what’s behind each door, opens another door revealing a goat.

  5. Now, Monty offers you a choice: stick with Door A or switch to the remaining unopened door.

Here’s the million-dollar question: Should you switch doors or stay put? Does it even matter?

Surprisingly, the odds aren’t 50–50. If you switch, you’ll win the car 2/3 of the time! Sounds counterintuitive, right? Let’s prove it with code.


Setting Up Our JavaScript Simulator

First, let’s create a simple Node.js app. If you’re familiar with the process, feel free to skip this section.

Otherwise, follow these steps:

  1. Open your terminal and navigate to your desired project folder.

  2. Run these commands:

mkdir monty-hall-problem
cd monty-hall-problem

Create an entry file, where we will write the actual code:

touch index.js

That’s it! Now, let’s start the actual coding!


Coding the Monty Hall Simulation

Let’s break down our simulation into manageable steps:

  1. Model three doors

  2. Randomly place the car behind one door

  3. Simulate the player’s initial choice

  4. Simulate Monty opening a door with a goat

  5. Simulate choosing the remaining door when the player decides to switch

  6. Calculate wins for both strategies: switching and staying

Let’s introduce a constant for the doors count so we won’t have the magic number 3 in our code.

const DOORS_COUNT = 3;

We’ll keep the win numbers in respective variables:

let winsWithoutDoorChange = 0;
let winsWithDoorChange = 0;

Let’s create a function that randomly generates an integer between 0 and given maxNumber :

const generateRandomNumber = (maxNumber) => {
    return Math.floor(Math.random() * maxNumber);
}

We have 3 doors, starting from index with 0 , so maxNumber will be 2. Let’s randomly select our door with car and the one the player chose:

const doorWithCar = generateRandomNumber(DOORS_COUNT);
const chosenDoor = generateRandomNumber(DOORS_COUNT);

Then, we need to choose some door that the host will open. It must not be the one the player chose, and also must not be one with car. We can do that with this code (one of rare cases when do/while is actually appropriate):

do {
    openDoorWithGoat = generateRandomNumber(DOORS_COUNT);
} while ([chosenDoor, doorWithCar].includes(openDoorWithGoat));

Ok, now we have one door chosen by player and another open door with a goat. The player can change their decision and choose the last door. Let’s simulate it:

const newChosenDoor = [0, 1, 2]
    .find(door => ![chosenDoor, openDoorWithGoat].includes(door));

Here we iterate over an array of 3 elements (doors), and select the only one remaining (the door that is not selected and is not open). This is the new door that the player chooses.

All that remains is to check whether the player has won and increase the corresponding counter:

if (chosenDoor === doorWithCar) {
    winsWithoutDoorChange++;
}

if (newChosenDoor === doorWithCar) {
    winsWithDoorChange++;
}

That’s it! Let’s put this logic in a for loop and try iterating with different numbers. Remember, the more iterations, the more accurate the final result will be.

Here’s the complete code for our simulation:

const ATTEMPTS_COUNT = 1000_000;
const DOORS_COUNT = 3;

const generateRandomNumber = (maxNumber) => {
  return Math.floor(Math.random() * maxNumber);
}

const simulateMontyHall = (attempts) => {
  let winsWithoutDoorChange = 0;
  let winsWithDoorChange = 0;

  for (let i = 0; i < attempts; i++) {
    const doorWithCar = generateRandomNumber(DOORS_COUNT);
    const chosenDoor = generateRandomNumber(DOORS_COUNT);

    let openDoorWithGoat;

    do {
      openDoorWithGoat = generateRandomNumber(DOORS_COUNT);
    } while ([chosenDoor, doorWithCar].includes(openDoorWithGoat));

    const newChosenDoor = [0, 1, 2]
      .find(door => ![chosenDoor, openDoorWithGoat].includes(door));

    if (chosenDoor === doorWithCar) {
      winsWithoutDoorChange++;
    }

    if (newChosenDoor === doorWithCar) {
      winsWithDoorChange++;
    }
  }

  return {
    winsWithoutDoorChange,
    winsWithDoorChange,
  }
}

const {
  winsWithoutDoorChange,
  winsWithDoorChange,
} = simulateMontyHall(ATTEMPTS_COUNT);

const withoutChangeWinProbability = (winsWithoutDoorChange / ATTEMPTS_COUNT * 100).toFixed(2);
const withChangeWinProbability = (winsWithDoorChange / ATTEMPTS_COUNT * 100).toFixed(2);

console.log(
  `Without change, won ${winsWithoutDoorChange} out of ${ATTEMPTS_COUNT} attempts. Probability is ${withoutChangeWinProbability}%`,
);
console.log(
  `With change, won ${winsWithDoorChange} out of ${ATTEMPTS_COUNT} attempts. Probability is ${withChangeWinProbability}%`,
);

To start the program, simply run node index.js in terminal. You will have ~33.3% of wins if the player doesn’t change their initial choice, and ~66.6% of wins in case of change.

If you don’t want to create and run the program locally, here is a link to Codepen. Run it and check the results.

Prefer watching instead? Check out the video on YouTube.

Hope you enjoyed it! If you have any notes, remarks or questions, please share them in the comments.


Stay updated with the latest JavaScript and software development news! Join my Telegram channel for more insights and discussions: TechSavvy: Frontend & Backend.

0
Subscribe to my newsletter

Read articles from Vardan Hakobyan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vardan Hakobyan
Vardan Hakobyan

Hi, I'm a seasoned software engineer with a strong focus on JavaScript. I'm passionate about sharing my knowledge and experiences to help others learn something new and avoid the same pitfalls I've encountered along the way.