Simular o problema de Monty Hall [fechado]

8

Eu nunca fui capaz de entender o problema de Monty Hall . Aqui está a premissa:

Suponha que você esteja em um game show e tenha a opção de três portas: Atrás de uma porta está um carro; atrás dos outros, cabras. Você escolhe uma porta, digamos o número 1, e o anfitrião, que sabe o que está por trás das portas, abre outra porta, digamos o número 3, que tem uma cabra. Ele então diz para você: "Você quer pegar a porta número 2?" É a sua vantagem mudar sua escolha?

Execute 10.000 simulações. Saída da porcentagem de ganho de comutação. Por exemplo:

> 66.66733%
Bendytree
fonte
5
O anfitrião sabe onde o carro é, então ele nunca abre uma porta com o carro por trás dele
bendytree
6
Como o desafio está, é difícil argumentar que não é perfeitamente legal ter apenas 10.000 execuções do gerador de números aleatórios e somar quais delas ficam abaixo de 0,6666. Você pode dizer que não está realmente simulando o problema de Monty Hall. Mas se produz exatamente a mesma saída, o que realmente está faltando?
breadbox
Uma perspectiva histórica interessante (sobre o problema, não sobre o golfe): Qual porta possui o Cadillac? .
Cary Swoveland
3
O desafio ainda é um pouco ambíguo com relação às suposições que podemos fazer. Por exemplo, algumas das respostas provavelmente estão economizando uma quantidade significativa de código, assumindo que o carro estará sempre atrás da mesma porta ou que o jogador escolha a mesma porta todas as vezes.
Iszi 25/10
1
Enumerando todas as possibilidades é pelo menos tão esclarecedor como gerá-los aleatoriamente ...
Daniel Cristofani

Respostas:

4

JavaScript 52

for(i=s=0;i++<1e4;)s+=Math.random()<2/3;alert(s/100)

As portas são 1: [0,1 / 3), 2: [1 / 3,2 / 3), 3: [2/3, 1)

Suponha que o prêmio esteja sempre na porta 3. Se o hóspede pegar as portas 1 ou 2, que é o intervalo [0,2 / 3), e trocar, ele ganhou o prêmio.

Tristin
fonte
1
Parece que o CoffeeScript nos permite cortar um único caractere:i=s=0;s+=Math.random()<2/3while i++<1e4;alert s/100
Kerrick 05/10
3

J: 17 15

100%~+/2>?1e4$3

Ele escolhe uma porta aleatória - vamos rotular esses 0, 1 ou 2 onde 2 é a porta do carro - e calcula o benefício de alternar com base nessa lógica:

  • Se o jogador escolher a porta 0, o host abrirá a porta 1. A troca dará ao jogador um carro novo ( 1).
  • Se o jogador escolher a porta 1, o host abrirá a porta 0. A troca dará ao jogador um carro novo ( 1).
  • Se o jogador escolher a porta 2, a porta vencedora, o host abrirá a porta 0 ou a porta 1. De qualquer maneira, se o jogador trocar, ele ou ela encontrará uma cabra ( 0).

Em seguida, calcula o resultado como a soma da matriz anterior, dividida por 100.

Estou bastante instável com J, então tenho certeza de que isso poderia ser melhorado ainda mais.

pswg
fonte
3

R 115 100

A resposta da pseudo-simulação tem 23 caracteres:

sum(runif(1e4)>1/3)/100

mas aqui está uma simulação real:

D=1:3
S=function(x)x[sample(length(x),1)]
sum(replicate(1e4,{
C=S(D)
P=S(D)
H=S(D[-c(C,P)])
F=D[-c(P,H)]
C==F
}))/100
  1. D são as portas possíveis
  2. S é uma função para selecionar aleatoriamente um item de um vetor
  3. Cé a porta do carro (aleatória entre D)
  4. Pé a porta escolhida pelo jogador (aleatória entre D)
  5. Hé a porta escolhida pelo host (aleatória entre Dmenos Ce P)
  6. Fé a porta final escolhida pelo jogador (determinística: Dmenos Pe H)
  7. o sucesso é medido por C==F.

