rendu final

This commit is contained in:
Dylan LANDRIN 2024-10-23 21:37:10 +02:00
commit affd1b3ae0
11 changed files with 426 additions and 0 deletions

24
TPIA/jeu_nim/exo1.py Normal file
View File

@ -0,0 +1,24 @@
def afficher_etat(etat_jeu):
print("État actuel du jeu:")
for i, tas in enumerate(etat_jeu):
print(f"Tas {i+1}: {tas} objets")
#etat_jeu = [3, 4, 5]#
#afficher_etat(etat_jeu)#
# Test de la fonction avec plusieurs configurations
configurations = [
[3, 4, 5],
[1, 0, 2],
[0, 0, 1],
[4, 4, 4],
[5, 1, 0, 2]
]
for etat in configurations:
afficher_etat(etat)
print('-' * 20) # Pour séparer les affichages entre les tests

0
TPIA/jeu_nim/exo10.py Normal file
View File

52
TPIA/jeu_nim/exo2.py Normal file
View File

@ -0,0 +1,52 @@
def generer_mouvements(etat_jeu):
mouvements = [] # Liste pour stocker les nouveaux états possibles
for i, tas in enumerate(etat_jeu):
# Vérifier si le tas a au moins un objet
if tas > 0:
# Retirer 1 à tas objets, générer un nouvel état
for nb_objets in range(1, tas + 1):
nouvel_etat = etat_jeu.copy() # Faire une copie de l'état actuel
nouvel_etat[i] -= nb_objets # Retirer des objets de ce tas
mouvements.append(nouvel_etat) # Ajouter le nouvel état à la liste
return mouvements
etat_jeu = [3, 4, 5]
mouvements_possibles = generer_mouvements(etat_jeu)
for mouvement in mouvements_possibles:
print(mouvement)
def afficher_mouvements(mouvements):
print("Mouvements possibles :")
for mouvement in mouvements:
print(mouvement)
# Vérification avec plusieurs configurations d'état de jeu
etat_jeu1 = [3, 4, 5]
etat_jeu2 = [1, 0, 2]
etat_jeu3 = [0, 0, 1]
etat_jeu4 = [2, 2, 2]
print("Test avec l'état [3, 4, 5] :")
mouvements1 = generer_mouvements(etat_jeu1)
afficher_mouvements(mouvements1)
print('-' * 30)
print("Test avec l'état [1, 0, 2] :")
mouvements2 = generer_mouvements(etat_jeu2)
afficher_mouvements(mouvements2)
print('-' * 30)
print("Test avec l'état [0, 0, 1] :")
mouvements3 = generer_mouvements(etat_jeu3)
afficher_mouvements(mouvements3)
print('-' * 30)
print("Test avec l'état [2, 2, 2] :")
mouvements4 = generer_mouvements(etat_jeu4)
afficher_mouvements(mouvements4)
print('-' * 30)

23
TPIA/jeu_nim/exo3.py Normal file
View File

@ -0,0 +1,23 @@
def appliquer_mouvement(etat_jeu, tas_index, nb_objets):
# Créer une copie de l'état du jeu pour ne pas modifier l'état original
nouvel_etat = etat_jeu.copy()
# Retirer nb_objets du tas à l'index tas_index
if 0 <= tas_index < len(nouvel_etat) and nouvel_etat[tas_index] >= nb_objets:
nouvel_etat[tas_index] -= nb_objets
else:
raise ValueError("Mouvement invalide : index du tas ou nombre d'objets incorrect")
return nouvel_etat
# Test 1 : Retirer 3 objets du tas 0 (le premier tas)
etat1 = appliquer_mouvement([3, 4, 5], 0, 3)
print("Test 1 :", etat1) # [0, 4, 5]
# Test 2 : Retirer 1 objet du tas 2 (le troisième tas)
etat2 = appliquer_mouvement([1, 0, 2], 2, 1)
print("Test 2 :", etat2) # [1, 0, 1]
# Test 3 : Retirer 1 objet du tas 1 (le deuxième tas)
etat3 = appliquer_mouvement([2, 2, 2], 1, 1)
print("Test 3 :", etat3) # [2, 1, 2]

17
TPIA/jeu_nim/exo4.py Normal file
View File

@ -0,0 +1,17 @@
def heuristique(etat_jeu):
# Retourner le nombre total d'objets restants dans tous les tas
return sum(etat_jeu)
# Test avec différents états de jeu
etat_jeu1 = [3, 4, 5] # Total de 12 objets
etat_jeu2 = [1, 0, 2] # Total de 3 objets
etat_jeu3 = [0, 0, 1] # Total de 1 objet
etat_jeu4 = [0, 0, 0] # Aucun objet restant, donc état final
print("Heuristique pour [3, 4, 5] :", heuristique(etat_jeu1)) # 12
print("Heuristique pour [1, 0, 2] :", heuristique(etat_jeu2)) # 3
print("Heuristique pour [0, 0, 1] :", heuristique(etat_jeu3)) # 1
print("Heuristique pour [0, 0, 0] :", heuristique(etat_jeu4)) # 0
etat_jeu = [3, 2, 2] # Un total de 7 objets

