Simulasikan Masalah Monty Hall [ditutup]

8

Saya tidak pernah bisa membungkus kepala saya di sekitar masalah Monty Hall . Inilah premisnya:

Misalkan Anda berada di sebuah acara permainan, dan Anda diberi pilihan tiga pintu: Di belakang satu pintu adalah mobil; di belakang yang lain, kambing. Anda memilih pintu, katakan No. 1, dan tuan rumah, yang tahu apa yang ada di balik pintu, membuka pintu lain, katakan No. 3, yang memiliki seekor kambing. Dia kemudian berkata kepada Anda, "Apakah Anda ingin memilih pintu No. 2?" Apakah menguntungkan Anda untuk mengalihkan pilihan Anda?

Jalankan 10.000 simulasi. Keluarkan persentase kemenangan dari pengalihan. Sebagai contoh:

> 66.66733%
bendytree
sumber
5
Tuan rumah tahu di mana mobil itu berada, jadi dia tidak pernah membuka pintu dengan mobil di belakangnya
bendytree
6
Sebagai tantangan berdiri, sulit untuk berpendapat bahwa itu tidak sah untuk hanya memiliki 10.000 berjalan dari generator nomor acak dan menambahkan mana yang mendarat di bawah 0,6666. Anda mungkin mengatakan bahwa itu tidak benar-benar mensimulasikan masalah Monty Hall. Tetapi jika itu menghasilkan output yang sama persis, lalu apa yang benar-benar hilang?
kotak roti
Perspektif sejarah yang menarik (tentang masalah, bukan golf): Pintu Yang Memiliki Cadillac? .
Cary Swoveland
3
Tantangannya masih agak ambigu sehubungan dengan asumsi apa yang kami boleh buat. Sebagai contoh, beberapa jawaban mungkin menyimpan sejumlah besar kode dengan mengasumsikan mobil akan berada di belakang pintu yang sama setiap kali atau pemain mengambil pintu yang sama setiap waktu.
Iszi
1
Menghitung semua kemungkinan setidaknya sama mencerahkannya dengan membuatnya secara acak ...
Daniel Cristofani

Jawaban:

4

JavaScript 52

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

Pintu adalah 1: [0,1 / 3), 2: [1 / 3,2 / 3), 3: [2/3, 1)

Anggap hadiah selalu ada di pintu 3. Jika tamu memilih pintu 1 atau 2, yaitu kisaran [0,2 / 3), dan mereka berganti, mereka telah memenangkan hadiah.

tristin
sumber
1
Sepertinya CoffeeScript memungkinkan kita untuk mencukur satu karakter:i=s=0;s+=Math.random()<2/3while i++<1e4;alert s/100
Kerrick
3

J: 17 15

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

Itu mengambil pintu acak — mari beri label 0, 1, atau 2 ini di mana 2 adalah pintu dengan mobil — dan menghitung manfaat beralih berdasarkan logika ini:

  • Jika pemain memilih pintu 0, tuan rumah akan membuka pintu 1. Beralih akan memberi pemain mobil baru ( 1).
  • Jika pemain memilih pintu 1, tuan rumah akan membuka pintu 0. Switching akan memberi pemain mobil baru (1 ).
  • Jika pemain memilih pintu 2, pintu kemenangan, tuan rumah akan membuka pintu 0 atau pintu 1. Apa pun caranya, jika pemain beralih, ia akan menemukan seekor kambing ( 0).

Kemudian menghitung hasilnya sebagai jumlah dari array sebelumnya, dibagi dengan 100.

Saya cukup gemetar dengan J jadi saya yakin ini bisa diperbaiki lebih lanjut.

pswg
sumber
3

R 115 100

Jawaban pseudo-simulasi adalah 23 karakter:

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

tapi di sini adalah simulasi yang sebenarnya:

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 apakah pintu yang mungkin
  2. S adalah fungsi untuk secara acak memilih satu item dari vektor
  3. Cadalah pintu dengan mobil (acak di antara D)
  4. Padalah pintu yang dipilih oleh pemain (acak di antara D)
  5. Hadalah pintu diangkat oleh tuan rumah (acak di antara Dminus Cdan P)
  6. Fadalah pintu terakhir yang dipilih oleh pemain (deterministik: Dminus Pdan H)
  7. kesuksesan diukur dengan C==F.

pengembalian: [1] 66.731

Edit

