Simulieren Sie das Monty Hall-Problem [geschlossen]

8

Ich war noch nie in der Lage, mich mit dem Monty Hall-Problem zu befassen . Hier ist die Prämisse:

Angenommen, Sie sind in einer Spielshow und haben die Wahl zwischen drei Türen: Hinter einer Tür steht ein Auto; hinter den anderen Ziegen. Sie wählen eine Tür, sagen Sie Nr. 1, und der Gastgeber, der weiß, was sich hinter den Türen befindet, öffnet eine weitere Tür, sagen Sie Nr. 3, die eine Ziege hat. Dann sagt er zu Ihnen: "Wollen Sie Tür Nr. 2 öffnen?" Ist es zu Ihrem Vorteil, Ihre Wahl zu ändern?

Führen Sie 10.000 Simulationen aus. Geben Sie den Gewinnprozentsatz der Umschaltung aus. Zum Beispiel:

> 66.66733%
Bendytree
quelle
5
Der Gastgeber weiß, wo das Auto ist, also öffnet er nie eine Tür mit dem Auto dahinter
Bendytree
6
Angesichts der Herausforderung ist es schwer zu argumentieren, dass es nicht völlig legal ist, nur 10.000 Durchläufe des Zufallszahlengenerators zu haben, und addiert, welche unter 0,6666 landen. Man könnte sagen, dass es das Monty Hall-Problem nicht wirklich simuliert. Aber wenn es genau die gleiche Ausgabe erzeugt, was fehlt dann wirklich?
Brotkasten
Eine interessante historische Perspektive (zum Problem, nicht zum Golfen): Welche Tür hat der Cadillac? .
Cary Swoveland
3
Die Herausforderung ist immer noch ein wenig zweideutig, welche Annahmen wir treffen dürfen. Zum Beispiel sparen einige der Antworten wahrscheinlich eine erhebliche Menge an Code, indem angenommen wird, dass sich das Auto jedes Mal hinter derselben Tür befindet oder der Spieler jedes Mal dieselbe Tür auswählt.
Iszi
1
Das Aufzählen aller Möglichkeiten ist mindestens so aufschlussreich wie das zufällige Generieren ...
Daniel Cristofani

Antworten:

4

JavaScript 52

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

Türen sind 1: [0,1 / 3), 2: [1 / 3,2 / 3), 3: [2/3, 1)

Angenommen, der Preis befindet sich immer in Tür 3. Wenn der Gast die Türen 1 oder 2 auswählt, was dem Bereich [0,2 / 3] entspricht, und wechselt, hat er den Preis gewonnen.

Tristin
quelle
1
Es sieht so aus, als könnten wir mit CoffeeScript einen einzelnen Charakter rasieren:i=s=0;s+=Math.random()<2/3while i++<1e4;alert s/100
Kerrick
3

J: 17 15

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

Es wählt eine zufällige Tür aus - beschriften wir diese 0, 1 oder 2, wobei 2 die Tür mit dem Auto ist - und berechnet den Vorteil des Schaltens basierend auf dieser Logik:

  • Wenn der Spieler Tür 0 gewählt hat, öffnet der Host Tür 1. Durch das Umschalten erhält der Spieler ein neues Auto ( 1).
  • Wenn der Spieler Tür 1 ausgewählt hat, öffnet der Host Tür 0. Durch das Umschalten erhält der Spieler ein neues Auto ( 1).
  • Wenn der Spieler Tür 2, die Gewinnertür, ausgewählt hat, öffnet der Gastgeber entweder Tür 0 oder Tür 1. In beiden Fällen findet der Spieler eine Ziege ( 0) , wenn er wechselt .

Anschließend wird das Ergebnis als Summe des vorherigen Arrays geteilt durch 100 berechnet.

Ich bin ziemlich wackelig mit J, also bin ich sicher, dass dies weiter verbessert werden könnte.

pswg
quelle
3

R 115 100

Die Pseudosimulationsantwort ist 23 Zeichen lang:

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

aber hier ist eine tatsächliche Simulation:

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 sind die möglichen Türen
  2. S ist eine Funktion zum zufälligen Auswählen eines Elements aus einem Vektor
  3. Cist die Tür mit dem Auto (zufällig unter D)
  4. Pist die vom Spieler gewählte Tür (zufällig unter D)
  5. Hist die vom Gastgeber ausgewählte Tür (zufällig zwischen DMinus Cund P)
  6. Fist die letzte vom Spieler gewählte Tür (deterministisch: DMinus Pund H)
  7. Erfolg wird gemessen an C==F.

Rückgabe: [1] 66.731

