Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Monty Hall problem

monty_hall.livemd

Monty Hall problem

What is the Monty Hall problem?

Suppose you’re on a game show, and you’re given the choice of three doors:

  • Behind one door is a car;
  • behind the others, goats.

You pick a door, say No. 1, and the host, who knows what’s behind the doors, opens another door, say No. 3, which has a goat. He then says to you, “Do you want to pick door No. 2?” Is it to your advantage to switch your choice?

Lets run a few rounds and see?

The plan is to simulate the game and test the results. We need to model the game, the host knowing the door and the contestant picking a choice. Then just calculate the number of times the contestant wins.

defmodule MontyHall do
  defstruct door_1: nil, door_2: nil, door_3: nil, initial_guess: nil
end
# A implement an inspect method so we can print the game in a pretty way
defimpl Inspect, for: MontyHall do
  def inspect(%MontyHall{door_1: d1, door_2: d2, door_3: d3}, _) do
    """
    \
    """
  end

  defp draw_symbol(d) when d == :car do
    "🏎"
  end

  defp draw_symbol(d) when d == :open do
    "🪤"
  end

  defp draw_symbol(_d) do
    "🐐"
  end
end
%MontyHall{door_1: :goat, door_2: :car, door_3: :goat}

We have a way of drawing the game, so lets look at generating a random game board.

defmodule GenerateMH do
  def gen_random do
    case Enum.random([1, 2, 3]) do
      1 -> %MontyHall{door_1: :car, door_2: :goat, door_3: :goat}
      2 -> %MontyHall{door_1: :goat, door_2: :car, door_3: :goat}
      3 -> %MontyHall{door_1: :goat, door_2: :goat, door_3: :car}
    end
  end
end
GenerateMH.gen_random()

We now have a way of generating lots of games.

We now need a function that can run alot of games, take a contestants guess and return the new game when the host has opened the door.

defmodule PlayMH do
  def guess(game) do
    guess(game, Enum.random([1, 2, 3]))
  end

  def guess(game, guess) when guess == 1 do
    {da, db} = open_door(game.door_2, game.door_3)
    %MontyHall{door_1: game.door_1, door_2: da, door_3: db, initial_guess: 1}
  end

  def guess(game, guess) when guess == 2 do
    {da, db} = open_door(game.door_1, game.door_3)
    %MontyHall{door_1: da, door_2: game.door_2, door_3: db, initial_guess: 2}
  end

  def guess(game, guess) when guess == 3 do
    {da, db} = open_door(game.door_1, game.door_2)
    %MontyHall{door_1: da, door_2: db, door_3: game.door_3, initial_guess: 3}
  end

  # So there are 3 possibilites
  # A - Goat, B - Car
  # A - Car, B - Goat
  # A - Goat, B - Goat
  defp open_door(da, db) when da == :goat and db == :car do
    {:open, db}
  end

  defp open_door(da, db) when da == :car and db == :goat do
    {da, :open}
  end

  defp open_door(_da, db) do
    {:open, db}
  end
end
# Lets give it a shot, we should expect that Door 1 is never opened, but either 2 or 3 are.

GenerateMH.gen_random() |> PlayMH.guess(1)

We have the basis for a test - we can now look at how many times the contestant would win if they stick with their choice and how often they win when they change.

defmodule EvaluateGame do
  def calc_percent(games) do
    won = games |> Enum.count(fn game -> eval(game) == true end)
    won / length(games)
  end

  def eval(game) do
    case game.initial_guess do
      1 -> would_win(game.door_1)
      2 -> would_win(game.door_2)
      3 -> would_win(game.door_3)
    end
  end

  def would_win(door) when door == :car do
    true
  end

  def would_win(_door) do
    false
  end
end
1..1000
|> Enum.map(fn _x -> GenerateMH.gen_random() |> PlayMH.guess() end)
|> EvaluateGame.calc_percent()

WTF??

So we seem to be converging on a probability of 1/3 (the more games you run, the close it will get to a third)

Does this make intuitive sense? What is going on?

A good description can be found here

> You pick a door with a goat originally and you switch. What do you have? A car. Suppose you don’t switch. What do you have? A goat. > So if you pick a goat originally, then switching gets a car and not switching gets a goat. > The only relevant question then, is what is the probability that you picked a goat originally? (2/3rds)