# Monty Hall with a billion doors

In order to provide intuition behind the solution of the Monty Hall problem, Antonio Cangiano says:

If there were a billion doors, you picked one, and then Monty proceeded to open up all the remaining doors but one, we’d have a situation where it would be extremely unlikely that you picked the right door at the beginning, while it would be extremely likely that the remaining door was the one that was concealing the car.

Now, what happens when there are more than three doors. In this post, I will modify the solution of my last post to work for any number of doors. It requires a little change to the program.

`````` import Data.List (delete, (\\) )
import Text.Printf (printf)
``````

This time, instead of defining `Door` by listing all alternatives, I define it as an instance of `Bounded` class.

`````` data Door   = Door Int deriving (Show, Eq)
numDoors    = 3

instance Bounded Door where
minBound = Door 1
maxBound = Door numDoors

instance Enum Door where
toEnum      n     = Door n
fromEnum (Door n) =    n

doors = [minBound .. maxBound] :: [Door]
``````

`Object` are the same as before.

`````` data Object = Car | Goat deriving (Show, Eq)
type Universe = [Object]
``````

There is one car; all other doors have goats. This can still be generated using the `shuffle` function.

`````` nature :: MC Universe
nature = shuffle numDoors (Car: repeat Goat)
``````

The contestant open one door at random.

`````` contestant :: MC Door
contestant = sample numDoors doors
``````

The options available to the host remain the same as before.

`````` options :: Universe -> Door -> [Door]
options universe door = filter (\d -> Goat == open universe d) remainder
where remainder = delete door doors
``````

We need a generic function to see what is behind a closed door.

`````` open :: Universe -> Door -> Object
open universe (Door n) = universe !! (n-1)
``````

The host opens all but one door. We can do this by replacing the `sample` function with `sampleSubset` function.

`````` host :: [Door]-> MC [Door]
host o = sampleSubset (numDoors-2) l o where l = length o
``````

The strategies are now whether to stick or switch based on the door that the contestant chose, and the doors that the host opened.

`````` strategyStick :: Door -> [Door] -> Door
strategyStick d1 d2 = d1

strategySwitch :: Door -> [Door] -> Door
strategySwitch d1 d2 = head (doors \\ (d1:d2))
``````

The reward function is same as before.

`````` reward :: Universe -> Door -> Double
reward u d = if Car == open u d then 1.0 else 0.0
``````

And so is the generation of the ranom experiment.

`````` randomVariable :: (Door -> [Door] -> Door) -> MC Double
randomVariable strategy = do
u <- nature
c <- contestant
h <- host (options u c)
let r = reward u (strategy c h)
return r
``````

And we see the result.

`````` main = let
n     = 100000
seed  = 42
stats = repeatMC n (randomVariable strategyStick) `evalMC` mt19937 seed
in do
putStrLn \$ printf "\nnumDoors                : %d" numDoors
putStrLn \$ printf "Mean                    : %f" (sampleMean stats)
putStrLn \$ printf "99%% Confidence interval : (%f, %f)"
`uncurry` (sampleCI 0.99 stats)
``````

Now lets see the results. For

``````numDoors                : 3
Mean                    : 0.3334800000000033
99% Confidence interval : (0.3296397390134338, 0.33732026098657275)

numDoors                : 30
Mean                    : 0.03466999999999957
99% Confidence interval : (0.03317983597888913, 0.03616016402111001)

numDoors                : 300
Mean                    : 0.0038399999999999784
99% Confidence interval : (0.0033362101507491866, 0.00434378984925077)
``````

Well, I think that you get the idea. I am not going to run this thing for a billion doors.

• Cristophone: I think that I am taking care of excluding the door which has the car. The `host` function is called on `options u c` where `options` function filters all doors that have a `Goat` behind them, thus excluding the `Car`. So, I think that I am taking care of the `Car` unless, I overlooked something really simple.