retornos: [1] 66.731

Editar

Eu posso salvar alguns caracteres não atribuindo a variáveis ​​e assumindo sem perda de generalidade que C==1:

D=1:3;S=function(x)x[sample(length(x),1)];sum(replicate(1e4,{P=S(D);1==D[-c(P,S(D[-c(1,P)]))]}))/100
modelo
fonte
2

Perl, 98 89 83 75 72 71 caracteres

Aqui está uma resposta séria que realmente executa a simulação:

sub c{($==rand 2)-"@_"?$=:&c}$n+=$%==c c($%=rand 3)for 1..1e4;say$n/100

Em cada iteração de loop, a escolha inicial do jogador é sempre a porta 2. Primeiro, a porta do carro é armazenada e $%, em seguida, uma porta diferente é selecionada para Monty Hall expor. Se a porta restante for igual a $%, a rodada será ganha.

(Variáveis ​​de pontuação do Perl $%e $=são usadas porque fazem truncamento inteiro gratuitamente).

caixa de pão
fonte
2

Powershell - 168 131 125 115

Código de golfe:

nal g Random;1..1e4|%{$C=g 3;$P=g 3;$T+=$C-eq(0..2|?{$_-ne$P-and$_-ne(0..2|?{$_-ne$P-and$_-ne$C}|g)})};"$($T/100)%"

Alterações do original:
aparadas 53 caracteres do script original com algumas modificações.

  • Espaços e parênteses removidos onde o PowerShell está perdoando.
  • Usou um ForEach-Objectloop, via %alias, em vez de while.
  • Intervalos numéricos usados ​​(por exemplo 0..2:) em vez de matrizes definidas explicitamente.
  • Removido writedo último comando - acontece que não preciso disso, afinal.
  • Alternou a expressão para a escolha do host em torno de usar a sintaxe de pipelining mais curta.
  • 10000 substituído por 1e4.
  • Tomou a sugestão de Joey e omitiu Get-a partir Get-Random. (Nota: essa modificação aumenta significativamente o tempo de execução. No meu sistema, ela saltou de cerca de 20 segundos para quase meia hora por execução!)
  • Usado truque de Rynant de fazer $T+=...em vez de if(...){$T++}.

Algumas notas:

Este script deve ser o mais conciso possível, além de ser o mais simulação possível do cenário de Monty Hall. Não faz suposições sobre onde o carro estará ou qual porta o jogador escolherá primeiro. Nem sequer são feitas suposições para qual porta específica o host escolherá em qualquer cenário. As únicas suposições restantes são aquelas que são realmente declaradas no problema de Monty Hall:

  • O anfitrião escolherá uma porta que o jogador não escolheu primeiro, que não contém o carro.
    • Se o jogador abriu a porta com o carro primeiro, isso significa que existem duas opções possíveis para o anfitrião.
  • A escolha final do jogador não será nem sua escolha inicial nem a escolha do anfitrião.

Ungolfed, com comentários:

# Setup a single-character alias for Random, to save characters later.
# Note: Script will run a lot (about 500 times) faster if you use Get-Random here.
# Seriously, as it currently is, this script will take about a half-hour or more to run.
# With Get-Random, it'll take less than a minute.
nal g Random;

# Run a Monty Hall simulation for each number from 1 to 10,000 (1e4).
1..1e4|%{

    # Set car location ($C) and player's first pick ($P) to random picks from a pool of 3.
    # Used in this way, Random chooses from 0..2.
    $C=g 3;$P=g 3;

    # Increment win total ($T) if the car is behind the door the player finally chooses.
    # (Player's final choice represented by nested script.)
    $T+=$C-eq(

        # Filter the doors (0..2) to determine player's final choice.
        0..2|?{

            # Player's final choice will be neither their original choice, nor the host's pick.
            # (Host's pick represented by nested script.)
            $_-ne$P-and$_-ne(

                # Filter the doors to determine host's pick.
                0..2|?{

                    # Host picks from door(s) which do not contain the car and were not originally picked by the player.
                    $_-ne$P-and$_-ne$C

                # Send filtered doors to Random for host's pick.
                }|g
            )
        }
    )
};

