diff --git a/README.md b/README.md new file mode 100644 index 0000000..c140b84 --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# 📘 README – Minimax pour le jeu de Nim + +## 🎯 Objectif +Ce TP a pour but d’implĂ©menter l’algorithme **Minimax** dans le jeu de **Nim** (variante Ă  1 tas oĂč l’on peut retirer 1, 2 ou 3 objets). +On dĂ©veloppe plusieurs versions de l’algorithme pour comprendre ses optimisations possibles. + +--- + +## 📂 Fichiers +Le projet contient **4 fichiers Java**, correspondant chacun Ă  une variante de Minimax : + +1. **`MinimaxSimple.java`** + - Version de base. + - Explore toutes les possibilitĂ©s jusqu’à la fin de la partie. + - Pas d’optimisation → explore parfois plus que nĂ©cessaire. + +2. **`MinimaxEarlyStop.java`** + - Optimisation par **arrĂȘt anticipĂ©** . + - Si un coup gagnant (pour Max) ou perdant (pour Min) est trouvĂ©, la recherche s’arrĂȘte immĂ©diatement. + - MĂȘme rĂ©sultat que la version simple, mais plus rapide. +```bash +boutaric@MacBook-James TP1 % time java MinimaxSimple +RĂ©sultat pour n=8 → -1 +java MinimaxSimple 0,03s user 0,03s system 49% cpu 0,136 total +``` +```bash +boutaric@MacBook-James TP1 % time java MinimaxStop +RĂ©sultat pour n=7 → 1 +java MinimaxStop 0,04s user 0,02s system 93% cpu 0,062 total +``` + + +3. **`MinimaxProfondeur.java`** + - Variante avec **profondeur maximale fixĂ©e**. + - Quand la profondeur limite est atteinte, on utilise une **fonction d’évaluation heuristique**. + - Heuristique utilisĂ©e : une position est perdante si `n % 4 == 0`, sinon gagnante. + +4. **`MinimaxMemo.java`** + - Optimisation par **mĂ©moĂŻsation**. + - Utilise deux tableaux (`memoMax` et `memoMin`) pour stocker les rĂ©sultats dĂ©jĂ  calculĂ©s. + - Évite les recalculs et accĂ©lĂšre l’algorithme pour des valeurs de `n` plus grandes. + +--- + +## ▶ ExĂ©cution +Compiler et lancer chaque fichier sĂ©parĂ©ment : + +```bash +javac MinimaxSimple.java +java MinimaxSimple +``` + +```bash +javac MinimaxEarlyStop.java +java MinimaxEarlyStop +``` + +```bash +javac MinimaxProfondeur.java +java MinimaxProfondeur +``` + +```bash +javac MinimaxMemo.java +java MinimaxMemo +``` + +Chaque programme affiche le rĂ©sultat pour une valeur donnĂ©e de `n` (taille initiale du tas). +- `+1` → Position gagnante pour Max (le joueur qui commence). +- `-1` → Position perdante pour Max. + +--- + +## 📊 Exemple de rĂ©sultats +Pour les premiĂšres positions de Nim (1 tas) : + +| n | RĂ©sultat | Commentaire | +|----|----------|-------------| +| 1 | +1 | Max peut tout prendre et gagne | +| 2 | +1 | Max peut tout prendre et gagne | +| 3 | +1 | Max peut tout prendre et gagne | +| 4 | -1 | Position perdante (Min gagne) | +| 5 | +1 | Max enlĂšve 1 → reste 4 (perdant pour Min) | +| 6 | +1 | Max enlĂšve 2 → reste 4 | +| 7 | +1 | Max enlĂšve 3 → reste 4 | +| 8 | -1 | Position perdante | +| ...| ... | ... | + +--- + +## 🧠 Conclusion +- Le **Minimax simple** permet de comprendre la logique de base. +- Le **Minimax stop** amĂ©liore la performance sans changer le rĂ©sultat. +- La **profondeur fixe + heuristique** est utile si l’arbre est trop grand. +- La **mĂ©moĂŻsation** accĂ©lĂšre Ă©normĂ©ment le calcul pour des valeurs de `n` Ă©levĂ©es. diff --git a/TP1/Minimax.java b/TP1/Minimax.java deleted file mode 100644 index aa3f45f..0000000 --- a/TP1/Minimax.java +++ /dev/null @@ -1,44 +0,0 @@ - -public class Minimax { - - public static int pire; - public static int res; - public static int meilleurRes; - - public static void main(String[] args) { - System.out.println(ExploreMin(1)); - - } - - public static int ExploreMin(int n){ - if(n <= 0) { - return -1; - } - - pire = 2; - - for (int coups = 1; coups <= 3; coups++) { - res = ExploreMax(n - coups); - if(res < pire){ - pire = res; - } - } - - return pire; - } - - public static int ExploreMax(int n){ - if(n <= 0) { - return -1; - } - - for (int coups = 1; coups <= 3; coups++) { - res = ExploreMin(n - coups); - if(res > meilleurRes){ - meilleurRes = res; - } - } - - return meilleurRes; - } -} \ No newline at end of file diff --git a/TP1/MinimaxMemo.class b/TP1/MinimaxMemo.class new file mode 100644 index 0000000..4fccfaa Binary files /dev/null and b/TP1/MinimaxMemo.class differ diff --git a/TP1/MinimaxMemo.java b/TP1/MinimaxMemo.java new file mode 100644 index 0000000..15300b2 --- /dev/null +++ b/TP1/MinimaxMemo.java @@ -0,0 +1,43 @@ +public class MinimaxMemo { + + // Minimax avec mĂ©mo (on Ă©vite de recalculer les mĂȘmes positions) + public static Integer[] memoMax; + public static Integer[] memoMin; + + public static int exploreMax(int n) { + if (n <= 0) return -1; + if (memoMax[n] != null) return memoMax[n]; + + int meilleur = Integer.MIN_VALUE; + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMin(n - coups); + meilleur = Math.max(meilleur, res); + } + + memoMax[n] = meilleur; + return meilleur; + } + + public static int exploreMin(int n) { + if (n <= 0) return +1; + if (memoMin[n] != null) return memoMin[n]; + + int pire = Integer.MAX_VALUE; + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMax(n - coups); + pire = Math.min(pire, res); + } + + memoMin[n] = pire; + return pire; + } + + public static void main(String[] args) { + int n = 25; // taille du tas initial + memoMax = new Integer[n + 1]; + memoMin = new Integer[n + 1]; + + int resultat = exploreMax(n); + System.out.println("RĂ©sultat pour n=" + n + " → " + resultat); + } +} diff --git a/TP1/MinimaxProfondeur.class b/TP1/MinimaxProfondeur.class new file mode 100644 index 0000000..c7e77c8 Binary files /dev/null and b/TP1/MinimaxProfondeur.class differ diff --git a/TP1/MinimaxProfondeur.java b/TP1/MinimaxProfondeur.java new file mode 100644 index 0000000..a37790e --- /dev/null +++ b/TP1/MinimaxProfondeur.java @@ -0,0 +1,41 @@ +public class MinimaxProfondeur { + + // Minimax avec profondeur fixe + public static int PROFONDEUR_MAX = 4; + + public static int exploreMax(int n, int profondeur) { + if (n <= 0) return -1; + if (profondeur == 0) return evaluer(n); + + int meilleur = Integer.MIN_VALUE; + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMin(n - coups, profondeur - 1); + meilleur = Math.max(meilleur, res); + } + return meilleur; + } + + public static int exploreMin(int n, int profondeur) { + if (n <= 0) return +1; + if (profondeur == 0) return evaluer(n); + + int pire = Integer.MAX_VALUE; + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMax(n - coups, profondeur - 1); + pire = Math.min(pire, res); + } + return pire; + } + + // Fonction hsimple : perdant si n % 4 == 0 + public static int evaluer(int n) { + return (n % 4 == 0) ? -1 : +1; + } + + public static void main(String[] args) { + int n = 8; + int profondeur = PROFONDEUR_MAX; + int resultat = exploreMax(n, profondeur); + System.out.println("RĂ©sultat (profondeur fixe) pour n=" + n + " → " + resultat); + } +} diff --git a/TP1/MinimaxSimple.class b/TP1/MinimaxSimple.class new file mode 100644 index 0000000..d9a4f18 Binary files /dev/null and b/TP1/MinimaxSimple.class differ diff --git a/TP1/MinimaxSimple.java b/TP1/MinimaxSimple.java new file mode 100644 index 0000000..440855e --- /dev/null +++ b/TP1/MinimaxSimple.java @@ -0,0 +1,33 @@ +public class MinimaxSimple { + + // Max = moi, Min = adversaire + // Retourne +1 si Max gagne, -1 si Max perd + + public static int exploreMax(int n) { + if (n <= 0) return -1; // dĂ©faite pour Max + int meilleur = Integer.MIN_VALUE; + + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMin(n - coups); + meilleur = Math.max(meilleur, res); + } + return meilleur; + } + + public static int exploreMin(int n) { + if (n <= 0) return +1; // victoire pour Max + int pire = Integer.MAX_VALUE; + + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMax(n - coups); + pire = Math.min(pire, res); + } + return pire; + } + + public static void main(String[] args) { + int n = 8; // tas initial + int resultat = exploreMax(n); + System.out.println("RĂ©sultat pour n=" + n + " → " + resultat); + } +} diff --git a/TP1/MinimaxStop.class b/TP1/MinimaxStop.class new file mode 100644 index 0000000..fb7d9c3 Binary files /dev/null and b/TP1/MinimaxStop.class differ diff --git a/TP1/MinimaxStop.java b/TP1/MinimaxStop.java new file mode 100644 index 0000000..29a4acd --- /dev/null +++ b/TP1/MinimaxStop.java @@ -0,0 +1,34 @@ +public class MinimaxStop { + + // Minimax avec dĂ©tection de victoire immĂ©diate + + public static int exploreMax(int n) { + if (n <= 0) return -1; + int meilleur = Integer.MIN_VALUE; + + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMin(n - coups); + if (res == +1) return +1; // victoire immĂ©diate + meilleur = Math.max(meilleur, res); + } + return meilleur; + } + + public static int exploreMin(int n) { + if (n <= 0) return +1; + int pire = Integer.MAX_VALUE; + + for (int coups = 1; coups <= 3; coups++) { + int res = exploreMax(n - coups); + if (res == -1) return -1; // dĂ©faite immĂ©diate pour Max + pire = Math.min(pire, res); + } + return pire; + } + + public static void main(String[] args) { + int n = 7; + int resultat = exploreMax(n); + System.out.println("RĂ©sultat pour n=" + n + " → " + resultat); + } +}