Saya dapat menyimpan beberapa karakter dengan tidak menugaskan ke variabel dan mengasumsikan tanpa kehilangan generalitas bahwa 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
flodel
sumber
2

Perl, 98 89 83 75 72 71 karakter

Inilah jawaban serius yang benar-benar menjalankan simulasi:

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

Di setiap iterasi loop, pilihan awal pemain selalu pintu # 2. Pertama pintu dengan mobil disimpan $%, kemudian pintu yang berbeda dipilih untuk diekspos Monty Hall. Jika pintu yang tersisa sama dengan $%, putaran dimenangkan.

(Variabel tanda baca Perl $%dan $=digunakan karena mereka memotong bilangan bulat secara gratis.)

kotak roti
sumber
2

Powershell - 168 131 125 115

Kode golf:

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)%"

Perubahan dari Asli:
Memotong 53 karakter dari skrip asli dengan beberapa modifikasi.

  • Ruang dan kurung yang dihapus di mana PowerShell memaafkannya.
  • Menggunakan ForEach-Objectperulangan, melalui %alias, alih-alih while.
  • Kisaran angka yang digunakan (misalnya:) 0..2alih-alih array yang didefinisikan secara eksplisit.
  • Dihapus writedari perintah terakhir - ternyata saya tidak membutuhkannya sama sekali.
  • Membalik ekspresi untuk pilihan host sekitar untuk menggunakan sintaks pipelining yang lebih pendek.
  • Digantikan 10000 dengan 1e4.
  • Mengambil saran Joey dan dihilangkan Get-dari Get-Random. (Catatan: Modifikasi ini secara signifikan menggembungkan run time. Pada sistem saya, itu melonjak dari sekitar 20 detik menjadi hampir setengah jam per run!)
  • Menggunakan trik Rynant untuk melakukan $T+=...alih - alih if(...){$T++}.

Beberapa catatan:

Script ini dimaksudkan untuk menjadi sesingkat mungkin, sambil juga simulasi skenario Monty Hall sebaik mungkin. Tidak ada asumsi di mana mobil akan berada, atau pintu mana yang akan dipilih pemain terlebih dahulu. Asumsi bahkan tidak dibuat untuk pintu tertentu tuan rumah akan memilih dalam skenario apa pun. Satu-satunya asumsi yang tersisa adalah yang sebenarnya dinyatakan dalam masalah Monty Hall:

  • Tuan rumah akan memilih pintu yang pemain tidak memilihnya terlebih dahulu, yang tidak mengandung mobil.
    • Jika pemain memilih pintu dengan mobil terlebih dahulu, itu berarti ada dua pilihan yang mungkin untuk tuan rumah.
  • Pilihan akhir pemain tidak akan menjadi pilihan awal maupun pilihan tuan rumah.

Tidak disatukan, dengan komentar:

# 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

Saya telah menjalankan skrip ini beberapa kali dan secara konsisten menampilkan hasil yang sangat dekat dengan probabilitas dua pertiga. Beberapa sampel:

(Seperti di atas)

  • 67,02%

(Menggunakan Get-Randomsebagai definisi alias, bukan hanya Random)

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

Ruby 48 40 38

Kode saya tidak membuat asumsi tentang pintu mana hadiah akan selalu ada di belakang atau pintu mana pemain akan selalu terbuka. Sebaliknya, saya fokus pada apa yang menyebabkan pemain kalah. Sesuai artikel Wikipedia :

[...] 2/3 dari waktu, pilihan awal pemain adalah pintu menyembunyikan kambing. Ketika itu terjadi, tuan rumah dipaksa untuk membuka pintu kambing lainnya [...] "Beralih" hanya gagal memberikan mobil ketika pemain mengambil pintu "kanan" (pintu menyembunyikan mobil) untuk memulai.

Jadi untuk mensimulasikan ini (alih-alih menggunakan nilai tetap), saya memodelkannya sebagai:

  • pertunjukan secara acak memilih 1 dari 3 pintu untuk menyembunyikan hadiah di belakang
  • pemain kemudian secara acak memilih 1 dari 3 pintu sebagai pilihan pertamanya
  • pemain selalu berganti, jadi jika pilihan pertamanya sama dengan pilihan pertunjukan, dia kalah

Kode v1:

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

Kode v3 (terima kasih kepada steenslag dan Iszi!):

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

Beberapa nilai pengembalian sampel:

  • 66.44
  • 66,98
  • 66.33
  • 67.2
  • 65.7
