Follow

Follow

# A naive simulation of the Monty Hall problem

shibli049
·May 14, 2022·

Monty Hall problem is a probability puzzle, named after the original host of "Let's Make a Deal".

The problem became famous as a question from a reader's letter in the "Ask Marilyn" column in Parade magazine in 1990.

## Problem statement:

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?"

## Solution

You should switch the door. Because, the switching strategy has a 66.67% chance of winning, while the strategy that remains firm with the initial choice has only a 33.33% chance of winning.

Many readers of Parade magazine denied the explanation that switching is beneficial. Approximately ten thousand Parade magazine readers, including many readers with PhDs wrote to the author that the explanation was wrong. Even with explanations, simulations, and formal proofs, many still don't accept the answer of switching as the strategy.

Paul Erdős, one of the most prolific Hungarian mathematicians in history, remained unconvinced until he was shown a computer simulation demonstrating Marilyn vos Savant's predicted result.

I was also confused with the explanation, so I tried to write a naive python simulation of this problem.

## Simulation

``````# ---------------- the game ----------------
# player choose a door, and switch based on flag
def play_the_game(switch_door = False):
# number of doors
door_num = 3
doors, choosen = put_the_prize_behind_door(door_num)
# player choose a random door
player_choice = rand_range(door_num)
if switch_door:
# host show a door, behind which there is a goat
shown = show_door(door_num, choosen, player_choice)
final_choice = switch_to_new_door(doors, player_choice, shown)
return len(final_choice) == 1 and final_choice[0] == 1
else:
# no matter which door the presenter shows, player's decision is final
return doors[player_choice] == 1
``````

Now simulate the game N number of times, the bigger the N, the better the results.

``````# ---------------- tests ----------------
def simulate(N = 10001, switch_door = False):
success_count = 0
for i in range(N):
if play_the_game(switch_door):
success_count += 1
return generate_stat(switch_door, success_count, N)

if __name__ == "__main__":
n = 9999_99 # the bigger the size, the better the result

switch_rates = simulate(n, True)
print(switch_rates)

other_rates = simulate(n, False)
print(other_rates)
``````

## Result

With this simulation, I got a 66.6% win when switching the door. And, 33.3% when not switching the door.

The solution is so counterintuitive it seems absurd. Nevertheless, the solution is true in my simulation, and in many other simulations.

### Appendix

``````# ---------------- helpers ----------------
# creates a random number between 0 and n
def rand_range(n):
return random.randrange(n)

# choose an item randomly from the list
def rand_item(lst):
return random.choice(lst)

def put_the_prize_behind_door(door_num):
# initialize the doors
doors = [0] * door_num
# choose a random door to put the prize behind the door
choosen = rand_range(door_num)
# prize is set
doors[choosen] = 1
return doors,choosen

def show_door(door_num, choosen, player_choice):
# remove the door player choose, and the door behind which the prize is
choice = [ele for ele in range(door_num) if ele not in [choosen, player_choice]]
return rand_item(choice)

def switch_to_new_door(doors, player_choice, shown):
# remove the shown door and player choice and choose the 3rd door
return [doors[ind] for ind, elem in enumerate(doors) if ind not in [shown, player_choice]]

def generate_stat(switch_door, success_count, total):
return f"Switch door: {switch_door}, Total: {total}, Success: {success_count}, percent: {((1.0 * success_count)/total) * 100}"
``````