Files
DEV5.2/TP01/code.py
2024-10-23 11:58:29 +02:00

197 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import heapq
import random
class Noeud:
def __init__(self, etat, parent, cout, heuristique):
self.etat = etat
self.parent = parent
self.cout = cout
self.heuristique = heuristique
def __lt__(self, other):
return self.cout + self.heuristique < other.cout + other.heuristique
def __eq__(self, other):
return self.etat == other.etat
def __hash__(self):
return hash(tuple(self.etat))
def __str__(self):
return str(self.etat)
def afficher_etat(etat_jeu) :
print(etat_jeu)
def xor_etat(etat_jeu):
xor_total = 0
for nb_objets in etat_jeu:
xor_total ^= nb_objets
return xor_total
def heuristique(etat_jeu):
xor_valeur = xor_etat(etat_jeu)
if xor_valeur == 0:
# Position désavantageuse (perdante)
return 100 + sum(etat_jeu) # Pénalité
else:
# Position avantageuse (gagnante)
return sum(etat_jeu) # Heuristique standard
def appliquer_mouvement(etat_jeu, tas_index, nombre_objets) :
if nombre_objets > etat_jeu[tas_index] :
print("Erreur : nombre d'objets à retirer supérieur au nombre d'objets dans le tas.")
return etat_jeu
else :
etat_jeu[tas_index] -= nombre_objets
return etat_jeu
def cout_transition(etat_courant, etat_suivant):
return 1
def est_etat_final(etat):
return all(pile == 0 for pile in etat)
def generer_successeurs(etat):
successeurs = []
for i in range(len(etat)):
if etat[i] > 0:
for j in range(1, etat[i] + 1):
nouvel_etat = etat[:]
nouvel_etat[i] -= j
successeurs.append(nouvel_etat)
return successeurs
def algorithme_a_star(etat_initial):
noeud_initial = Noeud(etat_initial, None, 0, heuristique(etat_initial))
frontiere = []
heapq.heappush(frontiere, noeud_initial)
visites = set()
while frontiere:
noeud_courant = heapq.heappop(frontiere)
if est_etat_final(noeud_courant.etat):
chemin = []
while noeud_courant:
chemin.append(noeud_courant.etat)
noeud_courant = noeud_courant.parent
return chemin[::-1]
visites.add(tuple(noeud_courant.etat))
for successeur in generer_successeurs(noeud_courant.etat):
if tuple(successeur) not in visites:
cout = noeud_courant.cout + cout_transition(noeud_courant.etat, successeur)
heur = heuristique(successeur)
noeud_successeur = Noeud(successeur, noeud_courant, cout, heur)
heapq.heappush(frontiere, noeud_successeur)
return None
def reconstruire_chemin(noeud_final):
"""
Reconstruit la séquence de mouvements depuis létat initial jusquà létat final.
:param noeud_final: Le nœud final de l'algorithme A*.
:return: Une liste des états représentant le chemin de l'état initial à l'état final.
"""
chemin = []
noeud_courant = noeud_final
while noeud_courant:
chemin.append(noeud_courant.etat)
noeud_courant = noeud_courant.parent
return chemin[::-1]
def sauvegarder_partie(historique, fichier="historique_parties.txt"):
"""
Sauvegarde l'historique de la partie dans un fichier.
:param historique: Liste des coups effectués pendant la partie.
:param fichier: Nom du fichier où sauvegarder l'historique.
"""
with open(fichier, "a") as f:
f.write("Nouvelle partie\n")
for coup in historique:
f.write(f"{coup}\n")
f.write("\n")
def jeu_nim(etat_initial):
etat = etat_initial[:]
historique = []
while not est_etat_final(etat):
afficher_etat(etat)
try:
pile = int(input("Entrez le numéro de la pile (1, 2, 3, ...): ")) - 1
nb_objets = int(input("Entrez le nombre d'objets à retirer: "))
historique.append(f"Joueur: Pile {pile + 1}, Objets retirés: {nb_objets}")
appliquer_mouvement(etat, pile, nb_objets)
afficher_etat(etat)
except ValueError:
print("Entrée invalide. Veuillez entrer des nombres entiers.")
continue
if est_etat_final(etat):
print("\nFélicitations ! Vous avez gagné !")
break
# Tour de l'IA
chemin_optimal = algorithme_a_star(etat)
if chemin_optimal and len(chemin_optimal) > 1:
etat_ia = chemin_optimal[1]
historique.append(f"IA: Pile {pile + 1}, Objets retirés: {nb_objets}")
print("\nL'IA joue...")
etat = etat_ia
if est_etat_final(etat):
print("\n L'IA a gagné !")
break
sauvegarder_partie(historique)
def pile_random(etat) :
piles_non_vides = [i for i, pile in enumerate(etat) if pile > 0]
return random.choice(piles_non_vides)
def nb_objets_random(etat, pile):
return random.randint(1, etat[pile])
def jeu_nim_random(etat_initial):
etat = etat_initial[:]
historique = []
while not est_etat_final(etat):
afficher_etat(etat)
try:
pile = pile_random(etat)
nb_objets = nb_objets_random(etat, pile)
historique.append(f"Joueur: Pile {pile + 1}, Objets retirés: {nb_objets}")
appliquer_mouvement(etat, pile, nb_objets)
afficher_etat(etat)
except ValueError:
print("Entrée invalide. Veuillez entrer des nombres entiers.")
continue
if est_etat_final(etat):
print("\nFélicitations ! Vous avez gagné !")
break
# Tour de l'IA
chemin_optimal = algorithme_a_star(etat)
if chemin_optimal and len(chemin_optimal) > 1:
etat_ia = chemin_optimal[1]
historique.append(f"IA: Pile {pile + 1}, Objets retirés: {nb_objets}")
print("\nL'IA joue...")
etat = etat_ia
if est_etat_final(etat):
print("\n L'IA a gagné !")
break
sauvegarder_partie(historique)
etat_initial = [3, 4, 5]
jeu_nim_random(etat_initial)