Sunday, March 1, 2015

Finishing up with Monty Hall

I've managed to break down my extensive Monty Hall algorithm to just twenty lines of code (though, in Racket, that concept is abstract...), one struct and five functions. It also runs incredibly faster, processing 100,000,000 entries in a little bit less than time than it took the original to process 100,000. This was all possible through some heavy reductions, followed by a clever leap of faith.



As I was building this second implementation, I sought to reduce the 'Gameshow' to just being a list of six-- the first three representing the player/host's choice, and then the second three representing the doors. This would make it all one structure. This would vastly improve the time it would take to generate the sample set-- or at least I thought. As I started working on the host-reveal function for the second time, I simply could not find a smooth way to claw through every possible case-- this is due to the fact they're we're altering the player/host's choice list, while cycling through the door list. This involves several arguments, because you need to maintain the original door list, and be prepared to return the altered player choice list at point-- meaning you'll need to append to the end the original player choice (after you sub in the added -1). This is all quite dynamic for something iterating through a pair of lists, so I became a bit skeptical that this was the best way handle it... worse yet, was the fact that these would all need to be placed into a list of 'revealed gameshows' and then evaluated. Yikes.

So then, the idea became to have simultaneous creation and evaluation. It seemed like a sort of lofty goal, but then after some thought I came to an interesting conclusion about the Monty Hall Problem, which helped my perception in implementation and may help yours in understanding how it comes out to 1/3 odds.

The Take Home

I remember that list-ref returns a given item in the list, according to an index. This is something you almost never do with a random variable, but this time it worked just the way I wanted it to. If you substitute in 1-3 into a list of doors, it represents player's choice. So, if the value returned is a 1, this means the player correctly chose the car, if not, then they did not choose the car.

It seems like common sense, but it illuminates one of the important principles of thinking through the Monty Hall problem: You're going to win (...either by staying or switching). You see, as I work through this model, I completely disregard the host's choice.  After all, the final Monty Hall proposition is that you either chose the car, and would win by staying, or you didn't choose the car, and would win by switching. And from the outset, with three possible choices, you're more likely from the outset to have chosen a goat. All that has changed here is that host has revealed one of the possible choices, and made it a binary affair, reiterating that you win either by staying or by switching.

Now with this assumption all we need to operate is a random door list, and a boolean evaluation of whether our random choice into the list brings back a car. If it does, that's one for staying. If it doesn't, that's one for switching.

And with that, we just need a number of times to perform this operation. No structs or lists involved. Sure, I used a 'collection' struct, but it can also be done with two ints.

If you interested for the differences line by line, check out this site, which compares two files and returns the differences. As always, the code is always available in my Github.

At this point, I think I can call this one closed. I imagine there's a few more tweaks that could be made, but this function as it is would be great for any project using this data. :)


1 comment:

  1. Some folks were kind enough to point out some inaccuracies and oversight in the code, so I'll be updating again soon... I may not make a blog post for it though! Just stay tuned.

    ReplyDelete