From affd1b3ae01120e269f6b3c5e6b19b1570916d7c Mon Sep 17 00:00:00 2001 From: landrin Date: Wed, 23 Oct 2024 21:37:10 +0200 Subject: [PATCH] rendu final --- TPIA/jeu_nim/exo1.py | 24 +++++++++++++++ TPIA/jeu_nim/exo10.py | 0 TPIA/jeu_nim/exo2.py | 52 +++++++++++++++++++++++++++++++ TPIA/jeu_nim/exo3.py | 23 ++++++++++++++ TPIA/jeu_nim/exo4.py | 17 ++++++++++ TPIA/jeu_nim/exo5.py | 10 ++++++ TPIA/jeu_nim/exo6.py | 66 +++++++++++++++++++++++++++++++++++++++ TPIA/jeu_nim/exo7.py | 72 +++++++++++++++++++++++++++++++++++++++++++ TPIA/jeu_nim/exo8.py | 72 +++++++++++++++++++++++++++++++++++++++++++ TPIA/jeu_nim/exo8b.py | 44 ++++++++++++++++++++++++++ TPIA/jeu_nim/exo9.py | 46 +++++++++++++++++++++++++++ 11 files changed, 426 insertions(+) create mode 100644 TPIA/jeu_nim/exo1.py create mode 100644 TPIA/jeu_nim/exo10.py create mode 100644 TPIA/jeu_nim/exo2.py create mode 100644 TPIA/jeu_nim/exo3.py create mode 100644 TPIA/jeu_nim/exo4.py create mode 100644 TPIA/jeu_nim/exo5.py create mode 100644 TPIA/jeu_nim/exo6.py create mode 100644 TPIA/jeu_nim/exo7.py create mode 100644 TPIA/jeu_nim/exo8.py create mode 100644 TPIA/jeu_nim/exo8b.py create mode 100644 TPIA/jeu_nim/exo9.py diff --git a/TPIA/jeu_nim/exo1.py b/TPIA/jeu_nim/exo1.py new file mode 100644 index 0000000..e6bb079 --- /dev/null +++ b/TPIA/jeu_nim/exo1.py @@ -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 + + diff --git a/TPIA/jeu_nim/exo10.py b/TPIA/jeu_nim/exo10.py new file mode 100644 index 0000000..e69de29 diff --git a/TPIA/jeu_nim/exo2.py b/TPIA/jeu_nim/exo2.py new file mode 100644 index 0000000..d485286 --- /dev/null +++ b/TPIA/jeu_nim/exo2.py @@ -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) + diff --git a/TPIA/jeu_nim/exo3.py b/TPIA/jeu_nim/exo3.py new file mode 100644 index 0000000..f10ae1f --- /dev/null +++ b/TPIA/jeu_nim/exo3.py @@ -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] diff --git a/TPIA/jeu_nim/exo4.py b/TPIA/jeu_nim/exo4.py new file mode 100644 index 0000000..f4e766b --- /dev/null +++ b/TPIA/jeu_nim/exo4.py @@ -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 diff --git a/TPIA/jeu_nim/exo5.py b/TPIA/jeu_nim/exo5.py new file mode 100644 index 0000000..b5f811b --- /dev/null +++ b/TPIA/jeu_nim/exo5.py @@ -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 diff --git a/TPIA/jeu_nim/exo6.py b/TPIA/jeu_nim/exo6.py new file mode 100644 index 0000000..28f7b13 --- /dev/null +++ b/TPIA/jeu_nim/exo6.py @@ -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) diff --git a/TPIA/jeu_nim/exo7.py b/TPIA/jeu_nim/exo7.py new file mode 100644 index 0000000..fc33e36 --- /dev/null +++ b/TPIA/jeu_nim/exo7.py @@ -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) diff --git a/TPIA/jeu_nim/exo8.py b/TPIA/jeu_nim/exo8.py new file mode 100644 index 0000000..15acf20 --- /dev/null +++ b/TPIA/jeu_nim/exo8.py @@ -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) diff --git a/TPIA/jeu_nim/exo8b.py b/TPIA/jeu_nim/exo8b.py new file mode 100644 index 0000000..c59fad6 --- /dev/null +++ b/TPIA/jeu_nim/exo8b.py @@ -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 où 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) diff --git a/TPIA/jeu_nim/exo9.py b/TPIA/jeu_nim/exo9.py new file mode 100644 index 0000000..690e7d8 --- /dev/null +++ b/TPIA/jeu_nim/exo9.py @@ -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()