# After all simulations are complete, output overall win percentage.
"$($T/100)%"

# Variable & alias cleanup. Not included in golfed script.
rv C,P,T;ri alias:g

Eu executei esse script várias vezes e sempre gera resultados muito próximos da probabilidade de dois terços. Algumas amostras:

(Como acima)

  • 67,02%

(Usando Get-Randomcomo a definição de alias, em vez de apenas Random)

  • 66,92%
  • 67,71%
  • 66,6%
  • 66,88%
  • 66,68%
  • 66,16%
  • 66,96%
  • 66,7%
  • 65,96%
  • 66,87%
Iszi
fonte
2

Ruby 48 40 38

Meu código não faz nenhuma suposição sobre qual porta o prêmio estará sempre atrás ou qual porta o jogador sempre abrirá. Em vez disso, concentrei-me no que faz o jogador perder. Conforme o artigo da Wikipedia :

[...] 2/3 do tempo, a escolha inicial do jogador é uma porta que esconde uma cabra. Quando este for o caso, o anfitrião é forçado a abrir a outra porta [...] da cabra "Trocar" apenas falha em dar o carro quando o jogador escolhe a porta "direita" (a porta que esconde o carro) para começar.

Então, para simular isso (em vez de usar valores fixos), eu o modelei da seguinte forma:

  • o show escolhe aleatoriamente uma das 3 portas para esconder o prêmio
  • o jogador escolhe aleatoriamente 1 das 3 portas como sua primeira escolha
  • o jogador sempre muda, então, se sua primeira escolha foi a mesma do programa, ele perde

O código v1:

w=0;10000.times{w+=rand(3)==rand(3)?0:1};p w/1e2

O código v3 (graças a steenslag e Iszi!):

p (1..1e4).count{rand(3)!=rand(3)}/1e2

Alguns exemplos de valores de retorno:

  • 66,44
  • 66,98
  • 66,33
  • 67,2
  • 65,7
Jonathan Hefner
fonte
1
p (1..10000).count{rand(3)!=rand(3)}/1e2salva alguns caracteres.
steenslag
@steenslag Ah, é verdade! Obrigado! =)
Jonathan Hefner
1
Ruby não permite poderes de atalho de 10? Por exemplo: 1e4para 10000?
Iszi
@Iszi Sim, mas a notação científica produz uma flutuação, portanto nem sempre pode ser substituída. No entanto, é uma substituição viável na v2, economizando mais 2 caracteres!
Jonathan Hefner
1

Mathematica 42

Count[RandomReal[1,10^4],x_/;x>1/3]/100// N

66,79

DavidC
fonte
1

PowerShell, 90

$i=0
1..10000|%{$g=random 3;$n=0..2-ne$g;$g=($n,2)[!!($n-eq2)]|random;$i+=$g-eq2}
$i/10000

Comentado:

# Winning door is always #2

$i=0

# Run simulation 1,000 times
1..10000|%{

# Guess a random door
$g=random 3

# Get the doors Not guessed
$n=0..2-ne$g

# Of the doors not guessed, if either is the
# winning door, switch to that door.
# Else, switch to a random door.
$g=($n,2)[!!($n-eq2)]|random

# Increment $i if 
$i+=$g-eq2}

# Result
$i/10000
Rynant
fonte
Isso não gera uma porcentagem vencedora no formato especificado na pergunta. Além disso, salve alguns caracteres usando em 1e4vez de 10000.
Iszi
1

C, 101 95