Jonathan Hefner
sumber
1
p (1..10000).count{rand(3)!=rand(3)}/1e2menghemat beberapa karakter.
steenslag
@steenslag Ah, memang benar! Terima kasih! =)
Jonathan Hefner
1
Apakah Ruby tidak mengizinkan kekuatan shortcut 10? Misalnya: 1e4untuk 10000?
Iszi
@Iszi Ya, tapi notasi ilmiah menghasilkan pelampung, jadi tidak selalu bisa diganti. Namun, ini adalah substitusi yang layak di v2, menghemat 2 karakter lagi!
Jonathan Hefner
1

Mathematica 42

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

66.79

DavidC
sumber
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

Berkomentar:

# 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
sumber
Ini tidak menghasilkan persentase kemenangan dalam format yang ditentukan dalam pertanyaan. Juga, simpan beberapa karakter dengan menggunakan 1e4alih-alih 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);}

Itu untuk simulasi yang sebenarnya. Untuk beberapa kode pembengkokkan aturan yang curang, hanya 71 65 59:

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

Saya tidak melakukan srand () karena aturan tidak mengatakan saya harus melakukannya. Juga, versi cheaty mencetak sekitar 30.000 angka tambahan karena menyimpan karakter. Saya mungkin kehilangan beberapa trik, tetapi saya melakukan yang terbaik yang saya bisa.

Stuntddude
sumber
Variabel global dijamin nol pada saat startup. Pindahkan deklarasi variabel mainAnda dan Anda dapat membatalkan =0inisialisasi.
kotak roti
1

Python 2: 72 66 64

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

Contoh output: 66.49

Rees
sumber
1
Anda dapat menyimpan beberapa karakter dengan menggunakan exec"i-=randint(0,2)&1;"*ialih-alih forloop.
Pasang kembali Monica
@ Wolfram Terima kasih, saya akan memperbaruinya sekarang.
Rees
Juga, gunakan print.01*ibukan print i/100..
Pasang kembali Monica
Solusi yang bagus tetapi Anda kehilangan titik koma.
Daniel Lubarov
Sangat benar. Memperbarui sekarang ...
Rees
0

Ikan - 46 43

Ini menggunakan asumsi yang sama yang dibuat Tristin:

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

Arah ke bawah menyala x awalnya Anda memilih pintu yang benar, kiri dan kanan adalah kasus-kasus bahwa Anda memilih pintu yang berbeda, dan naik bukan apa-apa, dan akan berguling lagi.

Awalnya, saya inisialisasi 10000dengan "dd"*, tetapi "dd"semua harus berada di jalur yang sama, dan saya membuang beberapa spasi. Dengan mengular aa*a*a*saya dapat menghapus kolom, dan akhirnya 3 karakter. Ada sedikit ruang kosong yang tersisa yang belum bisa saya singkirkan, saya pikir ini cukup bagus!

Cruncher
sumber
0

PHP 140

Tapi saya pikir ini tidak berfungsi dengan baik. Ada tip? Saya mendapatkan nilai dari 49 hingga 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
sumber
"Jika pemain mengubah pilihan"?
Timtech
Maaf bahasa Inggris saya tidak bagus. Maksud saya, pertama saya melakukan sambil mencoba untuk mendapatkan nilai yang dapat diterima. Karena "tuan rumah" tidak dapat melepas pintu yang berisi mobil ATAU pintu yang Anda pilih. Maka saya punya $ p (pilihan pemain) dan $ c (di mana mobil itu). OP mengatakan bahwa Anda harus mengambil persentase kemenangan ketika Anda beralih, jadi saya hanya menghitung hasilnya sebagai "kemenangan" ketika $ p! = $ C (Anda mengubah pilihan Anda ke pintu lain dan Anda menang).
Carlos Goce
0

Bahasa Game Maker, 19 (51 w / loop)

show_message(200/3)

Ini menghasilkan 66,67! Ini adalah probabilitas yang benar;)


Kode mode serius, 51 karakter:

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

Pastikan untuk mengkompilasi dengan memperlakukan semua variabel yang tidak diinisialisasi sebagai 0.


Kode tertua, 59 karakter:

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

Sekali lagi, pastikan untuk mengkompilasi dengan memperlakukan semua variabel yang tidak diinisialisasi sebagai 0.

Outputnya adalah 66.23

Timtech
sumber