Это хороший или плохой «симулятор» для Монти Холла? Как так? - PullRequest
17 голосов
/ 08 августа 2009

Вчера, пытаясь объяснить проблему Монти Холла другу во время урока, мы закончили писать код на Python, чтобы доказать, что если вы всегда поменяетесь местами, вы выиграете 2/3 раза. Мы придумали это:

import random as r

#iterations = int(raw_input("How many iterations? >> "))
iterations = 100000

doors = ["goat", "goat", "car"]
wins = 0.0
losses = 0.0

for i in range(iterations):
    n = r.randrange(0,3)

    choice = doors[n]
    if n == 0:
        #print "You chose door 1."
        #print "Monty opens door 2. There is a goat behind this door."
        #print "You swapped to door 3."
        wins += 1
        #print "You won a " + doors[2] + "\n"
    elif n == 1:
        #print "You chose door 2."
        #print "Monty opens door 1. There is a goat behind this door."
        #print "You swapped to door 3."
        wins += 1
        #print "You won a " + doors[2] + "\n"
    elif n == 2:
        #print "You chose door 3."
        #print "Monty opens door 2. There is a goat behind this door."
        #print "You swapped to door 1."
        losses += 1
        #print "You won a " + doors[0] + "\n"
    else:
        print "You screwed up"

percentage = (wins/iterations) * 100
print "Wins: " + str(wins)
print "Losses: " + str(losses)
print "You won " + str(percentage) + "% of the time"

Мой друг подумал, что это хороший способ (и хороший симулятор), но у меня есть свои сомнения и опасения. Это на самом деле достаточно случайно?

Проблема, с которой я столкнулся, заключается в том, что все варианты жестко запрограммированы.

Это хороший или плохой «симулятор» для проблемы Монти Холла? Как получилось?

Можете ли вы придумать лучшую версию?

Ответы [ 17 ]

1 голос
/ 22 июля 2017

Еще одно «доказательство», на этот раз с Python 3. Обратите внимание на использование генераторов, чтобы выбрать 1) какую дверь открывает Монти и 2) на какую дверь игрок переключается.

import random

items = ['goat', 'goat', 'car']
num_trials = 100000
num_wins = 0

for trial in range(num_trials):
    random.shuffle(items)
    player = random.randrange(3)
    monty = next(i for i, v in enumerate(items) if i != player and v != 'car')
    player = next(x for x in range(3) if x not in (player, monty))
    if items[player] == 'car':
        num_wins += 1

print('{}/{} = {}'.format(num_wins, num_trials, num_wins / num_trials))
0 голосов
/ 06 июля 2014

Вот мое решение проблемы MontyHall, реализованной в python.

Это решение использует numpy для скорости, а также позволяет изменять количество дверей.

def montyhall(Trials:"Number of trials",Doors:"Amount of doors",P:"Output debug"):
    N = Trials # the amount of trial
    DoorSize = Doors+1
    Answer = (nprand.randint(1,DoorSize,N))

    OtherDoor = (nprand.randint(1,DoorSize,N))

    UserDoorChoice = (nprand.randint(1,DoorSize,N))

    # this will generate a second door that is not the user's selected door
    C = np.where( (UserDoorChoice==OtherDoor)>0 )[0]
    while (len(C)>0):
        OtherDoor[C] = nprand.randint(1,DoorSize,len(C))
        C = np.where( (UserDoorChoice==OtherDoor)>0 )[0]

    # place the car as the other choice for when the user got it wrong
    D = np.where( (UserDoorChoice!=Answer)>0 )[0]
    OtherDoor[D] = Answer[D]

    '''
    IfUserStays = 0
    IfUserChanges = 0
    for n in range(0,N):
        IfUserStays += 1 if Answer[n]==UserDoorChoice[n] else 0
        IfUserChanges += 1 if Answer[n]==OtherDoor[n] else 0
    '''
    IfUserStays = float(len( np.where((Answer==UserDoorChoice)>0)[0] ))
    IfUserChanges = float(len( np.where((Answer==OtherDoor)>0)[0] ))

    if P:
        print("Answer        ="+str(Answer))
        print("Other         ="+str(OtherDoor))
        print("UserDoorChoice="+str(UserDoorChoice))
        print("OtherDoor     ="+str(OtherDoor))
        print("results")
        print("UserDoorChoice="+str(UserDoorChoice==Answer)+" n="+str(IfUserStays)+" r="+str(IfUserStays/N))
        print("OtherDoor     ="+str(OtherDoor==Answer)+" n="+str(IfUserChanges)+" r="+str(IfUserChanges/N))

    return IfUserStays/N, IfUserChanges/N
0 голосов
/ 17 декабря 2013

Вот тот, который я сделал ранее:

import random

def game():
    """
    Set up three doors, one randomly with a car behind and two with
    goats behind. Choose a door randomly, then the presenter takes away
    one of the goats. Return the outcome based on whether you stuck with
    your original choice or switched to the other remaining closed door.
    """
    # Neither stick or switch has won yet, so set them both to False
    stick = switch = False
    # Set all of the doors to goats (zeroes)
    doors = [ 0, 0, 0 ]
    # Randomly change one of the goats for a car (one)
    doors[random.randint(0, 2)] = 1
    # Randomly choose one of the doors out of the three
    choice = doors[random.randint(0, 2)]
    # If our choice was a car (a one)
    if choice == 1:
        # Then stick wins
        stick = True
    else:
        # Otherwise, because the presenter would take away the other
        # goat, switching would always win.
        switch = True
    return (stick, switch)

