Ziegenproblem

Code-Stücke können hier veröffentlicht werden.
Antworten
Üpsilon
User
Beiträge: 222
Registriert: Samstag 15. September 2012, 19:23

Wir haben heute uns heute in Mathe mit bedingten Wahrscheinlichkeiten beschäftigt und dann auch übers Ziegenproblem gequatscht. Bekanntlich soll man ja wechseln, aber die Erklärung des Lehrers war nur so halb überzeugend. Aber jetzt haben wir Gewissheit:

Code: Alles auswählen

from random import choice

def ohne(liste, raus):
    return filter(lambda i: i not in raus, liste)

TUEREN = ["a", "b", "c"]

def ohne_wechseln():
    hauptgewinn = choice(TUEREN)
    kandidat = choice(TUEREN)
    ##showmaster = choice(ohne(TUEREN, [kandidat, hauptgewinn]))
    return kandidat == hauptgewinn
    
def mit_wechseln():
    hauptgewinn = choice(TUEREN)
    kandidat = choice(TUEREN)
    showmaster = choice(ohne(TUEREN, [kandidat, hauptgewinn]))
    kandidat = ohne(TUEREN, [kandidat, showmaster])[0]
    return kandidat == hauptgewinn

print "Ohne Wechseln:", sum([ohne_wechseln() for _ in range(10000)])
print "Mit Wechseln:", sum([mit_wechseln() for _ in range(10000)])
PS: Die angebotene Summe ist beachtlich.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich hatte dazu auch vor olims Zeiten mal einen Thread erstellt - leider ist paste.pocoo.org ja down und somit der Code weg :-( (Müsste mal gucken, ob ich den lokal noch habe)

Um das ganze evtl. klarer zu machen, stellt Dir mal vor, dass Du 100 Türen hast und Dir 98 falsche nach der ersten Wahl weggenommen werden. Dann ist es viel intuitiver, dass man beim ersten Mal eher falsch liegt als richtig ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Üpsilon
User
Beiträge: 222
Registriert: Samstag 15. September 2012, 19:23

Jaja, auch eine schöne Erklärung ist folgende:

»Angenommen, wir wüssten, dass der Hauptgewinn hinter Tür A oder B ist.
Dann würden wir auf C setzen, der Moderator würde B aufmachen und wir wüssten mit Sicherheit, dass A gewinnt (oder andersrum) und wir würden wechseln.
Da die angenommene Bedingung (Gewinn hinter A oder B) meistens (2/3) stimmt, sollte man immer so handeln.«

b2t: Es wurde ja noch gar nix zu meinem Programm gesagt. Soll ich das so verstehen, dass das Programm perfekt ist? :mrgreen:
Ohne ist n Scheißname, die Listenklammern in den letzten Zeilen sind unnötig und ich will eigentlich xrange benutzen.
PS: Die angebotene Summe ist beachtlich.
Fiaban
User
Beiträge: 3
Registriert: Mittwoch 13. Dezember 2023, 11:15

from random import randint, seed
seed()
#schritt 1 : auto wird versteckt
tuerAuto= randint(1,3)

# schritt 2: kandidat waehlt eine Tuer aus
tuerKandidat= int(input("waehle eine Tuer(1,2,3): "))
# schritt 3: moderator oeffnet eine Tuer
if tuerAuto==1:

if tuerKandidat==1:

muenze=randint(0,1)
if muenze==0:

tuerziege=2

else:

tuerziege=3

else:
wahrscheinlichkeit= False

if tuerKandidat==2:
tuerziege=3

else:
wahrscheinlichkeit= False

if tuerKandidat==3:

tuerziege=2

else:
wahrscheinlichkeit = False





else:
wahrscheinlichkeint= False

if tuerAuto==2:

if tuerKandidat == 1:
tuerziege= 3

else:
wahrscheinlichkeit= False

if tuerKandidat==2:
muenze=randint(0,1)
if muenze==0:
tuerziege=1

else:
tuerziege=3

if tuerKandidat==3:
tuerziege=1

else:
wahrscheinlichkeit= False





else:
wahrscheinlichkeint = False
if tuerAuto==3:

if tuerKandidat==1:
tuerziege=2

else:
wahrscheinlichkeit=False
if tuerKandidat==2:
tuerziege=1

else:
wahrscheinlichkeit=False
if tuerKandidat==3:
muenze=randint(0,1)
if muenze==0:
tuerziege=1

else:
tuerziege=2

else:
wahrscheinlichkeit=False



else:
wahrscheinlichkeit=False
print("hinter Tuer",tuerziege,"befindet sich eine ziege!")


if tuerAuto==1 or tuerAuto==2 or tuerAuto==3:
print("du hast ein Auto gewonnen!")
else:
print("du hast eine ziege gewonnen!")
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Variablennamen werden in Python komplett_klein geschrieben.
Leerzeilen dienen der Übersichtlichkeit. Du hast Leerzeilen in einem mir nicht erkennbaren Schema verteilt.
Der Aufruf von seed() bewirkt, dass die Zahlen weniger zufällig werden. `seed` ist nur mit Parameter sinnvoll, um immer die selben Zufallszahlen zu erhalten.

wahrscheinlichkeit wird gesetzt, aber nie benutzt. Ist auch besser so, denn die Variable wird ja nicht in jedem Fall gesetzt. In einem Fall ist `wahrscheinlichkeint` auch falsch geschrieben.

tuer_kandidat und tuer_auto haben die selbe Struktur vom Namen her, aber eine völlig andere bedeutung, das eine ist die Tür, hinter der der Kandidat steht, das andere die Tür, die beim Auto offensteht.
Solche Feinheiten sollten im Variablennamen sichtbar sein.

Wenn man sich auschließende if-Abfragen hat, benutzt man elif.
Damit kommt man ungefähr bei folgendem raus:

Code: Alles auswählen

from random import randint

tuer_mit_auto = randint(1,3)
tuer_ausgewaehlt_von_kandidat = int(input("waehle eine Tuer(1,2,3): "))

# schritt 3: moderator oeffnet eine Tuer
if tuer_mit_auto == 1:
    if tuer_ausgewaehlt_von_kandidat == 1:
        muenze=randint(0,1)
        if muenze == 0:
            tuer_mit_ziege = 2
        else:
            tuer_mit_ziege = 3
    elif tuer_ausgewaehlt_von_kandidat == 2:
        tuer_mit_ziege = 3
    elif tuer_ausgewaehlt_von_kandidat == 3:
        tuer_mit_ziege = 2
elif tuer_mit_auto == 2:
    if tuer_ausgewaehlt_von_kandidat == 1:
        tuer_mit_ziege = 3
    elif tuer_ausgewaehlt_von_kandidat == 2:
        muenze = randint(0,1)
        if muenze == 0:
            tuer_mit_ziege = 1
        else:
            tuer_mit_ziege = 3
    elif tuer_ausgewaehlt_von_kandidat == 3:
        tuer_mit_ziege = 1
elif tuer_mit_auto == 3:
    if tuer_ausgewaehlt_von_kandidat == 1:
        tuer_mit_ziege = 2
    elif tuer_ausgewaehlt_von_kandidat == 2:
        tuer_mit_ziege = 1
    elif tuer_ausgewaehlt_von_kandidat == 3:
        muenze = randint(0,1)
        if muenze == 0:
            tuer_mit_ziege = 1
        else:
            tuer_mit_ziege = 2

print(f"hinter Tuer {tuer_mit_ziege} befindet sich eine ziege!")

if  tuer_mit_auto == 1 or tuer_mit_auto == 2 or tuer_mit_auto == 3:
    print("du hast ein Auto gewonnen!")
else:
    print("du hast eine ziege gewonnen!")
Nun hast Du dreimal den selben Code, nur mit anderen Zahlen; solche Dopplungen versucht man beim Programmieren zu vermeiden, in dem man keine fixen Werte benutzt, sondern Variablen.
Das Problem "finde die Tuer mit der Ziege, die nicht die Tuer des Kandidaten ist" läßt sich genau so Programmieren: Nehme alle Türen, die weder Auto noch Kandidat sind und wähle davon eine zufällig aus.

Code: Alles auswählen

from random import randint, choice

tuer_mit_auto = randint(1, 3)
tuer_ausgewaehlt_von_kandidat = int(input("waehle eine Tuer(1,2,3): "))

# schritt 3: moderator oeffnet eine Tuer
tuer_mit_ziege = choice([tuer for tuer in range(1, 3) if tuer  not in [tuer_mit_auto, tuer_ausgewaehlt_von_kandidat]])
print(f"hinter Tuer {tuer_mit_ziege} befindet sich eine ziege!")
Die Abfrage, ob Du ein Auto gewonnen hast, ist noch falsch, da solltest Du nochmal draufschauen.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Fiaban: Den letzten von Sirius3 angesprochenen Fehler sieht man vielleicht leichter wenn man das nicht mit mehreren durch ``or`` verknüpften Vergleichen ausdrückt, sondern kürzer mit ``in``:

Code: Alles auswählen

if tuer_mit_auto in [1, 2, 3]:
    print("Du hast ein 🚗 gewonnen!")
else:
    print("Du hast eine 🐐 gewonnen!")
Aus Sicht des Kandidaten könnte ich mit dem Fehler ja leben. 😀
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Fiaban
User
Beiträge: 3
Registriert: Mittwoch 13. Dezember 2023, 11:15

from random import randint, seed
seed()

anzahlspiele=int(input("bitte zähle an das spielen:" ))
zaehlerspiele=0
zaehlerAuto=0
while zaehlerspiele < anzahlspiele:
tuer_mit_Auto=randint(1,3)
tuer_mit_kandidat=randint(1,3)
if tuer_mit_Auto==tuer_mit_kandidat:
print("du hast en Auto gewonnen")
zaehlerAuto=zaehlerAuto+1
print("anzahlAutos sind:")

else:
print("du hast verloren")
zaehlerspiele= zaehlerspiele +1

print(anzahlspiele,zaehlerAuto)
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Fiaban: Da ist ja schon wieder der unnötige bis falsche `seed()`-Aufruf. Und an die Namenskonvention klein_mit_unterstrichen hält es sich auch nicht.

Auch die Reihenfolge von Worten in einem Namen ist wichtig. `zaehlerspiele` sind etwas anderes als ein `spielezaehler`.

Leerzeichen um Zuweisungen und binäre Operatoren erhöhen die Lesbarkeit.

Die ``while``-Schleife sollte eigentlich eine ``for``-Schleife sein.

Der Name `tuer_mit_kandidat` ist inhaltlich wohl eher falsch. Und der Wert ist überflüssig. Wenn man beides gleichwahrscheinlich auswürfeln lässt, kann man für eines davon auch einfach einen festen Wert nehmen, ohne dass das etwas am Programmverhalten ändert.

Beim letzten `print()` im ``if``-Zweig fehlt offensichtlich noch etwas.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
from random import randint


def main():
    spielanzahl = int(input("Bitte Anzahl der Spiele eingeben: "))
    autoanzahl = 0
    for _ in range(spielanzahl):
        if randint(1, 3) == 1:
            print("Du hast ein Auto gewonnen.")
            autoanzahl += 1
            print("Autoanzahl:", autoanzahl)
        else:
            print("Du hast verloren.")

    print(spielanzahl, autoanzahl)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Fiaban
User
Beiträge: 3
Registriert: Mittwoch 13. Dezember 2023, 11:15

if tuer_mit_Auto==1 and 2 and 3: Das pässt .
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Fiaban: mich irritiert etwas, dass Du in drei Beiträgen bis auf Code insgesamt 2 Wörter geschrieben hast: "Das" und "pässt", wobei ich das Wort "pässt" nicht kenne. Aus dem Kontext würde ich interpretieren, dass das Wort bedeutet: "ich fange gerade erst an Python zu lernen und weiß deshalb nicht, wie ich eine if-Abfrage schreiben soll, denn der vorstehen Code passt irgendwie nicht wirklich und ich komme einfach nicht weiter".

Deshalb die Rückfrage:
in welchen Zusammenhang steht der Code? Und was willst Du eigentlich ausdrücken?

Code: Alles auswählen

if tuer_mit_Auto==1 and 2 and 3:
`and` verknüpft zwei Bedingungen und liefert "wahr" wenn beide "wahr" sind, sonst "falsch". Da 2 und 3 immer "wahr" sind (da eine Zahl != 0) ist das äquivalent zu:

Code: Alles auswählen

if tuer_mit_Auto==1 and True and True:
und diese "and True" kann man einfach weglassen, denn "a and True" liefert dann "wahr" wenn a "wahr" ist.
Bleibt also:

Code: Alles auswählen

if tuer_mit_Auto==1:
Antworten