Bearbeiten

Ich kann ein paar Zeichen speichern, indem ich keine Variablen zuordne und ohne Verlust der Allgemeinheit davon ausgehe, dass 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
quelle
2

Perl, 98 89 83 75 72 71 Zeichen

Hier ist eine ernsthafte Antwort, die die Simulation tatsächlich ausführt:

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

In jeder Schleifeniteration ist die erste Wahl des Spielers immer Tür 2. Zuerst wird die Tür mit dem Auto aufbewahrt $%, dann wird eine andere Tür ausgewählt, die Monty Hall freilegen soll. Wenn die verbleibende Tür gleich ist, $%ist die Runde gewonnen.

(Perl-Interpunktionsvariablen $%und $=werden verwendet, weil sie die Ganzzahlkürzung kostenlos durchführen.)

Brot-Box
quelle
2

Powershell - 168 131 125 115

Golfcode:

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

Änderungen gegenüber dem Original:
Mit einigen Änderungen wurden 53 Zeichen aus dem Originalskript entfernt.

  • Leerzeichen und Klammern wurden entfernt, in denen PowerShell dies verzeiht.
  • Verwendete eine ForEach-ObjectSchleife über den %Alias ​​anstelle von while.
  • Verwendete Nummernkreise (zB 0..2:) anstelle explizit definierter Arrays.
  • Aus writedem letzten Befehl entfernt - es stellt sich heraus, dass ich ihn doch nicht brauche.
  • Der Ausdruck für die Auswahl des Hosts wurde umgedreht, um die kürzere Pipelining-Syntax zu verwenden.
  • 10000 durch 1e4 ersetzt.
  • Nahm Joey Vorschlag und verzichtet Get-aus Get-Random. (Hinweis: Diese Änderung erhöht die Laufzeit erheblich . Auf meinem System stieg sie von etwa 20 Sekunden auf fast eine halbe Stunde pro Lauf!)
  • Gebrauchte Rynant Trick zu tun , $T+=...statt if(...){$T++}.

Einige Notizen:

Dieses Skript soll so präzise wie möglich sein und gleichzeitig das Monty Hall-Szenario so gründlich wie möglich simulieren. Es werden keine Annahmen darüber getroffen, wo sich das Auto befindet oder welche Tür der Spieler zuerst wählt. Es werden nicht einmal Annahmen getroffen, für welche bestimmte Tür der Host in einem bestimmten Szenario wählen wird. Die einzigen verbleibenden Annahmen sind diejenigen, die tatsächlich im Monty Hall-Problem angegeben sind:

  • Der Gastgeber wählt eine Tür aus, die der Spieler nicht zuerst ausgewählt hat und die das Auto nicht enthält.
    • Wenn der Spieler zuerst mit dem Auto die Tür geöffnet hat, bedeutet dies, dass der Gastgeber zwei Möglichkeiten hat.
  • Die endgültige Wahl des Spielers ist weder seine ursprüngliche Wahl noch die Wahl des Gastgebers.

Ungolfed, mit Kommentaren:

# 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

Ich habe dieses Skript mehrmals ausgeführt und es gibt konsistent Ergebnisse aus, die sehr nahe an der Wahrscheinlichkeit von zwei Dritteln liegen. Einige Beispiele:

(Wie oben)

  • 67,02%

(Verwenden Get-Randomals Alias-Definition, anstatt nur Random)

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

Ruby 48 40 38

Mein Code macht keine Annahmen darüber, hinter welcher Tür sich der Preis immer befindet oder welche Tür der Spieler immer öffnet. Stattdessen habe ich mich darauf konzentriert, was den Spieler zum Verlieren bringt. Gemäß dem Wikipedia-Artikel :

[...] 2/3 der Zeit ist die erste Wahl des Spielers eine Tür, die eine Ziege versteckt. Wenn dies der Fall ist, muss der Wirt die andere Ziegentür öffnen [...] "Umschalten" gibt dem Auto nur dann keinen, wenn der Spieler die "rechte" Tür (die Tür, die das Auto versteckt) auswählt.

Um dies zu simulieren (anstatt feste Werte zu verwenden), habe ich es folgendermaßen modelliert:

  • Die Show wählt zufällig 1 der 3 Türen aus, um den Preis dahinter zu verbergen
  • Der Spieler wählt dann zufällig 1 der 3 Türen als seine erste Wahl
  • Der Spieler wechselt immer. Wenn also seine erste Wahl mit der Wahl der Show übereinstimmt, verliert er

Der Code v1:

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

Der Code v3 (danke an steenslag und Iszi!):

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

