Source code for monty_hall_game.monty_hall_game
import uuid
import random
from .game_exceptions import InvalidGameInput
[docs]
class MontyHallGame(object):
"""Instantiates a new Monty Hall Game object.
Example usage::
game = MontyHallGame()
game.select_door(1)
game.let_host_open_door()
to_open = random.choice(game.available_doors())
game.select_door(to_open)
won = game.open_door()
"""
stats = {"changed": {"won": 0, "lost": 0}, "not_changed": {"won": 0, "lost": 0}}
[docs]
@staticmethod
def statistics():
"""Returns statistics about the winning chances of the "change door"
and "do not change door" strategies of all games played."""
# Get statistics class variable
stats = MontyHallGame.stats
s1 = "Changed and won: {} out of {}".format(
stats["changed"]["won"], stats["changed"]["won"] + stats["changed"]["lost"]
)
s2 = "Not changed and won: {} out of {}".format(
stats["not_changed"]["won"],
stats["not_changed"]["won"] + stats["not_changed"]["lost"],
)
return "{}\n{}".format(s1, s2)
def __init__(self):
self.game_id = str(uuid.uuid4())
self.__winning_door = random.randint(1, 3)
self.selected_door = None
self.opened_door = None
self.reselected_door = None
[docs]
def winning_door(self):
return self.__winning_door
[docs]
def select_door(self, door):
"""Use this function to let the play select a door. This function
should be called twice: Once at the beginning of the game for the initial
door choice. And once after calling :meth:`MontyHallGame.let_host_open_door`.
Arguments:
door (int):
The door to be selected. Valid values: [1, 2, 3]
"""
if not 1 <= door <= 3:
raise InvalidGameInput(
"Door must be an integer between 1 and 3, you provided {}.".format(door)
)
if door == self.opened_door:
raise InvalidGameInput("Cannot select opened door")
if self.selected_door is None:
self.selected_door = door
else:
self.reselected_door = door
[docs]
def available_doors(self):
"""Returns a list of doors that are still available for selection"""
a = set([1, 2, 3])
a.discard(self.opened_door)
return list(a)
[docs]
def let_host_open_door(self):
"""When this function is called, the host will open a door that contains no price.
:returns: The newly opened door number as an int."""
if self.selected_door is None:
raise InvalidGameInput("You must first select a door")
if self.opened_door is not None:
raise InvalidGameInput("The host has already opened a door")
opened = set([1, 2, 3])
opened.discard(self.__winning_door)
opened.discard(self.selected_door)
self.opened_door = random.choice(list(opened))
return self.opened_door
[docs]
def open_door(self):
"""Opens the door selected by the player
:returns: `True` if the player has won, `False` otherwise."""
if self.reselected_door is None or self.opened_door is None:
raise InvalidGameInput(
"You must select a door after letting the host open a door."
)
changed = self.selected_door != self.reselected_door
game_won = self.reselected_door == self.__winning_door
# Update statistics
if changed:
if game_won:
MontyHallGame.stats["changed"]["won"] += 1
else:
MontyHallGame.stats["changed"]["lost"] += 1
if not changed:
if game_won:
MontyHallGame.stats["not_changed"]["won"] += 1
else:
MontyHallGame.stats["not_changed"]["lost"] += 1
return game_won
if __name__ == "__main__":
game = MontyHallGame()
game.select_door(1)
game.let_host_open_door()
to_open = random.choice(game.available_doors())
game.select_door(to_open)
won = game.open_door()
if won:
print("You won")
else:
print("You lost")