
Por exemplo, em três portas, atrás de uma há um prêmio. Você escolhe uma das três e o mestre de cerimônias abre uma das outras duas, mostrando que o carro não está lá. A porta que você escolheu continua com ⅓ de chance de ser a correta, mas a outra porta não escolhida ganha a possibilidade de conter o prêmio da que foi aberta, passando a ser de ⅔.
Isso acontece porque a porta com o prêmio e a porta escolhida (independente de ser a do prêmio ou não) influenciaram juntas na escolha da porta a ser aberta, mesmo que você não saiba qual a porta do prêmio.
Muita gente discorda disso, diz que se sobraram duas portas, as chances passa a ser ½+½ e não ⅓+⅔. Pode-se ficar horas (ou dias) discutindo isso. A melhor forma de se verificar isso é testando!
Vamos escrever uma classe que
MasterOfCeremonies
que oferece três portas, sendo uma premiada:
from random import choice
class MasterOfCeremonies:
__slots__ = '__doors __prize __choice'.split()
def __init__(self) -> None:
self.__doors = 'ABC'
self.__prize = choice(self__doors)
self.__choice = None
@property
def doors(self) -> str:
return self.__doors
@property
def wins(self) -> bool:
if not self.__choice:
raise TypeError
return self.__choice == self.__prize
def choose(self, door: str) -> None:
if door not in self.__doors:
raise ValueError
self.__choice = door
Nossa classe guarda três portas (
Para facilitar, vamos escolher sempre a porta do meio:
A
, B
e C
), apenas uma premiada. Para testar, podemos jogar mil vezes e vermos em quantas vezes ganhamos.Para facilitar, vamos escolher sempre a porta do meio:
if __name__ == '__main__':
wins = 0
for _ in range(1000):
wc = MasterOfCeremonies()
door = wc.doors[1] # sempre a porta do meio
wc.choose(door)
wins += 1 if wc.wins else 0
print('Wins:', wins)
Não importa quantas vezes você execute esse programa, vai sempre retornar um valor próximo de 333 vitórias – o que faz todo sentido! São mil lances, ⅓ dá 333.
Agora vamos adicionar o paradoxo: um método que abre aleatoriamente uma porta sem prêmio e outro que permite ao jogador trocar para a porta fechada restante.
Dentro da classe
Agora vamos adicionar o paradoxo: um método que abre aleatoriamente uma porta sem prêmio e outro que permite ao jogador trocar para a porta fechada restante.
Dentro da classe
MasterOfCeremonies
adicione os seguintes métodos:
def remove(self) -> None:
if not self.__choice or len(self.__doors) == 2:
raise TypeError
doors = set(self.__doors)
others = doors - {self.__choices, self.__prize}
other = choice(list(others))
doors -= {other}
self.__doors = ''.join(list(doors))
def change(self) -> str:
if not (self.__choice and len(self.__doors) == 2):
raise TypeError
doors = set(self.__doors)
doors -= {self.__choice}
self.__choice = list(doors)[0]
return self.__choice
Agora vamos mudar nosso procedimento principal para trocar de porta após a abertura (
remove
) da porta sem prêmio:
if __name__ == '__main__':
wins = 0
for _ in range(1000):
wc = MasterOfCeremonies()
door = wc.doors[1] # sempre a porta do meio
mc.choose(door)
mc.remove() # descarta uma das portas sem prêmio
door = mc.change() # troca a porta escolhida
wins += 1 if wc.wins else 0
print('Wins:', wins)
Agora vem o mindfuck: não importa quantas vezes você execute esse programa, o número de vitórias em mil será sempre por volta de 667, ⅔ das tentativas!
Ou seja, o paradoxo realmente funciona. Volte lá na Wikipédia, porque a explicação é realmente muito boa. ;-)
Ou seja, o paradoxo realmente funciona. Volte lá na Wikipédia, porque a explicação é realmente muito boa. ;-)
[]’s
PS: Eu ia escrever os códigos em Prolog, pois sua abordagem de lidar com domínio de verdades é muito conveniente para este problema, no entanto Python é muito mais didática: já basta a dificuldade em entender o Paradoxo de Monty Hall, não precisamos de mais complicação com uma implementação complexa.