Files
DEV5.2/TP01/code.py

197 lines
6.0 KiB
Python
Raw Normal View History

2024-10-23 11:58:29 +02:00
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 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)