Simulation des Monty-Hall-Problems mit Tkinter

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

Das Monty-Hall-Problem ist ein berühmtes Wahrscheinlichkeitsrätsel, das auf einem Spielshow-Szenario basiert. Im Spiel wird einem Teilnehmer drei Türen präsentiert. Hinter einer der Türen befindet sich ein Preis (z. B. ein Auto), während hinter den anderen beiden Türen Ziegen versteckt sind. Der Teilnehmer wählt eine der Türen aus. Der Moderator, der weiß, wo sich der Preis befindet, öffnet dann eine der anderen beiden Türen und zeigt eine Ziege. Dem Teilnehmer wird dann die Möglichkeit gegeben, entweder bei seiner ursprünglichen Wahl zu bleiben oder zur anderen noch nicht geöffneten Tür zu wechseln. Die Frage lautet: Was ist die beste Strategie, zu wechseln oder zu bleiben? In diesem Projekt werden Sie durch den Bau einer GUI-Anwendung geführt, um das Monty-Hall-Problem mit der Tkinter-Bibliothek in Python zu simulieren.

👀 Vorschau

Monty Hall

🎯 Aufgaben

In diesem Projekt werden Sie lernen:

  • Wie man mithilfe von Tkinter eine grafische Benutzeroberfläche (GUI) entwirft und entwickelt.
  • Wie man das Monty-Hall-Problem simuliert, um seine Wahrscheinlichkeitsergebnisse zu verstehen.
  • Wie man die Spiellogik in Python implementiert, um Benutzerauswahlen zu verarbeiten und Ergebnisse anzuzeigen.
  • Wie man die random-Bibliothek von Python verwendet, um den Preis zufällig hinter einer der Türen zu platzieren.
  • Wie man den Spielzustand zurücksetzt, um mehrere Spielrunden ohne Neustart der Anwendung zu ermöglichen.

🏆 Errungenschaften

Nach Abschluss dieses Projekts können Sie:

  • GUI-Designprinzipien anwenden und sie in Python mit Tkinter implementieren.
  • Die praktische Anwendung von Wahrscheinlichkeitstheorie und Statistik in Spielsimulationen verstehen.
  • Ereignisgesteuertes Programmieren implementieren und Benutzerinteraktionen in einer GUI-Anwendung verarbeiten.
  • Fortgeschrittene Python-Programmiertechniken wie Lambda-Funktionen und Listen-Abstraktionen nutzen.
  • Die Wichtigkeit der Benutzererfahrung (UX) im Spieldesign erkennen und Feedback-Mechanismen mithilfe von Nachrichtenfenstern bereitstellen.

Projekt-Dateien erstellen

Erstellen Sie zunächst eine Python-Datei mit dem Namen monty_hall_gui.py in ~/project. Öffnen Sie diese dann in einem Texteditor oder einer integrierten Entwicklungsumgebung (IDE).

cd ~/project
touch monty_hall_gui.py
✨ Lösung prüfen und üben

Notwendige Bibliotheken importieren

Zu Beginn werden wir die erforderlichen Module importieren.

import tkinter as tk
from tkinter import messagebox
import random
from typing import List, Optional

Im obigen Code importieren wir die erforderlichen Python-Bibliotheken. tkinter dient zur Erstellung von GUI, messagebox für Pop-up-Warnungen und random für die randomisierte Spiellogik.

✨ Lösung prüfen und üben

Initialisierung der MontyHallSimulation-Klasse

Nun werden wir die Hauptklasse zur Verwaltung unserer Simulation erstellen.

class MontyHallSimulation:
    def __init__(self, root: tk.Tk) -> None:
        """
        Initialize the Monty Hall Simulation.

        :param root: The main tkinter window
        """
        ## Window Configuration
        self.root = root
        self.root.title("Monty Hall Problem Simulation")
        self.root.geometry("1200x800")

In den obigen Anweisungen beginnen wir, unsere Hauptklasse für die Simulation zu definieren.

✨ Lösung prüfen und üben

Einrichten von Variablen und UI-Komponenten

