Skip to main content

The Monty Hall Problem in 10 Python Lines

Background of the Problem

Many will remember the game show "Let´s make a Deal" from the 90ies where candidates had to choose one of three gates. Behind one gate, the prize was always hidden, and behind the other gates lurked blanks, i.e. the Zonk or, in the USA with presenter Monty Hall, goats. At the start, the candidate always chooses a gate behind which he believes the prize to be hidden. Then, the presenter can try to change the candidate´s mind to other gates by offering cash. He can also open gates in order to increase the excitement.

This opening of gates asks the candidate to stick with his previous choice or to switch to the last remaining gate. This is the heart of the problem. Intuitively, the majority believes that it does not matter and that the chances of winning remain at one-third both times. However, the odds of winning increase to two-thirds if one switches. Actually, it is very simple - if I do not switch, the situation is the same as if my gate had been opened immediately, i.e. one-third. The remaining alternative must have odds of two-thirds, because the total must result in 100%, i.e. three-thirds.

The Simulation

When I first read it more than 10 years ago, I did not really want to believe it, so I programmed it in Java as simulation and was finally convinced by the facts. In this blog entry, I would like to use the specific example in order to demonstrate such a simulation with Python in a form as concise as possible. 

Firstly, the code:

from random import randint, sample
numberDoors, trials, results = 5, 1000000, {'stayed':0,'switched':0}
for i in range(trials):
   doors=set(range(1,numberDoors+1))
   doorPlayer, doorPrize = sample(doors,1).pop(), sample(doors,1).pop()
   doorOpened    = sample(doors.difference(set((doorPlayer, doorPrize))),1).pop()
   doorAlternate = sample(doors.difference(set((doorOpened, doorPlayer))),1).pop()
   results['stayed']   += 1 if doorPlayer    == doorPrize else 0
   results['switched'] += 1 if doorAlternate == doorPrize else 0
print (results,results['switched']/(results['stayed']+results['switched']))

I find it impressive that Python enables such a simulation in only 10 lines and in relatively readable form. Here, I am relying on the somewhat neglected sets in Python. These can be very helpful for data evaluation programming because they performantly enable the reconciliation of sets. Within Python, sets are formations such as lists or tuples, with the exception that they may only contain each value once and the order is secondary.

The code is explained here:

  1. 1: Importing functions for random drawings.
  2. 2: Initializing and stocking the number of gates, the number of test runs and the filing of results.
  3. 3: Loop body
  4. 4: Generating a set with the gate numbers.
  5. 5: Random drawing of a gate with the prize and the gate chosen by the player. The sample function extracts a subset of length 1 from the goal set, from which we extract one single value via pop() in order to keep it as integer.
  6. 6: Random drawing of all gates opened by the host. For this purpose, the set of the previous gates must first be deducted from the set of all gates.
  7. 7: Identification of the remaining gate
  8. 8: Evaluation of the result if one sticks to one´s choice. For this purpose, I use the so-called temporary operator. This enables easy decisions between two alternatives without a separate if-block.
  9. 9: Evaluation of the result if one switches.
  10. 10: Display of the results and calculating the probability of winning in case of a switch.  

Result

The result is approximately 0.667%, i.e. two-thirds. Now one may wonder why I have gone to such lengths to randomly draw the remaining gate in line 7, seeing that there is only one gate left anyway. Now, I have not only simulated the problem here in 10 lines, but also created the possibility to simulate the problem for a game with 4 or more gates. The result: in case of 4 gates, the result is 0.60%, in case of 5 gates 0.57%. As expected, increasing the number of gates reduces the usefulness of switching gates as the residual probability is distributed between more alternatives.   

Stefan Seltmann
Stefan Seltmann
Lead Expert
Stefan loves programming, particularly when data engineering and data science are involved. He's turned his hobby into a career and has earned a reputation as a "phone a friend" whenever there's a tricky Python or Spark software development problem.
#CodeFirst, #TestMore, #CodeDoctor