У меня также был код для запуска игры много раз, и я сохранил его и пример вывода в этом репозитории .

0 голосов
/ 22 ноября 2011

Другой пример кода доступен по адресу: http://standardwisdom.com/softwarejournal/code-samples/monty-hall-python/

Код немного длиннее и может не использовать некоторые интересные функции Python, но я надеюсь, что он хорошо читается. Использовал Python именно потому, что у меня не было никакого опыта в этом, поэтому обратная связь приветствуется.

0 голосов
/ 11 марта 2013

Вот другой вариант, который я считаю наиболее интуитивным. Надеюсь, это поможет!

import random

class MontyHall():
    """A Monty Hall game simulator."""
    def __init__(self):
        self.doors = ['Door #1', 'Door #2', 'Door #3']
        self.prize_door = random.choice(self.doors)
        self.contestant_choice = ""
        self.monty_show = ""
        self.contestant_switch = ""
        self.contestant_final_choice = ""
        self.outcome = ""

    def Contestant_Chooses(self):
        self.contestant_choice = random.choice(self.doors)

    def Monty_Shows(self):
        monty_choices = [door for door in self.doors if door not in [self.contestant_choice, self.prize_door]]
        self.monty_show = random.choice(monty_choices)

    def Contestant_Revises(self):
        self.contestant_switch = random.choice([True, False])
        if self.contestant_switch == True:
            self.contestant_final_choice = [door for door in self.doors if door not in [self.contestant_choice, self.monty_show]][0]
        else:
            self.contestant_final_choice = self.contestant_choice

    def Score(self):
        if self.contestant_final_choice == self.prize_door:
            self.outcome = "Win"
        else:
            self.outcome = "Lose"

    def _ShowState(self):
        print "-" * 50
        print "Doors                    %s" % self.doors
        print "Prize Door               %s" % self.prize_door
        print "Contestant Choice        %s" % self.contestant_choice
        print "Monty Show               %s" % self.monty_show
        print "Contestant Switch        %s" % self.contestant_switch
        print "Contestant Final Choice  %s" % self.contestant_final_choice
        print "Outcome                  %s" % self.outcome
        print "-" * 50



Switch_Wins = 0
NoSwitch_Wins = 0
Switch_Lose = 0
NoSwitch_Lose = 0

for x in range(100000):
    game = MontyHall()
    game.Contestant_Chooses()
    game.Monty_Shows()
    game.Contestant_Revises()
    game.Score()
    # Tally Up the Scores
    if game.contestant_switch  and game.outcome == "Win":  Switch_Wins = Switch_Wins + 1
    if not(game.contestant_switch) and game.outcome == "Win":  NoSwitch_Wins = NoSwitch_Wins + 1
    if game.contestant_switch  and game.outcome == "Lose": Switch_Lose = Switch_Lose + 1
    if not(game.contestant_switch) and game.outcome == "Lose": NoSwitch_Lose = NoSwitch_Lose + 1

print Switch_Wins * 1.0 / (Switch_Wins + Switch_Lose)
print NoSwitch_Wins * 1.0 / (NoSwitch_Wins + NoSwitch_Lose)

Обучение остается тем же, что переключение увеличивает ваши шансы на выигрыш, 0,665025416127 против 0,33554730611 из вышеприведенного пробега.

0 голосов
/ 20 июля 2018

Я только что обнаружил, что общий коэффициент выигрыша составляет 50%, а коэффициент проигрыша - 50% ... Такова пропорция выигрыша или проигрыша в зависимости от выбранного окончательного варианта.

  • % побед (оставшихся): 16,692
  • % Wins (переключение): 33,525
  • % Потери (пребывания): 33.249
  • % Потери (переключение): 16.534

Вот мой код, который отличается от вашего + комментариями, поэтому вы можете запустить его с небольшими итерациями:

import random as r

#iterations = int(raw_input("How many iterations? >> "))
iterations = 100000

doors = ["goat", "goat", "car"]
wins_staying =  0
wins_switching = 0  
losses_staying =  0
losses_switching = 0  



for i in range(iterations):
    # Shuffle the options
    r.shuffle(doors)
    # print("Doors configuration: ", doors)

    # Host will always know where the car is 
    car_option = doors.index("car")
    # print("car is in Option: ", car_option)

    # We set the options for the user
    available_options = [0, 1 , 2]

    # The user selects an option
    user_option = r.choice(available_options)
    # print("User option is: ", user_option)

    # We remove an option
    if(user_option != car_option ) :
        # In the case the door is a goat door on the user
        # we just leave the car door and the user door
        available_options = [user_option, car_option]
    else:
        # In the case the door is the car door 
        # we try to get one random door to keep
        available_options.remove(available_options[car_option])
        goat_option = r.choice(available_options)
        available_options = [goat_option, car_option]


    new_user_option = r.choice(available_options)
    # print("User final decision is: ", new_user_option)

    if new_user_option == car_option :
        if(new_user_option == user_option) :
            wins_staying += 1
        else :
            wins_switching += 1    
    else :
        if(new_user_option == user_option) :
            losses_staying += 1
        else :
            losses_switching += 1 


print("%Wins (staying): " + str(wins_staying / iterations * 100))
print("%Wins (switching): " + str(wins_switching / iterations * 100))
print("%Losses (staying) : " + str(losses_staying / iterations * 100))
print("%Losses (switching) : " + str(losses_switching / iterations * 100))
0 голосов
/ 08 августа 2009

Монти никогда не открывает дверь с машиной - в этом весь смысл шоу (он не твой друг и знает, что за каждой дверью)

...