Innerhalb der Klasse initialisieren Sie die erforderlichen Variablen und UI-Elemente.

        ## Variables to keep track of the user's selected door, the door that's shown, and the winning door
        self.selected_door: Optional[int] = None
        self.show_door: Optional[int] = None
        self.winning_door: int = random.randint(1, 3)

        ## Variables to keep track of win counts based on decision to change or stay
        self.wins_change: int = 0
        self.wins_stay: int = 0

        ## Instructions displayed at the top
        self.label = tk.Label(root, text="Select a door!", font=("Arial", 16))
        self.label.pack(pady=5)

        ## Creating frame for door buttons
        self.doors_frame = tk.Frame(root)
        self.doors_frame.pack(pady=5)

Die obigen Anweisungen führen Sie durch die Initialisierung verschiedener Spielvariablen und das Einrichten der primären UI-Elemente für unsere Simulation.

✨ Lösung prüfen und üben

Einrichten von Türbildern und -buttons

Laden Sie die Türbilder und konfigurieren Sie die Türbuttons, um die Benutzerinteraktion zu ermöglichen.

        ## Load door images
        self.door_imgs: List[tk.PhotoImage] = [
            tk.PhotoImage(file="door_closed.png"),
            tk.PhotoImage(file="door_opened_empty.png"),
            tk.PhotoImage(file="door_opened_prize.png")
        ]

        ## Create door buttons with images and attach select door function
        self.door_buttons: List[tk.Button] = [
            tk.Button(self.doors_frame, image=self.door_imgs[0], command=lambda: self.select_door(1)),
            tk.Button(self.doors_frame, image=self.door_imgs[0], command=lambda: self.select_door(2)),
            tk.Button(self.doors_frame, image=self.door_imgs[0], command=lambda: self.select_door(3))
        ]

        for button in self.door_buttons:
            button.pack(side=tk.LEFT, padx=5)

        ## Buttons for choosing whether to switch doors
        self.yes_button = tk.Button(self.root, text="Yes", command=self.switch_door)
        self.yes_button.pack_forget()

        self.no_button = tk.Button(self.root, text="No", command=self.stay_door)
        self.no_button.pack_forget()

        ## Displaying results
        self.results_label = tk.Label(root, text="", font=("Arial", 14))
        self.results_label.pack(pady=5)

Im obigen Code laden wir die Türbilder, die verschiedene Türzustände repräsentieren. Anschließend erstellen und konfigurieren wir drei Buttons, die die Türen darstellen und es dem Benutzer ermöglichen, seine Wahl zu treffen.

✨ Lösung prüfen und üben

Implementierung der Türauswahl-Logik

Zunächst werden wir uns mit der Logik zur Auswahl einer Tür befassen.

    def select_door(self, door: int) -> None:
        """
        Handle the event when a door is selected.

        :param door: The number of the door selected
        """
        ## Ensure no re-selection of doors
        if self.selected_door:
            return

        self.selected_door = door

        ## Determine which doors were not selected
        non_selected_doors = [d for d in [1, 2, 3] if d!= self.selected_door]

        ## Decide which door to reveal
        if self.selected_door == self.winning_door:
            show_door = random.choice(non_selected_doors)
        else:
            non_selected_doors.remove(self.winning_door)
            show_door = non_selected_doors[0]

        self.show_door = show_door
        self.door_buttons[show_door - 1].config(image=self.door_imgs[1])

        ## Prompt the user to decide whether to switch
        self.label.config(text="Would you like to switch?")

        ## Display the yes and no buttons
        self.yes_button.pack(side=tk.LEFT, padx=10, pady=20)
        self.no_button.pack(side=tk.RIGHT, padx=10, pady=20)

Im obigen Code definieren wir die Methode select_door, die verwendet wird, wenn ein Spieler eine Tür auswählt. Die Methode speichert die Auswahl des Spielers und zeigt eine der Türen, die kein Preis enthält, auf.

✨ Lösung prüfen und üben

Handhabung der Türwechsel-Logik

