From 02e56f43a7b143255694519d025eb093ed0a9a3d Mon Sep 17 00:00:00 2001
From: Guillaume VALLAT <guillaume.vallat@etu.u-pec.fr>
Date: Wed, 23 Oct 2024 11:11:19 +0200
Subject: [PATCH] =?UTF-8?q?T=C3=A9l=C3=A9verser=20les=20fichiers=20vers=20?=
 =?UTF-8?q?"/"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 heuristique_Nim.py | 161 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)
 create mode 100644 heuristique_Nim.py

diff --git a/heuristique_Nim.py b/heuristique_Nim.py
new file mode 100644
index 0000000..d69ffe6
--- /dev/null
+++ b/heuristique_Nim.py
@@ -0,0 +1,161 @@
+import json
+import random
+import datetime
+import heapq  # Pour la file de priorité (algorithme A*)
+
+# Fonction pour afficher l'état actuel du jeu
+def afficher_etat(etat_jeu):
+    print("\nVoici l'état actuel des tas :")
+    for i, nb_objets in enumerate(etat_jeu):
+        print(f"Tas {i+1}: {nb_objets} objets")
+    print()
+
+# Fonction pour générer tous les mouvements possibles
+def generer_mouvements(etat_jeu):
+    mouvements = []
+    for i, nb_objets in enumerate(etat_jeu):
+        for n in range(1, nb_objets + 1):
+            nouvel_etat = etat_jeu[:]
+            nouvel_etat[i] -= n
+            mouvements.append(nouvel_etat)
+    return mouvements
+
+# Fonction pour appliquer un mouvement à l'état
+def appliquer_mouvement(etat_jeu, tas_index, nb_objets):
+    if 1 <= nb_objets <= etat_jeu[tas_index]:
+        etat_jeu[tas_index] -= nb_objets
+        return etat_jeu
+    else:
+        raise ValueError("Mouvement invalide")
+
+# Fonction pour vérifier si l'état est final (tous les tas sont vides)
+def est_etat_final(etat_jeu):
+    return all(nb_objets == 0 for nb_objets in etat_jeu)
+
+# Fonction heuristique pour estimer le coût restant
+def heuristique(etat_jeu):
+    # Heuristique simple : somme des objets restants
+    return sum(etat_jeu)
+
+# Classe Noeud pour l'algorithme A*
+class Noeud:
+    def __init__(self, etat, parent=None, g=0, h=0):
+        self.etat = etat
+        self.parent = parent
+        self.g = g  # Coût pour atteindre ce nœud
+        self.h = h  # Heuristique estimée
+        self.f = g + h  # Fonction de coût totale
+
+    def __lt__(self, autre):
+        return self.f < autre.f
+
+# Fonction pour reconstruire le chemin optimal
+def reconstruire_chemin(noeud_final):
+    chemin = []
+    noeud_actuel = noeud_final
+    while noeud_actuel:
+        chemin.append(noeud_actuel.etat)
+        noeud_actuel = noeud_actuel.parent
+    return chemin[::-1]  # Inverser le chemin pour obtenir du départ à l'arrivée
+
+# Algorithme A* pour résoudre le jeu de Nim
+def algorithme_a_star(etat_initial):
+    # Initialisation de la file de priorité
+    open_list = []
+    heapq.heappush(open_list, Noeud(etat_initial, h=heuristique(etat_initial)))
+    
+    # Ensemble des états déjà visités
+    visited = set()
+    
+    while open_list:
+        noeud_courant = heapq.heappop(open_list)
+        
+        if est_etat_final(noeud_courant.etat):
+            return reconstruire_chemin(noeud_courant)
+        
+        visited.add(tuple(noeud_courant.etat))
+        
+        for mouvement in generer_mouvements(noeud_courant.etat):
+            if tuple(mouvement) not in visited:
+                noeud_successeur = Noeud(mouvement, parent=noeud_courant,
+                                         g=noeud_courant.g + 1,
+                                         h=heuristique(mouvement))
+                heapq.heappush(open_list, noeud_successeur)
+
+# Sauvegarder la partie dans un fichier json
+
+def sauvegarder_partie(historique, resultat):
+    partie = {
+        "date": str(datetime.datetime.now()),
+        "historique": historique,
+        "resultat": resultat
+    }
+
+     # Chargement du fichier JSON existant ou création s'il n'existe pas
+    try:
+        with open("historique_nim.json", "r") as fichier:
+            sauvegardes = json.load(fichier)
+    except FileNotFoundError:
+        sauvegardes = []
+    
+    # Ajouter la nouvelle partie à l'historique
+    sauvegardes.append(partie)
+    
+    # Sauvegarde dans le fichier
+    with open("historique_nim.json", "w") as fichier:
+        json.dump(sauvegardes, fichier, indent=4)
+
+# Boucle principale pour jouer une partie
+def jeu_de_nim(tas_initial, mode="normal"):
+    etat_jeu = tas_initial[:]
+    joueur = 1  # 1 pour joueur humain, 2 pour ordinateur
+    historique = [f"Tas initiaux: {etat_jeu}"]
+
+    while not est_etat_final(etat_jeu):
+        if joueur == 1:
+            print("Tour du joueur :")
+            afficher_etat(etat_jeu)
+            tas_choisi = int(input("Choisissez un tas (numéro): ")) - 1
+            nb_objets = int(input(f"Combien d'objets voulez-vous prendre dans le tas {tas_choisi + 1}? "))
+            etat_jeu = appliquer_mouvement(etat_jeu, tas_choisi, nb_objets)
+            historique.append(f"Joueur a pris {nb_objets} objets du tas {tas_choisi + 1}")
+        else:
+            print("Tour de l'ordinateur :")
+            meilleur_chemin = algorithme_a_star(etat_jeu)
+            prochain_etat = meilleur_chemin[1]  # Choisir le premier mouvement du chemin
+            for i in range(len(etat_jeu)):
+                if etat_jeu[i] != prochain_etat[i]:
+                    nb_objets = etat_jeu[i] - prochain_etat[i]
+                    etat_jeu = prochain_etat
+                    historique.append(f"Ordinateur a pris {nb_objets} objets du tas {i + 1}")
+                    break
+        
+        joueur = 2 if joueur == 1 else 1
+    
+    # Condition de victoire/perte
+    if mode == "normal":
+        if joueur == 2:
+            print("Félicitations, vous avez gagné!")
+            resultat = "Joueur a gagné"
+        else:
+            print("Dommage, l'ordinateur a gagné.")
+            resultat = "Ordinateur a gagné"
+    elif mode == "misere":
+        if joueur == 2:
+            print("L'ordinateur a perdu (version misère)!")
+            resultat = "Ordinateur a perdu (misère)"
+        else:
+            print("Vous avez perdu (version misère).")
+            resultat = "Joueur a perdu (misère)"
+    
+    # Sauvegarder la partie
+    sauvegarder_partie(historique, resultat)
+
+# Lancement du jeu
+if __name__ == "__main__":
+    tas_initial = [3, 4, 5]  # Exemple de configuration initiale
+    mode_de_jeu = input("Choisissez le mode de jeu (normal/misere) : ").strip().lower()
+    if mode_de_jeu not in ["normal", "misere"]:
+        mode_de_jeu = "normal"
+    
+    jeu_de_nim(tas_initial, mode_de_jeu)
\ No newline at end of file