diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..20f033c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..a5c2172 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/BUT3JeuR5.5.iml b/BUT3JeuR5.5.iml new file mode 100644 index 0000000..b107a2d --- /dev/null +++ b/BUT3JeuR5.5.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/MiniMax.class b/MiniMax.class new file mode 100644 index 0000000..2e46e50 Binary files /dev/null and b/MiniMax.class differ diff --git a/MiniMax.java b/MiniMax.java index 085aef6..267cf01 100644 --- a/MiniMax.java +++ b/MiniMax.java @@ -1,52 +1,95 @@ + public class MiniMax { - /* - Variable donnant le nombre d'allumettes au départ du jeu - */ - public static int depart = 5; + // J'aime bien les majuscules + public static boolean True = true; + public static boolean False = false; + + /* + Variable donnant le nombre d'allumettes au départ du jeu (remplacée par un argument en ligne de commande) + */ + public static int depart = 9099; + + private static int[] J1; + private static int[] J2; + + private static int compteur; + private static int limite; public static void main(String[] args) { - System.out.println(Nim(depart)); + limite = depart; + compteur = 0; + //int n = depart; + J1 = new int[limite + 1]; + J2 = new int[limite + 1]; + int s = Nim(limite); + System.out.print(limite+" "); + if (s == 1){ + System.out.print("Gagné"); + } else { + System.out.print("Perdu"); + } + System.out.println(" Compteur = "+compteur); + /* + System.out.println("J1 : "); + for (int nb: J1) { + System.out.print(nb+" ; "); + } + System.out.println(); + System.out.println("J2 : "); + for (int nb: J2) { + System.out.print(nb+" ; "); + */ } - - /* - Fonction de démarrage du jeu, donner un nombre d'allumettes de démarrage - */ public static int Nim(int n){ return exploreMax(n); } /* Vérifie les issues des coups jouables par le J1 et renvoie 1 si le J1 a une opportunité de gagner a coup sur + Vérifie si le coup a déjà été joué avant de continuer l'arbre, si il verifie l'arbre il ajoute au tableau */ public static int exploreMax(int allumette) { - + compteur++; + if (J1[allumette] != 0){ + return J1[allumette]; + } + int n = allumette; + int max = -1; for (int i=0;allumette>1&&i<3;i++){ allumette--; int v=exploreMin(allumette); - if (v==1){ - return v; + if (v > max){ + max = v; } - } - return -1; + J1[n] = max; + return max; } /* Vérifie les issues possibles des coups du J2 et renvoie -1 si le J2 a une opportunité de gagner a coup sur + Vérifie si le coup a déjà été joué avant de continuer l'arbre, si il verifie l'arbre il ajoute au tableau */ public static int exploreMin(int allumette){ + compteur++; + if (J2[allumette] != 0){ + return J2[allumette]; + } + int n = allumette; + int min = 1; for (int i=0;allumette>1&&i<3;i++){ allumette--; int v=exploreMax(allumette); - if (v==-1){ - return v; + if (v < min){ + min = v; } } - return 1; + J2[n] = min; + return min; } } \ No newline at end of file diff --git a/MiniMaxOptiCarnet.class b/MiniMaxOptiCarnet.class new file mode 100644 index 0000000..16b3d37 Binary files /dev/null and b/MiniMaxOptiCarnet.class differ diff --git a/MiniMaxOptiCarnet.java b/MiniMaxOptiCarnet.java new file mode 100644 index 0000000..fba817e --- /dev/null +++ b/MiniMaxOptiCarnet.java @@ -0,0 +1,104 @@ + +public class MiniMaxOptiCarnet { + + + // J'aime bien les majuscules + public static boolean True = true; + public static boolean False = false; + + /* + Variable donnant le nombre d'allumettes au départ du jeu (remplacée par un argument en ligne de commande) + */ + public static int depart = 10000; + + private static int[] J1; + private static int[] J2; + + private static int compteur; + private static int limite; + + public static void main(String[] args) { + limite = 0; + try { + while (true) { + limite++; + compteur = 0; + //int n = depart; + J1 = new int[limite + 1]; + J2 = new int[limite + 1]; + int s = Nim(limite); + System.out.print(limite+" "); + if (s == 1){ + System.out.print("Gagné"); + } else { + System.out.print("Perdu"); + } + + System.out.println(" Compteur = "+compteur); + + /* + System.out.println("J1 : "); + for (int nb: J1) { + System.out.print(nb+" ; "); + } + System.out.println(); + System.out.println("J2 : "); + for (int nb: J2) { + System.out.print(nb+" ; "); + */ + } + } catch (StackOverflowError e){ + } + System.out.println(limite-1); + } + + public static int Nim(int n){ + return exploreMax(n); + } + + /* + Vérifie les issues des coups jouables par le J1 et renvoie 1 si le J1 a une opportunité de gagner a coup sur + Vérifie si le coup a déjà été joué avant de continuer l'arbre, si il verifie l'arbre il ajoute au tableau + */ + public static int exploreMax(int allumette) { + compteur++; + if (J1[allumette] != 0){ + return J1[allumette]; + } + int n = allumette; + int max = -1; + for (int i=0;allumette>1&&i<3;i++){ + allumette--; + int v=exploreMin(allumette); + if (v > max){ + max = v; + } + } + J1[n] = max; + return max; + } + + + /* + Vérifie les issues possibles des coups du J2 et renvoie -1 si le J2 a une opportunité de gagner a coup sur + Vérifie si le coup a déjà été joué avant de continuer l'arbre, si il verifie l'arbre il ajoute au tableau + */ + public static int exploreMin(int allumette){ + compteur++; + if (J2[allumette] != 0){ + return J2[allumette]; + } + int n = allumette; + int min = 1; + for (int i=0;allumette>1&&i<3;i++){ + allumette--; + int v=exploreMax(allumette); + if (v < min){ + min = v; + } + } + J2[n] = min; + return min; + } + +} \ No newline at end of file diff --git a/MiniMaxPetiteOpti.java b/MiniMaxPetiteOpti.java new file mode 100644 index 0000000..2d0cf9c --- /dev/null +++ b/MiniMaxPetiteOpti.java @@ -0,0 +1,22 @@ +public class MiniMaxPetiteOpti { + + public static int depart = 5; + + private static int compteur; + + public static void main(String[] args) { + int n = depart; + compteur = 0; + int s = Nim(n); + if (s == 1){ + System.out.print("Gagné"); + } else { + System.out.print("Perdu"); + } + System.out.println(" Compteur = "+compteur); + } + + public static int Nim(int n){ + return exploreMax(n); + } +} diff --git a/README.md b/README.md index 6e7c0e4..33c7cf1 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,14 @@ Utilisation de deux fonctions récursives pour dire si le premier joueur peut ga ExplorationMax -> Tour du joueur 1, vérifie si il a un coup permettant de gagner à coup sûr ExplorationMin -> Tour du joueur 2, vérifie si le joueur 2 perd à coup sûr -Optimisations faites : Si le joueur 1 possède un coup permettant de gagner à coup sûr, la fonction remontera directement pour finir la fonction. \ No newline at end of file +Optimisations faites : Si le joueur 1 possède un coup permettant de gagner à coup sûr, la fonction remontera directement pour finir la fonction. + +## Optimisation en utilisant le systeme de cahier (MiniMaxOptiCarnet.java) + +Cette optimisation utilise le système de carnet demandé afin de vérifier qu'une seule fois chaque situation. +Ainsi, l'algorithme vérifie a chaque fois exactement n*6-17 noeuds, n étant le nombre d'allumettes au démarrage du jeu. +Le carnet existe sous la forme de deux tableaux d'entiers, un par joueur. Chaque joueur à n-1 situations car le Joueur 1 ne peut pas se retrouver avec n-1 allumette et le Joueur 2 ne peut pas avoir n allumettes +La limite du nombre d'allumettes est de 33736 (testé grace au bloc try/catch lançant en batch). Cependant lorsque le programme est lancé avec une valeur simple, la limite est beaucoup plus basse, étant à 9099 (sur ma machine). +Cette limite est causée par la limite de récursivité de Java, causant une StackOverflowError. + + diff --git a/out/production/BUT3JeuR5.5/.idea/.gitignore b/out/production/BUT3JeuR5.5/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/out/production/BUT3JeuR5.5/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/out/production/BUT3JeuR5.5/.idea/misc.xml b/out/production/BUT3JeuR5.5/.idea/misc.xml new file mode 100644 index 0000000..20f033c --- /dev/null +++ b/out/production/BUT3JeuR5.5/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/out/production/BUT3JeuR5.5/.idea/modules.xml b/out/production/BUT3JeuR5.5/.idea/modules.xml new file mode 100644 index 0000000..a5c2172 --- /dev/null +++ b/out/production/BUT3JeuR5.5/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/out/production/BUT3JeuR5.5/.idea/vcs.xml b/out/production/BUT3JeuR5.5/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/out/production/BUT3JeuR5.5/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/out/production/BUT3JeuR5.5/BUT3JeuR5.5.iml b/out/production/BUT3JeuR5.5/BUT3JeuR5.5.iml new file mode 100644 index 0000000..b107a2d --- /dev/null +++ b/out/production/BUT3JeuR5.5/BUT3JeuR5.5.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/BUT3JeuR5.5/MiniMax.class b/out/production/BUT3JeuR5.5/MiniMax.class new file mode 100644 index 0000000..a09c877 Binary files /dev/null and b/out/production/BUT3JeuR5.5/MiniMax.class differ diff --git a/out/production/BUT3JeuR5.5/MiniMaxOptiCarnet.class b/out/production/BUT3JeuR5.5/MiniMaxOptiCarnet.class new file mode 100644 index 0000000..337a8cc Binary files /dev/null and b/out/production/BUT3JeuR5.5/MiniMaxOptiCarnet.class differ diff --git a/out/production/BUT3JeuR5.5/README.md b/out/production/BUT3JeuR5.5/README.md new file mode 100644 index 0000000..77ad854 --- /dev/null +++ b/out/production/BUT3JeuR5.5/README.md @@ -0,0 +1,21 @@ +# BUT3JeuR5.5 + +## Jeu de Nim : MiniMax + +Utilisation de deux fonctions récursives pour dire si le premier joueur peut gagner à coup sûr au jeu de Nim ++1 = J1 peut Gagner à coup sur +-1 = J1 peut perdre à coup sur + +ExplorationMax -> Tour du joueur 1, vérifie si il a un coup permettant de gagner à coup sûr +ExplorationMin -> Tour du joueur 2, vérifie si le joueur 2 perd à coup sûr + +Optimisations faites : Si le joueur 1 possède un coup permettant de gagner à coup sûr, la fonction remontera directement pour finir la fonction. + +## Optimisation en utilisant le systeme de cahier (MiniMaxOptiCarnet.java) + +Cette optimisation utilise le système de carnet demandé afin de vérifier qu'une seule fois chaque situation. +Ainsi, l'algorithme vérifie a chaque fois exactement n*6-17 noeuds, n étant le nombre d'allumettes au démarrage du jeu. +Le carnet existe sous la forme de deux tableaux d'entiers, un par joueur. Chaque joueur à n-1 situations car le Joueur 1 ne peut pas se retrouver avec n-1 allumette et le Joueur 2 ne peut pas avoir n allumettes +La limite du nombre d'allumettes est de 33736 (testé grace au bloc try/catch lançant en batch). Cependant lorsque le programme est lancé avec une valeur simple, la limite est beaucoup plus basse, + +