10
TPIA/jeu_nim/exo5.py Normal file
View File

@ -0,0 +1,10 @@
def est_etat_final(etat_jeu):
# Un état est final si tous les tas sont vides (c'est-à-dire que tous les éléments de la liste sont égaux à 0)
return all(tas == 0 for tas in etat_jeu)
# Exemple d'état final et non-final
etat_jeu1 = [0, 0, 0] # Tous les tas sont vides, donc état final
etat_jeu2 = [1, 0, 2] # Il reste encore des objets, donc pas un état final
print("L'état [0, 0, 0] est-il un état final ?", est_etat_final(etat_jeu1)) # True
print("L'état [1, 0, 2] est-il un état final ?", est_etat_final(etat_jeu2)) # False

66
TPIA/jeu_nim/exo6.py Normal file
View File

@ -0,0 +1,66 @@
def cout_mouvement(etat_actuel, nouvel_etat):
# Chaque mouvement a un coût constant de 1
return 1
etat_jeu1 = [3, 4, 5] # État initial
etat_jeu2 = [3, 3, 5] # Après avoir retiré 1 objet du deuxième tas
# Le coût de passer de l'état [3, 4, 5] à l'état [3, 3, 5]
print("Coût du mouvement :", cout_mouvement(etat_jeu1, etat_jeu2)) # 1
import heapq
def algorithme_a_star(etat_initial):
# File de priorité (tas) pour les nœuds à explorer
file_priorite = []
# Ajouter l'état initial dans la file de priorité (f(n), g(n), état)
heapq.heappush(file_priorite, (0 + heuristique(etat_initial), 0, etat_initial))
# Dictionnaire pour stocker le coût minimal pour atteindre chaque état
cout_minimal = {tuple(etat_initial): 0}
# Dictionnaire pour reconstruire le chemin
predecesseurs = {tuple(etat_initial): None}
while file_priorite:
# Extraire l'état avec le plus faible coût estimé f(n)
_, cout_actuel, etat_actuel = heapq.heappop(file_priorite)
# Vérifier si l'état actuel est l'état final
if est_etat_final(etat_actuel):
# Reconstruire le chemin optimal
chemin = []
while etat_actuel is not None:
chemin.append(etat_actuel)
etat_actuel = predecesseurs[tuple(etat_actuel)]
chemin.reverse() # On inverse le chemin pour l'avoir dans l'ordre
return chemin
# Générer tous les mouvements possibles à partir de l'état actuel
mouvements_possibles = generer_mouvements(etat_actuel)
for nouvel_etat in mouvements_possibles:
# Calculer le coût du mouvement (toujours 1 dans notre cas)
cout_mouvement_actuel = cout_actuel + cout_mouvement(etat_actuel, nouvel_etat)
# Si le nouvel état est rencontré avec un coût inférieur à celui déjà connu
if tuple(nouvel_etat) not in cout_minimal or cout_mouvement_actuel < cout_minimal[tuple(nouvel_etat)]:
cout_minimal[tuple(nouvel_etat)] = cout_mouvement_actuel
predecesseurs[tuple(nouvel_etat)] = etat_actuel
# Calculer f(n) = g(n) + h(n)
f_n = cout_mouvement_actuel + heuristique(nouvel_etat)
# Ajouter le nouvel état dans la file de priorité
heapq.heappush(file_priorite, (f_n, cout_mouvement_actuel, nouvel_etat))
# Si aucun chemin n'a été trouvé (ce qui ne devrait pas arriver dans le jeu de Nim)
return None
etat_initial = [3, 4, 5] # Exemple d'état initial
# Appel de l'algorithme A* pour trouver le chemin optimal
chemin_optimal = algorithme_a_star(etat_initial)
# Affichage du chemin
for etat in chemin_optimal:
print(etat)

72
TPIA/jeu_nim/exo7.py Normal file
View File

