diff --git a/TP1/Exercice2.py b/TP1/Exercice2.py new file mode 100644 index 0000000000000000000000000000000000000000..95b5b9f43ccd34fe279d2b416539a2e995a86b4c --- /dev/null +++ b/TP1/Exercice2.py @@ -0,0 +1,200 @@ +import random + +class Prisonnier: + """ + Classe représentant un prisonnier avec une stratégie basée sur une probabilité d'avouer. + """ + def __init__(self, proba_avouer=0.5): + """ + Constructeur de la classe Prisonnier. + + Args: + proba_avouer: probabilité d'avouer (par défaut 0.5 pour un joueur aléatoire uniforme) + """ + self.proba_avouer = proba_avouer + self.historique_adversaire = [] + + def jouer(self): + """ + Méthode qui détermine l'action du joueur en fonction de sa probabilité d'avouer. + + Returns: + 'avoue' ou 'nie' selon la probabilité + """ + if random.random() < self.proba_avouer: + return "avoue" + else: + return "nie" + + def maj(self, coup): + """ + Méthode qui met à jour l'historique des coups joués par l'adversaire. + + Args: + coup: le coup joué par l'adversaire ('avoue' ou 'nie') + """ + self.historique_adversaire.append(coup) + + +class TitForTat(Prisonnier): + """ + Stratégie Tit for Tat (oeil pour oeil) : commence par coopérer (nier), + puis imite le dernier coup de l'adversaire. + """ + def __init__(self): + """ + Constructeur de la classe TitForTat. + """ + super().__init__() # Appel du constructeur de la classe parente + + def jouer(self): + """ + Méthode qui détermine l'action du joueur selon la stratégie Tit for Tat. + + Returns: + 'avoue' ou 'nie' selon la stratégie + """ + # Si c'est le premier coup, on coopère (nie) + if not self.historique_adversaire: + return "nie" + # Sinon, on imite le dernier coup de l'adversaire + else: + return self.historique_adversaire[-1] + + +class Dummy(Prisonnier): + """ + Stratégie Dummy : toujours coopérer ou toujours trahir selon un paramètre. + """ + def __init__(self, coopere=True): + """ + Constructeur de la classe Dummy. + + Args: + coopere: si True, toujours coopérer (nier), sinon toujours trahir (avouer) + """ + super().__init__() # Appel du constructeur de la classe parente + self.coopere = coopere + + def jouer(self): + """ + Méthode qui détermine l'action du joueur selon la stratégie Dummy. + + Returns: + 'avoue' ou 'nie' selon la stratégie + """ + if self.coopere: + return "nie" # Coopérer = nier + else: + return "avoue" # Trahir = avouer + + +def jouer_partie(joueur1, joueur2, matrice_pertes, nb_tours=10): + """ + Fonction qui simule une partie entre deux joueurs. + + Args: + joueur1: premier joueur + joueur2: deuxième joueur + matrice_pertes: dictionnaire des pertes + nb_tours: nombre de tours à jouer + + Returns: + tuple des scores totaux (score_joueur1, score_joueur2) + """ + score_joueur1 = 0 + score_joueur2 = 0 + + for tour in range(nb_tours): + # Les joueurs choisissent leur action + action_joueur1 = joueur1.jouer() + action_joueur2 = joueur2.jouer() + + # On calcule les pertes pour ce tour + perte_joueur1, perte_joueur2 = matrice_pertes[(action_joueur1, action_joueur2)] + + # On met à jour les scores (négatif des pertes) + score_joueur1 -= perte_joueur1 + score_joueur2 -= perte_joueur2 + + # On met à jour l'historique des joueurs + joueur1.maj(action_joueur2) + joueur2.maj(action_joueur1) + + # Affichage du tour + print(f"Tour {tour+1}: Joueur 1 joue {action_joueur1}, Joueur 2 joue {action_joueur2}") + print(f"Pertes: Joueur 1 = {perte_joueur1}, Joueur 2 = {perte_joueur2}") + print(f"Scores cumulés: Joueur 1 = {score_joueur1}, Joueur 2 = {score_joueur2}\n") + + return score_joueur1, score_joueur2 + + +# Main pour tester le code +if __name__ == "__main__": + # Définition des actions possibles + actions = ["avoue", "nie"] + + # Représentation des pertes (peines) par un dictionnaire + pertes = { + ("avoue", "avoue"): (3, 3), + ("avoue", "nie"): (0, 10), + ("nie", "avoue"): (10, 0), + ("nie", "nie"): (1, 1) + } + + print("Exercice 2: Stratégies et dilemme itéré") + print("======================================") + + print("\nTest des classes de stratégies") + print("-----------------------------") + + # Création des joueurs + p_random = Prisonnier() + p_tit_for_tat = TitForTat() + p_dummy_coopere = Dummy(coopere=True) + p_dummy_trahit = Dummy(coopere=False) + + print("Joueur aléatoire (Prisonnier) :") + for i in range(3): + print(f"Coup {i+1}: {p_random.jouer()}") + + print("\nJoueur TitForTat :") + print(f"Premier coup (sans historique): {p_tit_for_tat.jouer()}") + + # Simulons quelques coups de l'adversaire + adversaire_coups = ["avoue", "nie", "avoue"] + for i, coup in enumerate(adversaire_coups): + p_tit_for_tat.maj(coup) + print(f"Après que l'adversaire a joué {coup}, TitForTat joue: {p_tit_for_tat.jouer()}") + + print("\nJoueur Dummy (coopère) :") + for i in range(3): + print(f"Coup {i+1}: {p_dummy_coopere.jouer()}") + + print("\nJoueur Dummy (trahit) :") + for i in range(3): + print(f"Coup {i+1}: {p_dummy_trahit.jouer()}") + + print("\nSimulation d'une partie") + print("---------------------") + + # Réinitialisation des joueurs pour la partie + joueur1 = TitForTat() + joueur2 = Dummy(coopere=False) + + print(f"Joueur 1: TitForTat") + print(f"Joueur 2: Dummy (trahit)") + + # Jouer une partie de 5 tours + score_joueur1, score_joueur2 = jouer_partie(joueur1, joueur2, pertes, nb_tours=5) + + print("Résultat final:") + print(f"Score Joueur 1 (TitForTat): {score_joueur1}") + print(f"Score Joueur 2 (Dummy trahit): {score_joueur2}") + + if score_joueur1 > score_joueur2: + print("Le Joueur 1 (TitForTat) gagne!") + elif score_joueur2 > score_joueur1: + print("Le Joueur 2 (Dummy trahit) gagne!") + else: + print("Match nul!") \ No newline at end of file