Als Nächstes befassen wir uns mit der Logik des Türwechsels.

    def switch_door(self) -> None:
        """Handle the event when the user decides to switch doors."""
        ## Find the door that was not selected and not revealed
        remaining_doors = [d for d in [1, 2, 3] if d!= self.selected_door and d!= self.show_door]
        new_door = remaining_doors[0]

        ## Check for a win
        if new_door == self.winning_door:
            self.wins_change += 1
            self.show_win(True)
        else:
            self.show_win(False)

Hier verwaltet die Funktion switch_door, was passiert, wenn ein Spieler beschließt, die Tür zu wechseln, nachdem der Moderator hinter einer der nicht ausgewählten Türen eine Ziege aufgedeckt hat.

✨ Lösung prüfen und üben

Behandlung der Logik für die Beibehaltung der Türauswahl

Jetzt befassen wir uns mit der Logik für die Beibehaltung der ursprünglichen Türauswahl.

    def stay_door(self) -> None:
        """Handle the event when the user decides to stay with the initial door selection."""
        ## Check for a win
        if self.selected_door == self.winning_door:
            self.wins_stay += 1
            self.show_win(True)
        else:
            self.show_win(False)

In diesem Codeausschnitt überwacht die Funktion stay_door das Ergebnis, wenn der Spieler beschließt, bei seiner ursprünglichen Türauswahl zu bleiben.

✨ Lösung prüfen und üben

Anzeige von Gewinn oder Verlust

Anschließend wird angezeigt, ob der Spieler gewonnen hat oder nicht.

    def show_win(self, did_win: bool) -> None:
        """
        Display the results after revealing all doors.

        :param did_win: Boolean indicating whether the user won or not
        """
        ## Update door images based on the results
        for i, button in enumerate(self.door_buttons):
            if i + 1 == self.winning_door:
                button.config(image=self.door_imgs[2])
            else:
                button.config(image=self.door_imgs[1])

        ## Show win/lose message
        if did_win:
            messagebox.showinfo("Congratulations!", "You won!")
        else:
            messagebox.showinfo("Sorry!", "Better luck next time!")

        ## Update the win statistics
        self.results_label.config(text=f"Wins (Switch): {self.wins_change}   Wins (Stay): {self.wins_stay}")

        ## Prepare for the next round
        self.reset_game()

Diese Methode show_win zeigt die Ergebnisse an. Wenn die endgültige Türauswahl des Spielers den Preis verbirgt, wird er als Gewinner erklärt; andernfalls wird ihm für das nächste Mal viel Glück gewünscht.

✨ Lösung prüfen und üben

Zurücksetzen der Spielmechanik

Schließlich müssen Sie sicherstellen, dass Sie das Spiel für eine neue Runde neu initialisieren können.

    def reset_game(self) -> None:
        """Reset the game for a new round."""
        self.selected_door = None
        self.winning_door = random.randint(1, 3)
        for button in self.door_buttons:
            button.config(image=self.door_imgs[0])
        self.label.config(text="Select a door!")
        self.yes_button.pack_forget()
        self.no_button.pack_forget()

Diese Funktion reset_game setzt den Spielzustand zurück und ermöglicht es den Spielern, eine weitere Runde zu spielen.

✨ Lösung prüfen und üben

Ausführen der Anwendung

Schließlich initialisieren und starten wir unsere Anwendung.

if __name__ == "__main__":
    root = tk.Tk()
    sim = MontyHallSimulation(root)
    root.mainloop()

Nachdem wir alle Schritte abgeschlossen haben, können wir den Code mit dem folgenden Befehl ausführen:

cd ~/project
python monty_hall_gui.py
Monty Hall
✨ Lösung prüfen und üben

Zusammenfassung

Herzlichen Glückwunsch! Sie haben gerade eine GUI-basierte Simulation des Monty-Hall-Problems mit Tkinter erstellt. Um die Simulation auszuführen, führen Sie das Skript monty_hall_gui.py aus und interagieren Sie mit der grafischen Benutzeroberfläche. Denken Sie daran, dass das Spiel die unintuitive Natur der Wahrscheinlichkeit zeigt und die beste Strategie besteht darin, immer die Tür zu wechseln!