float c,s,t,i;main(){for(;i<1e5;i++,c=rand()%3,s=rand()%3)i>5e4&c!=s?t++:t;printf("%f",t/5e4);}

Isso é para a simulação real. Para alguns códigos baratos de flexão de regras, são apenas 71 65 59:

p,i;main(){for(;i<1e5;rand()%5>1?i++:p++)printf("%f",p/1e5);}

Eu não fiz srand () porque as regras não diziam que eu precisava. Além disso, a versão mais barata imprime cerca de 30.000 números extras porque salva um caractere. Provavelmente estou perdendo alguns truques, mas fiz o melhor que pude.

Stuntddude
fonte
As variáveis ​​globais são garantidas como zero na inicialização. Mova suas declarações de variáveis maine você pode descartar as =0inicializações.
breadbox
1

Python 2: 72 66 64

from random import*
i=10000
exec"i-=randint(0,2)&1;"*i
print.01*i

Exemplo de saída: 66,49

Rees
fonte
1
Você pode salvar alguns caracteres usando em exec"i-=randint(0,2)&1;"*ivez do forloop.
Reintegrar Monica
@WolframH Obrigado, vou atualizá-lo agora.
Rees
Além disso, use em print.01*ivez de print i/100..
Reintegrar Monica
Solução agradável, mas falta um ponto e vírgula.
Daniel Lubarov
Muito verdadeiro. Atualizando agora ...
Rees
0

Peixe - 46 43

Isso está usando as mesmas suposições que Tristin fez:

aa*v>1-:?v$aa*,n;
v*a<$v+1$x! <
>a*0^<  $<

A direção para baixo em xrepresenta você inicialmente escolhendo a porta correta, esquerda e direita são os casos em que você escolheu uma porta diferente, e acima não é nada e rolará novamente.

Inicialmente, eu inicializei 10000com "dd"*, mas "dd"tinha que estar todos na mesma linha, e perdi algum espaço em branco. Serpenteando aa*a*a*eu consegui remover uma coluna e, finalmente, 3 caracteres. Ainda há um pouco de espaço em branco que eu não consegui me livrar, acho que isso é muito bom!

Triturador
fonte
0

PHP 140

Mas acho que isso não está funcionando direito. Alguma dica? Estou recebendo valores de 49 a 50.

$v=0;//victorys
for($i=0;$i<1e4;$i++){    
    //while the selection of the host ($r) equals the player selection or the car
    //h=removed by host, p=player, c=car
    while(in_array($h=rand(1,3),[$p=rand(1,3),$c=rand(1,3)])){}
    ($p!=$c)?$v+=1:0; //if the player changes the selection    
}
echo ($v/1e4)*100;
Carlos Goce
fonte
"Se o jogador mudar a seleção"?
Timtech #
Desculpe. Meu inglês não é bom. Quero dizer, primeiro eu faço um Ao tentar obter valores aceitáveis. Porque o "host" não pode remover uma porta que contém o carro OU a porta que você escolher. Então eu tenho $ p (escolha dos jogadores) e $ c (onde está o carro). O OP disse que você deve ter a porcentagem de vitórias ao trocar, portanto, só conto o resultado como uma "vitória" quando $ p! = $ C (você alterna sua escolha para a outra porta e ganha).
Carlos Goce 28/11
0

Linguagem do Game Maker, 19 (51 w / loop)

show_message(200/3)

Emite 66,67! Esta é a probabilidade correta;)


O código de modo sério, 51 caracteres:

repeat(10000)p+=(random(1)<2/3);show_message(p/100)

Certifique-se de compilar com tratar todas as variáveis ​​não inicializadas como 0.


O código mais antigo, 59 caracteres:

for(i=0;i<10000;i+=1)p+=(random(1)<2/3);show_message(p/100)

Novamente, certifique-se de compilar com tratar todas as variáveis ​​não inicializadas como 0.

A saída foi 66.23

Timtech
fonte