One of the most famous probability puzzles, which initially tricked PhDs all over the world in the past few decades (originally posed and solved in 1975), is the "Monty Hall Problem", named after the original host (Monty Hall) of Let's Make a Deal.
As posed in the "viral" (for its time) Parade magazine column in 1990, by reader Craig Whitaker writing to Marilyn vos Savant:
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?
The optimal strategy, definitively, is to switch away from your initial choice - giving you 2/3 chance of winning the car, as opposed to only 1/3 if you stay with your original selection.
This has been proven time and again, including with straight forward illustrations on the linked Wikipedia page (these illustrations are included in the end of this post).
But doing the work yourself is the best way to learn, right? So I wrote a simple simulator in Python, included below, that you can run yourself to see this in action.
Over 100,000 runs (set this number to whatever you like; line 6, sims variable), the "switch" strategy clearly wins 2/3 of the time:
import random as randAnd the illustrations from the Wikipedia page:
import time
import csv
filename = "C:\\temp\\Monty_Hall_" + "Sims_ao_" + time.strftime("%m_%d_%Y") + ".csv"
sims = 100000
trials = []
global switchWin, stayWin
def callRand():
r = rand.random()
return r
def assignChoice():
r = callRand()
if r < (1 / 3):
choice = 1
elif r < (2 / 3):
choice = 2
else:
choice = 3
return choice
def assignCar():
r = callRand()
if r < (1 / 3):
car = 1
elif r < (2 / 3):
car = 2
else:
car = 3
return car
def montyStandard(n, r, choice, car, strategy):
global stayWin, switchWin
if choice == 1:
if car == 2:
openDoor = 3
elif car == 3:
openDoor = 2
else:
if r < 0.5:
openDoor = 2
else:
openDoor = 3
elif choice == 2:
if car == 1:
openDoor = 3
elif car == 3:
openDoor = 1
else:
if r < 0.5:
openDoor = 1
else:
openDoor = 3
elif choice == 3:
if car == 1:
openDoor = 2
elif car == 2:
openDoor = 1
else:
if r < 0.5:
openDoor = 1
else:
openDoor = 2
if strategy == 'Switch':
if (openDoor == 1 and choice == 2) or (openDoor == 2 and choice == 1):
newChoice = 3
elif (openDoor == 2 and choice == 3) or (openDoor == 3 and choice == 2):
newChoice = 1
elif (openDoor == 3 and choice == 1) or (openDoor == 1 and choice == 3):
newChoice = 2
elif strategy == 'Stay':
newChoice = choice
if newChoice == car:
win = 1
else:
win = 0
if strategy == 'Switch' and win == 1:
switchWin += 1
elif strategy == 'Stay' and win == 1:
stayWin += 1
resultDict = {'Sim #': n, 'Strategy': strategy, 'Winner': win, 'Initial Choice': choice, 'Final Choice': newChoice,
'Car Door': car, 'Open Door': openDoor}
return resultDict
def printData():
columnNames = ["Sim #", "Strategy", "Winner", "Initial Choice", "Final Choice", "Car Door", "Open Door"]
with open(filename, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=columnNames)
writer.writeheader()
writer.writerows(trials)
def run():
global switchWin, stayWin
switchWin = stayWin = 0
for i in range(sims):
r = callRand()
choice = assignChoice()
car = assignCar()
trials.append(montyStandard(i, r, choice, car, 'Switch'))
trials.append(montyStandard(i, r, choice, car, 'Stay'))
printData()
print('Sims: ' + str(sims) + '; Switch Wins: ' + str(float(switchWin) / float(sims)) + ', Stay Wins: ' + str(
float(stayWin) / float(sims)))
run()