Einige Beispielrückgabewerte:

  • 66,44
  • 66,98
  • 66,33
  • 67.2
  • 65.7
Jonathan Hefner
quelle
1
p (1..10000).count{rand(3)!=rand(3)}/1e2spart einige Zeichen.
Steenslag
@steenslag Ah, in der Tat! Vielen Dank! =)
Jonathan Hefner
1
Erlaubt Ruby keine Shortcutting-Potenzen von 10? ZB: 1e4für 10000?
Iszi
@Iszi Es tut es, aber die wissenschaftliche Notation ergibt einen Float, so dass es nicht immer ersetzt werden kann. Es ist jedoch eine brauchbare Ersetzung in Version 2, wodurch 2 weitere Zeichen eingespart werden!
Jonathan Hefner
1

Mathematica 42

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

66,79

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

Kommentiert:

# 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
quelle
Dies gibt keinen Gewinnprozentsatz in dem in der Frage angegebenen Format aus. Speichern Sie außerdem ein paar Zeichen, indem Sie 1e4anstelle von verwenden 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);}

Das ist für die eigentliche Simulation. Für einige betrügerische Regeln zum Biegen von Regeln ist es nur 71 65 59:

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

Ich habe srand () nicht gemacht, weil die Regeln nicht sagten, dass ich musste. Außerdem druckt die betrügerische Version etwa 30.000 zusätzliche Zahlen aus, weil sie ein Zeichen speichert. Ich vermisse wahrscheinlich einige Tricks, aber ich habe mein Bestes gegeben.

Stuntddude
quelle
Globale Variablen sind beim Start garantiert Null. Verschieben Sie Ihre Variablendeklarationen aus mainund Sie können die =0Initialisierungen löschen.
Brotkasten
1

Python 2: 72 66 64

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

Beispielausgabe: 66,49

Rees
quelle
1
Sie können einige Zeichen speichern, indem Sie exec"i-=randint(0,2)&1;"*ianstelle der forSchleife verwenden.
Stellen Sie Monica
@ WolframH Danke, ich werde es jetzt aktualisieren.
Rees
Verwenden Sie auch print.01*ianstelle von print i/100..
Stellen Sie Monica
Gute Lösung, aber Ihnen fehlt ein Semikolon.
Daniel Lubarov
Sehr richtig. Jetzt aktualisieren ...
Rees
0

Fisch - 46 43

Dies basiert auf denselben Annahmen, die Tristin gemacht hat:

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

Die Abwärtsrichtung auf zeigt an x, dass Sie anfänglich die richtige Tür ausgewählt haben. Links und rechts sind die Fälle, in denen Sie eine andere Tür ausgewählt haben. Aufwärts ist nichts und rollt erneut.

Ursprünglich initialisiert ich 10000mit "dd"*, aber "dd"auf der gleichen Linie an alle sein musste, und ich einige Leerzeichen verschwendet. Durch Schlangen konnte aa*a*a*ich eine Spalte und letztendlich 3 Zeichen entfernen. Es gibt noch ein bisschen Leerzeichen, das ich nicht mehr loswerden konnte. Ich finde das aber ziemlich gut!

Cruncher
quelle
0

PHP 140

Aber ich denke, dass das nicht richtig funktioniert. Irgendein Tipp? Ich bekomme Werte von 49 bis 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
quelle
"Wenn der Spieler die Auswahl ändert"?
Timtech
Entschuldigung, mein Englisch ist nicht gut. Ich meine, zuerst mache ich einen Versuch, akzeptable Werte zu erhalten. Weil der "Gastgeber" eine Tür mit dem Auto ODER der von Ihnen gewählten Tür nicht entfernen kann. Dann habe ich $ p (Spielerwahl) und $ c (wo das Auto ist). Das OP sagte, dass Sie den Prozentsatz des Gewinns nehmen müssen, wenn Sie wechseln, also zähle ich das Ergebnis nur als "Sieg", wenn $ p! = $ C (Sie wechseln Ihre Wahl zur anderen Tür und Sie gewinnen).
Carlos Goce
0

Game Maker Language, 19 (51 mit Schleife)

show_message(200/3)

Es gibt 66,67 aus! Dies ist die richtige Wahrscheinlichkeit;)


Der Serious-Mode-Code, 51 Zeichen:

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

Stellen Sie sicher, dass alle nicht initialisierten Variablen als 0 behandelt werden.


Der älteste Code, 59 Zeichen:

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

Stellen Sie erneut sicher, dass alle nicht initialisierten Variablen als 0 behandelt werden.

Die Ausgabe war 66.23

Timtech
quelle