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)