first commit
This commit is contained in:
BIN
TP01/JeuNim.pdf
Normal file
BIN
TP01/JeuNim.pdf
Normal file
Binary file not shown.
496
TP01/Nim.ipynb
Normal file
496
TP01/Nim.ipynb
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Implémentation du jeu de Nim"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 12,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"etat_jeu = [3, 4, 5] # Trois tas contenant respectivement 3, 4 et 5 objets.\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 1 "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 13,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"[3, 4, 5]\n",
|
||||||
|
"[0, 0, 0]\n",
|
||||||
|
"[1, 0, 2]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"# A.\n",
|
||||||
|
"def afficher_etat(etat_jeu) :\n",
|
||||||
|
" print(etat_jeu)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"# B.\n",
|
||||||
|
"test1 = [3, 4, 5]\n",
|
||||||
|
"test2 = [0, 0, 0]\n",
|
||||||
|
"test3 = [1, 0, 2]\n",
|
||||||
|
"\n",
|
||||||
|
"afficher_etat(test1)\n",
|
||||||
|
"afficher_etat(test2)\n",
|
||||||
|
"afficher_etat(test3)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 2 : "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 14,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"[(0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5)]\n",
|
||||||
|
"[]\n",
|
||||||
|
"[(0, 1), (2, 1), (2, 2)]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"# A.\n",
|
||||||
|
"\n",
|
||||||
|
"def generer_mouvement(etat_jeu) : \n",
|
||||||
|
" mouvements = []\n",
|
||||||
|
" for i in range(len(etat_jeu)) : # On parcourt les tas\n",
|
||||||
|
" for j in range(etat_jeu[i]) : # On tire le nombre d'objets dans le tas\n",
|
||||||
|
" if etat_jeu[i] > 0 :\n",
|
||||||
|
" mouvements.append((i, j+1)) # On ajoute le mouvement à la liste\n",
|
||||||
|
" return mouvements\n",
|
||||||
|
"\n",
|
||||||
|
"# B.\n",
|
||||||
|
"print(generer_mouvement(test1))\n",
|
||||||
|
"print(generer_mouvement(test2))\n",
|
||||||
|
"print(generer_mouvement(test3))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 3 : "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 15,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# A et B\n",
|
||||||
|
"def appliquer_mouvement(etat_jeu, tas_index, nombre_objets) :\n",
|
||||||
|
" if nombre_objets > etat_jeu[tas_index] :\n",
|
||||||
|
" print(\"Erreur : nombre d'objets à retirer supérieur au nombre d'objets dans le tas.\")\n",
|
||||||
|
" return etat_jeu\n",
|
||||||
|
" else : \n",
|
||||||
|
" etat_jeu[tas_index] -= nombre_objets\n",
|
||||||
|
" return etat_jeu\n",
|
||||||
|
"\n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 4 :"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 16,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"\" étant donné que heuristique est égale à la somme des objets dans les tas, \\nc'est donc un calcul simple qui ne dépend pas de l'ordre des tas. \""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 16,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"# A.\n",
|
||||||
|
"'''\n",
|
||||||
|
"def heuristique(etat_jeu) :\n",
|
||||||
|
" return sum(etat_jeu)\n",
|
||||||
|
"\n",
|
||||||
|
"print(heuristique(test1))\n",
|
||||||
|
"print(heuristique(test2))\n",
|
||||||
|
"print(heuristique(test3))'''\n",
|
||||||
|
"\n",
|
||||||
|
"# B.\n",
|
||||||
|
"''' étant donné que heuristique est égale à la somme des objets dans les tas, \n",
|
||||||
|
"c'est donc un calcul simple qui ne dépend pas de l'ordre des tas. '''\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 5 :"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 17,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"1\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"# A.\n",
|
||||||
|
"def est_etat_final(etat_jeu) :\n",
|
||||||
|
" return sum(etat_jeu) == 0\n",
|
||||||
|
"\n",
|
||||||
|
"# B.\n",
|
||||||
|
"def cout_transition(etat_courant, etat_suivant):\n",
|
||||||
|
" return 1\n",
|
||||||
|
"\n",
|
||||||
|
"# Exemple d'utilisation\n",
|
||||||
|
"etat_courant = [3, 4, 5]\n",
|
||||||
|
"etat_suivant = appliquer_mouvement(etat_courant, 0, 1) # Devrait retourner [2, 4, 5]\n",
|
||||||
|
"print(cout_transition(etat_courant, etat_suivant)) # Devrait retourner 1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 6 : "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 18,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"[[4, 8, 5], [4, 0, 5], [0, 0, 5], [0, 0, 0]]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"import heapq\n",
|
||||||
|
"\n",
|
||||||
|
"class Noeud:\n",
|
||||||
|
" def __init__(self, etat, parent, cout, heuristique):\n",
|
||||||
|
" self.etat = etat\n",
|
||||||
|
" self.parent = parent\n",
|
||||||
|
" self.cout = cout\n",
|
||||||
|
" self.heuristique = heuristique\n",
|
||||||
|
"\n",
|
||||||
|
" def __lt__(self, other):\n",
|
||||||
|
" return self.cout + self.heuristique < other.cout + other.heuristique\n",
|
||||||
|
"\n",
|
||||||
|
" def __eq__(self, other):\n",
|
||||||
|
" return self.etat == other.etat\n",
|
||||||
|
"\n",
|
||||||
|
" def __hash__(self):\n",
|
||||||
|
" return hash(tuple(self.etat))\n",
|
||||||
|
"\n",
|
||||||
|
" def __str__(self):\n",
|
||||||
|
" return str(self.etat)\n",
|
||||||
|
" \n",
|
||||||
|
"def xor_etat(etat_jeu):\n",
|
||||||
|
" xor_total = 0\n",
|
||||||
|
" for nb_objets in etat_jeu:\n",
|
||||||
|
" xor_total ^= nb_objets\n",
|
||||||
|
" return xor_total\n",
|
||||||
|
"\n",
|
||||||
|
"def heuristique(etat_jeu):\n",
|
||||||
|
" xor_valeur = xor_etat(etat_jeu)\n",
|
||||||
|
" if xor_valeur == 0:\n",
|
||||||
|
" # Position désavantageuse (perdante)\n",
|
||||||
|
" return 100 + sum(etat_jeu) # Pénalité\n",
|
||||||
|
" else:\n",
|
||||||
|
" # Position avantageuse (gagnante)\n",
|
||||||
|
" return sum(etat_jeu) # Heuristique standard\n",
|
||||||
|
"\n",
|
||||||
|
"def est_etat_final(etat):\n",
|
||||||
|
" return all(pile == 0 for pile in etat)\n",
|
||||||
|
"\n",
|
||||||
|
"def generer_successeurs(etat):\n",
|
||||||
|
" successeurs = []\n",
|
||||||
|
" for i in range(len(etat)):\n",
|
||||||
|
" if etat[i] > 0:\n",
|
||||||
|
" for j in range(1, etat[i] + 1):\n",
|
||||||
|
" nouvel_etat = etat[:]\n",
|
||||||
|
" nouvel_etat[i] -= j\n",
|
||||||
|
" successeurs.append(nouvel_etat)\n",
|
||||||
|
" return successeurs\n",
|
||||||
|
"\n",
|
||||||
|
"def algorithme_a_star(etat_initial):\n",
|
||||||
|
" noeud_initial = Noeud(etat_initial, None, 0, heuristique(etat_initial))\n",
|
||||||
|
" frontiere = []\n",
|
||||||
|
" heapq.heappush(frontiere, noeud_initial)\n",
|
||||||
|
" visites = set()\n",
|
||||||
|
"\n",
|
||||||
|
" while frontiere:\n",
|
||||||
|
" noeud_courant = heapq.heappop(frontiere)\n",
|
||||||
|
"\n",
|
||||||
|
" if est_etat_final(noeud_courant.etat):\n",
|
||||||
|
" chemin = []\n",
|
||||||
|
" while noeud_courant:\n",
|
||||||
|
" chemin.append(noeud_courant.etat)\n",
|
||||||
|
" noeud_courant = noeud_courant.parent\n",
|
||||||
|
" return chemin[::-1]\n",
|
||||||
|
"\n",
|
||||||
|
" visites.add(tuple(noeud_courant.etat))\n",
|
||||||
|
"\n",
|
||||||
|
" for successeur in generer_successeurs(noeud_courant.etat):\n",
|
||||||
|
" if tuple(successeur) not in visites:\n",
|
||||||
|
" cout = noeud_courant.cout + cout_transition(noeud_courant.etat, successeur)\n",
|
||||||
|
" heur = heuristique(successeur)\n",
|
||||||
|
" noeud_successeur = Noeud(successeur, noeud_courant, cout, heur)\n",
|
||||||
|
" heapq.heappush(frontiere, noeud_successeur)\n",
|
||||||
|
"\n",
|
||||||
|
" return None\n",
|
||||||
|
"\n",
|
||||||
|
"# Exemple d'utilisation\n",
|
||||||
|
"etat_initial = [4, 8, 5]\n",
|
||||||
|
"chemin_optimal = algorithme_a_star(etat_initial)\n",
|
||||||
|
"print(chemin_optimal)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 7 :"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"(voir cellule précédante)\n",
|
||||||
|
"\n",
|
||||||
|
"A. \n",
|
||||||
|
"- Initialisation:\n",
|
||||||
|
" - Crée un nœud initial avec l'état initial du jeu.\n",
|
||||||
|
" - Utilise une file de priorité (heap) pour gérer les nœuds à explorer.\n",
|
||||||
|
" - Utilise un ensemble (set) pour stocker les états déjà visités.\n",
|
||||||
|
"- Boucle principale:\n",
|
||||||
|
" - Tant que la file de priorité n'est pas vide, extraire le nœud avec le coût total (coût + heuristique) le plus bas.\n",
|
||||||
|
" - Si l'état du nœud courant est un état final, reconstruire et retourner le chemin depuis l'état initial jusqu'à l'état final.\n",
|
||||||
|
" - Ajouter l'état courant à l'ensemble des états visités.\n",
|
||||||
|
" - Générer les états successeurs et les ajouter à la file de priorité s'ils n'ont pas été visités.\n",
|
||||||
|
"- Retour: Si aucun chemin n'est trouvé, retourner None.\n",
|
||||||
|
"\n",
|
||||||
|
"B.\n",
|
||||||
|
"- Vérification des états visités, avant d'ajouter un successeur à la file de priorité, on vérifie si ils ont été visité.\n",
|
||||||
|
"- Une fois qu'un successeur est ajouté, il est ajouté à la file de priorité et marqué comme visité.\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 8 : "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"A. \n",
|
||||||
|
"Une représentation de son parent est crée dans la classe noeud. Lorsque qu'un successeur est crée, le noeud courant est défini comme parent\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 19,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"[[3, 4, 5], [3, 4, 4], [3, 4, 0]]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"# B.\n",
|
||||||
|
"\n",
|
||||||
|
"def reconstruire_chemin(noeud_final):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Reconstruit la séquence de mouvements depuis l’état initial jusqu’à l’état final.\n",
|
||||||
|
" \n",
|
||||||
|
" :param noeud_final: Le nœud final de l'algorithme A*.\n",
|
||||||
|
" :return: Une liste des états représentant le chemin de l'état initial à l'état final.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" chemin = []\n",
|
||||||
|
" noeud_courant = noeud_final\n",
|
||||||
|
" while noeud_courant:\n",
|
||||||
|
" chemin.append(noeud_courant.etat)\n",
|
||||||
|
" noeud_courant = noeud_courant.parent\n",
|
||||||
|
" return chemin[::-1]\n",
|
||||||
|
"\n",
|
||||||
|
"# Création d'un chemin d'exemple pour tester la fonction\n",
|
||||||
|
"etat_initial = [3, 4, 5]\n",
|
||||||
|
"etat_intermediaire = [3, 4, 4]\n",
|
||||||
|
"etat_final = [3, 4, 0]\n",
|
||||||
|
"\n",
|
||||||
|
"noeud_final = Noeud(etat_final, Noeud(etat_intermediaire, Noeud(etat_initial, None, 0, 0), 1, 0), 2, 0)\n",
|
||||||
|
"chemin = reconstruire_chemin(noeud_final)\n",
|
||||||
|
"print(chemin) # Devrait retourner [[3, 4, 5], [3, 4, 4], [3, 4, 0]]\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 9 : "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 22,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"[3, 4, 5]\n",
|
||||||
|
"[3, 4, 5]\n",
|
||||||
|
"\n",
|
||||||
|
"L'IA joue...\n",
|
||||||
|
"[3, 4, 0]\n",
|
||||||
|
"[0, 4, 0]\n",
|
||||||
|
"\n",
|
||||||
|
"L'IA joue...\n",
|
||||||
|
"\n",
|
||||||
|
" L'IA a gagné !\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"def jeu_nim(etat_initial):\n",
|
||||||
|
" etat = etat_initial[:]\n",
|
||||||
|
" while not est_etat_final(etat):\n",
|
||||||
|
" afficher_etat(etat)\n",
|
||||||
|
" try:\n",
|
||||||
|
" pile = int(input(\"Entrez le numéro de la pile (1, 2, 3, ...): \")) - 1\n",
|
||||||
|
" nb_objets = int(input(\"Entrez le nombre d'objets à retirer: \"))\n",
|
||||||
|
" appliquer_mouvement(etat, pile, nb_objets)\n",
|
||||||
|
" afficher_etat(etat)\n",
|
||||||
|
" except ValueError:\n",
|
||||||
|
" print(\"Entrée invalide. Veuillez entrer des nombres entiers.\")\n",
|
||||||
|
" continue\n",
|
||||||
|
"\n",
|
||||||
|
" if est_etat_final(etat):\n",
|
||||||
|
" print(\"\\nFélicitations ! Vous avez gagné !\")\n",
|
||||||
|
" break\n",
|
||||||
|
"\n",
|
||||||
|
" # Tour de l'IA\n",
|
||||||
|
" chemin_optimal = algorithme_a_star(etat)\n",
|
||||||
|
" if chemin_optimal and len(chemin_optimal) > 1:\n",
|
||||||
|
" etat_ia = chemin_optimal[1]\n",
|
||||||
|
" print(\"\\nL'IA joue...\")\n",
|
||||||
|
" etat = etat_ia\n",
|
||||||
|
"\n",
|
||||||
|
" if est_etat_final(etat):\n",
|
||||||
|
" print(\"\\n L'IA a gagné !\")\n",
|
||||||
|
" break\n",
|
||||||
|
"\n",
|
||||||
|
"# Exemple d'utilisation\n",
|
||||||
|
"etat_initial = [3, 4, 5]\n",
|
||||||
|
"jeu_nim(etat_initial)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Exercice 10 :"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 21,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def xor_etat(etat_jeu):\n",
|
||||||
|
" xor_total = 0\n",
|
||||||
|
" for nb_objets in etat_jeu:\n",
|
||||||
|
" xor_total ^= nb_objets\n",
|
||||||
|
" return xor_total\n",
|
||||||
|
"\n",
|
||||||
|
"def heuristique_amelioree(etat_jeu):\n",
|
||||||
|
" xor_valeur = xor_etat(etat_jeu)\n",
|
||||||
|
" if xor_valeur == 0:\n",
|
||||||
|
" # Position désavantageuse (perdante)\n",
|
||||||
|
" return 100 + sum(etat_jeu) # Pénalité\n",
|
||||||
|
" else:\n",
|
||||||
|
" # Position avantageuse (gagnante)\n",
|
||||||
|
" return sum(etat_jeu) # Heuristique standard"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.10.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
197
TP01/code.py
Normal file
197
TP01/code.py
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
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)
|
Reference in New Issue
Block a user