@ -0,0 +1,72 @@
import heapq
def algorithme_a_star(etat_initial):
# File de priorité (tas) pour les nœuds à explorer
file_priorite = []
# Ajouter l'état initial dans la file de priorité (f(n), g(n), état)
heapq.heappush(file_priorite, (0 + heuristique(etat_initial), 0, etat_initial))
# Dictionnaire pour stocker le coût minimal pour atteindre chaque état
cout_minimal = {tuple(etat_initial): 0}
# Dictionnaire pour reconstruire le chemin
predecesseurs = {tuple(etat_initial): None}
# Ensemble pour stocker les états déjà visités
etats_visites = set()
while file_priorite:
# Extraire l'état avec le plus faible coût estimé f(n)
_, cout_actuel, etat_actuel = heapq.heappop(file_priorite)
# Convertir l'état en tuple pour le stockage dans les ensembles
etat_tuple = tuple(etat_actuel)
# Si l'état a déjà été visité, on l'ignore
if etat_tuple in etats_visites:
continue
# Marquer l'état comme visité
etats_visites.add(etat_tuple)
# Vérifier si l'état actuel est l'état final
if est_etat_final(etat_actuel):
# Reconstruire le chemin optimal
chemin = []
while etat_actuel is not None:
chemin.append(etat_actuel)
etat_actuel = predecesseurs[tuple(etat_actuel)]
chemin.reverse() # On inverse le chemin pour l'avoir dans l'ordre
return chemin
# Générer tous les mouvements possibles à partir de l'état actuel
mouvements_possibles = generer_mouvements(etat_actuel)
for nouvel_etat in mouvements_possibles:
# Calculer le coût du mouvement (toujours 1 dans notre cas)
cout_mouvement_actuel = cout_actuel + cout_mouvement(etat_actuel, nouvel_etat)
# Si le nouvel état est rencontré avec un coût inférieur à celui déjà connu
etat_tuple_nouveau = tuple(nouvel_etat)
# Vérifier si l'état a déjà été visité ou si le coût est inférieur
if etat_tuple_nouveau not in etats_visites or cout_mouvement_actuel < cout_minimal.get(etat_tuple_nouveau, float('inf')):
cout_minimal[etat_tuple_nouveau] = cout_mouvement_actuel
predecesseurs[etat_tuple_nouveau] = etat_actuel
# Calculer f(n) = g(n) + h(n)
f_n = cout_mouvement_actuel + heuristique(nouvel_etat)
# Ajouter le nouvel état dans la file de priorité
heapq.heappush(file_priorite, (f_n, cout_mouvement_actuel, nouvel_etat))
# Si aucun chemin n'a été trouvé (ce qui ne devrait pas arriver dans le jeu de Nim)
return None
etat_initial = [3, 4, 5] # Exemple d'état initial
# Appel de l'algorithme A* pour trouver le chemin optimal
chemin_optimal = algorithme_a_star(etat_initial)
# Affichage du chemin
for etat in chemin_optimal:
print(etat)

72
TPIA/jeu_nim/exo8.py Normal file
View File

@ -0,0 +1,72 @@
import heapq
def algorithme_a_star(etat_initial):
# File de priorité (tas) pour les nœuds à explorer
file_priorite = []
# Ajouter l'état initial dans la file de priorité (f(n), g(n), état)
heapq.heappush(file_priorite, (0 + heuristique(etat_initial), 0, etat_initial))
# Dictionnaire pour stocker le coût minimal pour atteindre chaque état
cout_minimal = {tuple(etat_initial): 0}
# Dictionnaire pour stocker le parent de chaque état (reconstruction du chemin)
predecesseurs = {tuple(etat_initial): None}
# Ensemble pour stocker les états déjà visités
etats_visites = set()
while file_priorite:
# Extraire l'état avec le plus faible coût estimé f(n)
_, cout_actuel, etat_actuel = heapq.heappop(file_priorite)
# Convertir l'état en tuple pour le stockage dans les ensembles
etat_tuple = tuple(etat_actuel)
# Si l'état a déjà été visité, on l'ignore
if etat_tuple in etats_visites:
continue
# Marquer l'état comme visité
etats_visites.add(etat_tuple)
# Vérifier si l'état actuel est l'état final
if est_etat_final(etat_actuel):
# Reconstruire le chemin optimal
chemin = []
while etat_actuel is not None:
chemin.append(etat_actuel)
etat_actuel = predecesseurs[tuple(etat_actuel)]
chemin.reverse() # On inverse le chemin pour l'avoir dans l'ordre
return chemin
# Générer tous les mouvements possibles à partir de l'état actuel
mouvements_possibles = generer_mouvements(etat_actuel)
for nouvel_etat in mouvements_possibles:
# Calculer le coût du mouvement (toujours 1 dans notre cas)
cout_mouvement_actuel = cout_actuel + cout_mouvement(etat_actuel, nouvel_etat)
# Si le nouvel état est rencontré avec un coût inférieur à celui déjà connu
etat_tuple_nouveau = tuple(nouvel_etat)
# Vérifier si l'état a déjà été visité ou si le coût est inférieur
if etat_tuple_nouveau not in etats_visites or cout_mouvement_actuel < cout_minimal.get(etat_tuple_nouveau, float('inf')):
cout_minimal[etat_tuple_nouveau] = cout_mouvement_actuel
predecesseurs[etat_tuple_nouveau] = etat_actuel # Stocker le parent
# Calculer f(n) = g(n) + h(n)
f_n = cout_mouvement_actuel + heuristique(nouvel_etat)
# Ajouter le nouvel état dans la file de priorité
heapq.heappush(file_priorite, (f_n, cout_mouvement_actuel, nouvel_etat))
# Si aucun chemin n'a été trouvé (ce qui ne devrait pas arriver dans le jeu de Nim)
return None
etat_initial = [3, 4, 5] # Exemple d'état initial
# Appel de l'algorithme A* pour trouver le chemin optimal
chemin_optimal = algorithme_a_star(etat_initial)
# Affichage du chemin
for etat in chemin_optimal:
print(etat)

