user1777667 user1777667 - 4 months ago 15
Python Question

Python OOP Monty Hall not giving the expected results

Trying out some OOP in python, I tried to create a Monty Hall Problem simulation that is giving odd results. I implement three different strategies that a player can choose from, either to stay with the first door selected, switch to the second closed door, or randomly choose between them.

import random

class Door():
behind = None
is_open = False
is_chosen = False
def __init__(self,name=None):
self.name = name
def open(self):
self.is_open = True
def choose(self):
self.is_chosen = True

class Goat():
is_a = 'goat'

class Car():
is_a = 'car'

class Player():
door = None
def choose(self,door):
self.door = door
self.door.choose()
def open(self):
self.door.open()
if self.door.behind.is_a == 'car':
return True
return False


def play(strategy):
player = Player()
items = [Goat(),Goat(),Car()]
doors = [Door(name='a'),Door(name='b'),Door(name='c')]
for door in doors:
item = items.pop()
door.behind = item
random.shuffle(doors)
player.choose(random.choice(doors))
if strategy == 'random':
if random.choice([True,False]):
for door in doors:
if not door.is_open and not door.is_chosen:
final = door
break
else:
final = player.door
elif strategy == 'switch':
for door in doors:
if not door.is_open and not door.is_chosen:
final = door
break
elif strategy == 'stay':
final = player.door
player.choose(final)
if player.open():
return True
else:
return False


## Play some games
for strategy in ['random','switch','stay']:
results = []
for game in range(0,10000):
if play(strategy):
results.append(True)
else:
results.append(False)

## Gather the results
wins = 0
loses = 0
for game in results:
if game:
wins += 1
else:
loses += 1
print 'results:\tstrategy={}\twins={}\tloses={}'.format(strategy,str(wins),str(loses))


But every time I run it, I get something like:

results: strategy=random wins=3369 loses=6631
results: strategy=switch wins=3369 loses=6631
results: strategy=stay wins=3320 loses=6680


Why is this giving nearly the same results for each strategy? Shouldn't the 'switch' strategy give a ratio of ~66% wins and 'stay' give ~33%?

Answer

You're not playing the game correctly. After the contestant chooses a door, the host reveals a goat behind one of the other two doors, and then offers the contestant the opportunity to switch -- you're allowing a choice between three doors instead of two. Here's a revised play() function:

def play(strategy):
    player = Player()
    items = [Goat(), Goat(), Car()]
    doors = [Door(name='a'), Door(name='b'), Door(name='c')]

    random.shuffle(items)

    for door in doors:
        item = items.pop()
        door.behind = item

    player.choose(random.choice(doors))

    # player has chosen a door, now show a goat behind one of the other two

    show = None
    for door in doors:
        if not (door.is_open or door.is_chosen) and door.behind.is_a == 'goat':
            show = door
            show.open()
            break

    # The player has now been shown a goat behind one of the two doors not chosen

    if strategy == 'random':
        if random.choice([True, False]):
            for door in doors:
                if not (door.is_open or door.is_chosen):
                    final = door
                    break
        else:
            final = player.door

    elif strategy == 'switch':
        for door in doors:
            if not (door.is_open or door.is_chosen):
                final = door
                break

    elif strategy == 'stay':
        final = player.door

    player.choose(final)

    return player.open()

That produces results like:

results:    strategy=random wins=4977   loses=5023
results:    strategy=switch wins=6592   loses=3408
results:    strategy=stay   wins=3368   loses=6632