You, lucky contestant, are on a game show! You stand a chance to win a car (with a trade-in value of $50k)!
The host, one Monty Hall, describes the game to you as follows:
Here before you, you see three doors -- A, B, and C! Behind one of them is the car.
We will start by having you pick one door, but do not open it.
Then, I will reveal what is behind one of the two doors you did not choose (needless to say, it will not be the car!)
At that point, you may either keep your first choice, OR you may switch your choice to another door.
If you can identify which door has the car behind it, you get to keep the car (or the money).
The question for you is this: as a winning strategy, should you (a) always stay with your original door choice, (b) always switch, or (c) it doesn't matter?
You, being an accomplished computational scientist, decide that rather than thinking hard about this, you're just going to simulate it using the Monte Carlo method (http://en.wikipedia.org/wiki/Monte_Carlo_method).
Let's start by setting up the problem.
# grab the pseudo-random # generator module in Python: http://blog.doughellmann.com/2010/10/pymotw-random-pseudorandom-number.html
import random
# now, build a function to create 3 doors, with one car behind them.
# this function will return a dictionary with keys A, B, and C, containing associated values 'empty' or 'car'.
def create_doors():
doors = {}
doors['A'] = 'empty'
doors['B'] = 'empty'
doors['C'] = 'empty'
# randomly choose *one* of the three doors
car_is_behind = random.choice(doors.keys())
doors[car_is_behind] = 'car'
return doors
Next, here are two functions, one which simulates choice (a) and one which simulates choice (b). If the function returns true, you've won! If the function returns false, you've lost.
def always_switch():
# set up the problem
doors_d = create_doors()
# pick a door
doors = ['A', 'B', 'C']
my_choice = random.choice(doors)
doors.remove(my_choice)
assert len(doors) == 2, "you should only have two doors left..."
# now Monty Hall picks a door:
while 1:
monty_choice = random.choice(doors)
if doors_d[monty_choice] != 'car': # he'll never reveal the car!
break
doors.remove(monty_choice)
# now, because you always switch, you're left with monty's non-choice:
assert len(doors) == 1, "you should only have one door left..."
my_choice = doors[0]
if doors_d[my_choice] == 'car':
return True # you win!
return False # you lose :(
def never_switch():
# set up the problem
doors_d = create_doors()
# pick a door
doors = ['A', 'B', 'C']
my_choice = random.choice(doors)
doors.remove(my_choice)
assert len(doors) == 2, "you should only have two doors left..."
# now Monty Hall picks a door:
while 1:
monty_choice = random.choice(doors)
if doors_d[monty_choice] != 'car': # he'll never reveal the car!
break
doors.remove(monty_choice)
# now, because you always switch, you're left with monty's non-choice:
assert len(doors) == 1, "you should only have one door left..."
# you stick with your original choice:
if doors_d[my_choice] == 'car':
return True # you win!
return False # you lose :(
# ok, let's try this out!
print always_switch()
print always_switch()
print always_switch()
print never_switch()
print never_switch()
print never_switch()
False True False False False True
OK, a couple of notes here.
First, this is a true implementation of the Monty Hall scenario, right? Even though you're randomly choosing doors, it's no different from what you'd normally be doing, right -- guessing?
Second, every time you run this, you will get a different set of answers -- because we're using a random number generator.
Write a loop that runs always_switch() many, many times, and counts up the number of times you win vs the number of times you lose.
Do the same for never_switch().
What is your conclusion? Should you always switch, never switch, or does it not matter? How much more likely are you to win in one case over another? Please answer in comments in the code.
Write a new function, 'monty_hall(do_switch)' where 'do_switch' is either True or False, that combines the functionality of 'always_switch' and 'never_switch', and returns True if you've won and False if you've lost. For example, 'monty_hall(False)' will return random results from the same decision making process as 'never_switch', and 'monty_hall(True)' will return random results from the same process as 'always_switch'.
Then, re-write the loops in the first question to use only this new function. Your loop should no longer contain direct calls to 'always_switch' and 'never_switch', but you should get the same qualitative results.
Copy 'create_doors' to 'create_doors2' and change the function so that it returns a dictionary where the car is always behind door A. Then create a copy of the functions in A or B that use this new create_doors2. Do your results change? Please answer in comments in the code.
Copy 'create_doors2' to 'create_doors3' and change the function so that it returns a dictionary with 10 doors, and make a new Monty Hall (monty_hall3?) function that uses this new 'create_doors3', in which Monty opens 8 doors for you. Note, you'll need to alter (not remove!) the assert statements.
How does the probability of winning change with 10 doors instead of 3? (Just estimate based on the numbers you generate.) Please answer in a Markdown cell (Cell... Markdown on the menus above)
Extra pixie dust credit if you can give a general formula -- note that you can use LaTeX math formatting like so (double click on this cell to see the underlying formatting):
$p_{winning} = 1/2$
Prepare arguments for class next Monday!