44
TPIA/jeu_nim/exo8b.py Normal file
View File

@ -0,0 +1,44 @@
def reconstruire_chemin(predecesseurs, etat_final):
"""
Reconstruit le chemin à partir de l'état final en suivant les parents jusqu'à l'état initial.
Args:
predecesseurs (dict): Dictionnaire chaque clé est un état et la valeur est le parent de cet état.
etat_final (list): L'état final à partir duquel remonter pour trouver le chemin.
Returns:
list: Le chemin depuis l'état initial jusqu'à l'état final, incluant tous les états intermédiaires.
"""
chemin = []
etat_actuel = tuple(etat_final) # Convertir en tuple pour correspondre aux clés dans 'predecesseurs'
# Remonter à travers les parents jusqu'à l'état initial
while etat_actuel is not None:
chemin.append(list(etat_actuel)) # Ajouter l'état actuel au chemin (reconverti en liste pour l'affichage)
etat_actuel = predecesseurs[etat_actuel] # Suivre le parent de l'état actuel
# Inverser le chemin pour qu'il soit dans l'ordre de l'état initial à l'état final
chemin.reverse()
return chemin
etat_initial = [3, 4, 5] # Exemple d'état initial
etat_final = [0, 0, 0] # Exemple d'état final (victoire)
# Dictionnaire des parents (simulé pour cet exemple)
predecesseurs = {
(3, 4, 5): None, # État initial sans parent
(2, 4, 5): (3, 4, 5),
(2, 3, 5): (2, 4, 5),
(2, 3, 4): (2, 3, 5),
(0, 3, 4): (2, 3, 4),
(0, 0, 4): (0, 3, 4),
(0, 0, 0): (0, 0, 4) # État final
}
# Reconstruction du chemin
chemin = reconstruire_chemin(predecesseurs, etat_final)
# Affichage du chemin
for etat in chemin:
print(etat)

46
TPIA/jeu_nim/exo9.py Normal file
View File

@ -0,0 +1,46 @@
def afficher_etat(etat_jeu):
"""Affiche l'état actuel du jeu."""
print("État actuel du jeu :")
for i, tas in enumerate(etat_jeu):
print(f"Tas {i + 1}: {tas} objets")
def appliquer_mouvement(etat_jeu, tas_index, nb_objets):
"""Applique un mouvement et modifie l'état du jeu."""
etat_jeu[tas_index] -= nb_objets
def mouvement_valide(etat_jeu, tas_index, nb_objets):
"""Vérifie si un mouvement est valide."""
return 0 <= tas_index < len(etat_jeu) and 1 <= nb_objets <= etat_jeu[tas_index]
def est_etat_final(etat_jeu):
"""Vérifie si tous les tas sont vides."""
return all(tas == 0 for tas in etat_jeu)
def boucle_de_jeu():
"""Boucle de jeu pour permettre à l'utilisateur de jouer."""
# Initialisation de l'état du jeu (par exemple, trois tas avec 3, 4 et 5 objets)
etat_jeu = [3, 4, 5]
# Boucle principale du jeu
while not est_etat_final(etat_jeu):
# Afficher l'état actuel du jeu
afficher_etat(etat_jeu)
# Demander à l'utilisateur quel tas et combien d'objets retirer
try:
tas_index = int(input("Choisissez un tas (1, 2, 3...): ")) - 1
nb_objets = int(input(f"Combien d'objets voulez-vous retirer du tas {tas_index + 1}? "))
# Vérifier si le mouvement est valide
if mouvement_valide(etat_jeu, tas_index, nb_objets):
appliquer_mouvement(etat_jeu, tas_index, nb_objets)
else:
print("Mouvement invalide ! Essayez à nouveau.")
except ValueError:
print("Entrée invalide. Veuillez entrer des nombres entiers.")
# Fin du jeu : si tous les tas sont vides
print("Félicitations ! Vous avez gagné !")
# Lancer la boucle de jeu
boucle_de_jeu()