Introduction
Le problème de Monty Hall est un célèbre puzzle de probabilité basé sur un scénario d'émission de jeu. Dans le jeu, un candidat est présenté avec trois portes. Derrière l'une des portes se trouve un prix (comme une voiture), tandis que les deux autres portes cachent des chèvres. Le candidat sélectionne l'une des portes. L'animateur, qui sait où se trouve le prix, ouvre ensuite l'une des deux autres portes pour révéler une chèvre. Le candidat a alors le choix de conserver son premier choix ou de changer pour l'autre porte non ouverte. La question est : Quelle est la meilleure stratégie, changer de porte ou la conserver? Ce projet vous guidera dans la construction d'une application GUI pour simuler le problème de Monty Hall en utilisant la bibliothèque Tkinter en Python.
👀 Aperçu

🎯 Tâches
Dans ce projet, vous apprendrez :
- Comment concevoir et développer une interface graphique utilisateur (GUI) en utilisant Tkinter.
- Comment simuler le problème de Monty Hall pour comprendre ses résultats probabilistes.
- Comment implémenter la logique du jeu en Python pour gérer les choix de l'utilisateur et révéler les résultats.
- Comment utiliser la bibliothèque
randomde Python pour attribuer aléatoirement le prix derrière l'une des portes. - Comment réinitialiser les états du jeu pour permettre plusieurs rounds de jeu sans redémarrer l'application.
🏆 Réalisations
Après avoir terminé ce projet, vous serez en mesure de :
- Appliquer les principes de conception GUI et les implémenter en Python avec Tkinter.
- Comprendre l'application pratique des probabilités et de la statistique dans les simulations de jeu.
- Implémenter la programmation événementielle et gérer les interactions utilisateur dans une application GUI.
- Utiliser des techniques de programmation Python avancées telles que les fonctions lambda et les compréhensions de liste.
- Reconnaître l'importance de l'expérience utilisateur (UX) dans la conception de jeu et fournir des mécanismes de feedback à l'aide de boîtes de message.
Créer les fichiers du projet
Tout d'abord, créez un fichier Python nommé monty_hall_gui.py dans le répertoire ~/project. Ensuite, ouvrez-le dans un éditeur de texte ou un environnement de développement intégré (IDE).
cd ~/project
touch monty_hall_gui.py
Importer les bibliothèques nécessaires
Pour commencer, nous allons importer les modules requis.
import tkinter as tk
from tkinter import messagebox
import random
from typing import List, Optional
Dans le code ci-dessus, nous importons les bibliothèques Python nécessaires. tkinter est utilisé pour la création de l'interface graphique utilisateur (GUI), messagebox pour les alertes pop-up et random pour la logique aléatoire du jeu.
Initialiser la classe MontyHallSimulation
Maintenant, nous allons créer la classe principale pour gérer notre simulation.
class MontyHallSimulation:
def __init__(self, root: tk.Tk) -> None:
"""
Initialise la simulation du problème de Monty Hall.
:param root: La fenêtre principale de tkinter
"""
## Configuration de la fenêtre
self.root = root
self.root.title("Monty Hall Problem Simulation")
self.root.geometry("1200x800")
Dans les instructions ci-dessus, nous commençons à définir notre classe principale pour la simulation.
Configurer les variables et les composants d'interface utilisateur (UI)
À l'intérieur de la classe, initialisez les variables nécessaires et les éléments de l'interface utilisateur (UI).
## Variables pour suivre la porte sélectionnée par l'utilisateur, la porte révélée et la porte gagnante
self.selected_door: Optional[int] = None
self.show_door: Optional[int] = None
self.winning_door: int = random.randint(1, 3)
## Variables pour suivre le nombre de victoires en fonction de la décision de changer ou de rester
self.wins_change: int = 0
self.wins_stay: int = 0
## Instructions affichées en haut
self.label = tk.Label(root, text="Select a door!", font=("Arial", 16))
self.label.pack(pady=5)
## Création d'un cadre pour les boutons des portes
self.doors_frame = tk.Frame(root)
self.doors_frame.pack(pady=5)
Les instructions ci-dessus vous guident dans l'initialisation de diverses variables de jeu et la configuration des éléments principaux de l'interface utilisateur pour notre simulation.
Configurer les images des portes et les boutons
Chargez les images des portes et configurez les boutons des portes pour permettre l'interaction de l'utilisateur.
## Charger les images des portes
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")
]
## Créer des boutons de porte avec des images et attacher la fonction de sélection de porte
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)
## Boutons pour choisir s'il faut changer de porte
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()
## Affichage des résultats
self.results_label = tk.Label(root, text="", font=("Arial", 14))
self.results_label.pack(pady=5)
Dans le code ci-dessus, nous chargeons les images des portes qui représentent différents états des portes. Ensuite, nous créons et configurons trois boutons représentant les portes, qui permettent à l'utilisateur de faire son choix.
Implémenter la logique de sélection des portes
Tout d'abord, nous allons aborder la logique de sélection d'une porte.
def select_door(self, door: int) -> None:
"""
Gère l'événement lorsqu'une porte est sélectionnée.
:param door: Le numéro de la porte sélectionnée
"""
## S'assurer qu'il n'y a pas de re-sélection de porte
if self.selected_door:
return
self.selected_door = door
## Déterminer quelles portes n'ont pas été sélectionnées
non_selected_doors = [d for d in [1, 2, 3] if d!= self.selected_door]
## Décider quelle porte révéler
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])
## Demander à l'utilisateur de décider s'il veut changer de porte
self.label.config(text="Would you like to switch?")
## Afficher les boutons Oui et Non
self.yes_button.pack(side=tk.LEFT, padx=10, pady=20)
self.no_button.pack(side=tk.RIGHT, padx=10, pady=20)
Dans le code ci-dessus, nous définissons la méthode select_door qui sera utilisée lorsque le joueur choisit une porte. Cette méthode mémorise le choix du joueur et révèle l'une des portes qui ne contient pas le prix.
Gérer la logique de changement de porte
Ensuite, nous allons nous plonger dans la logique du changement de choix de porte.
def switch_door(self) -> None:
"""Gère l'événement lorsque l'utilisateur décide de changer de porte."""
## Trouver la porte qui n'a pas été sélectionnée et n'a pas été révélée
remaining_doors = [d for d in [1, 2, 3] if d!= self.selected_door and d!= self.show_door]
new_door = remaining_doors[0]
## Vérifier s'il y a une victoire
if new_door == self.winning_door:
self.wins_change += 1
self.show_win(True)
else:
self.show_win(False)
Ici, la fonction switch_door gère ce qui se passe lorsque le joueur choisit de changer de porte après que le présentateur ait révélé une chèvre derrière l'une des portes non sélectionnées.
Gérer la logique de maintien de porte
Maintenant, examinons la logique pour maintenir le choix initial de porte.
def stay_door(self) -> None:
"""Gère l'événement lorsque l'utilisateur décide de conserver son choix initial de porte."""
## Vérifier s'il y a une victoire
if self.selected_door == self.winning_door:
self.wins_stay += 1
self.show_win(True)
else:
self.show_win(False)
Dans ce extrait de code, la fonction stay_door gère le résultat lorsque le joueur décide de conserver son choix initial de porte.
Illustrer la victoire ou la défaite
Ensuite, affichez si le joueur a remporté la partie ou non.
def show_win(self, did_win: bool) -> None:
"""
Affiche les résultats après avoir révélé toutes les portes.
:param did_win: Booléen indiquant si l'utilisateur a gagné ou non
"""
## Mettre à jour les images des portes en fonction des résultats
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])
## Afficher le message de victoire/défaite
if did_win:
messagebox.showinfo("Congratulations!", "You won!")
else:
messagebox.showinfo("Sorry!", "Better luck next time!")
## Mettre à jour les statistiques de victoire
self.results_label.config(text=f"Wins (Switch): {self.wins_change} Wins (Stay): {self.wins_stay}")
## Préparer la prochaine manche
self.reset_game()
Cette méthode show_win révèle les résultats. Si la porte finale choisie par le joueur cache le prix, il est déclaré gagnant ; sinon, on lui souhaite bonne chance pour la prochaine fois.
Réinitialiser la mécanique du jeu
Enfin, assurez-vous de pouvoir réinitialiser le jeu pour une nouvelle manche.
def reset_game(self) -> None:
"""Réinitialise le jeu pour une nouvelle manche."""
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()
Cette fonction, reset_game, redémarre l'état du jeu, permettant aux joueurs de tenter une nouvelle manche.
Exécuter l'application
Enfin, initialisons et exécutons notre application.
if __name__ == "__main__":
root = tk.Tk()
sim = MontyHallSimulation(root)
root.mainloop()
Maintenant que nous avons terminé toutes les étapes, nous pouvons exécuter le code en utilisant la commande suivante :
cd ~/project
python monty_hall_gui.py

Résumé
Félicitations! Vous venez de créer une simulation basée sur une interface graphique (GUI) du problème de Monty Hall en utilisant Tkinter. Pour exécuter la simulation, exécutez le script monty_hall_gui.py et interagissez avec l'interface graphique. N'oubliez pas que le jeu met en évidence la nature contre-intuitive de la probabilité, et que la meilleure stratégie est toujours de changer de porte!



