diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..e0292d2 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md deleted file mode 100644 index c140b84..0000000 --- a/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# 📘 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&TP2/MIniMax_versionprofondeur.class b/TP1&TP2/MIniMax_versionprofondeur.class new file mode 100644 index 0000000..5b0c863 Binary files /dev/null and b/TP1&TP2/MIniMax_versionprofondeur.class differ diff --git a/TP1&TP2/MIniMax_versionprofondeur.java b/TP1&TP2/MIniMax_versionprofondeur.java new file mode 100644 index 0000000..183fa16 --- /dev/null +++ b/TP1&TP2/MIniMax_versionprofondeur.java @@ -0,0 +1,42 @@ +public class MIniMax_versionprofondeur { + + private static int ExploreMax(int nbr_allumettes, int profondeur){ + if (nbr_allumettes <= 0){ + return 1; + } + if (profondeur == 0){ + return 0; + } + int meilleurres = -2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMin(nbr_allumettes - coup, profondeur - coup); + if (res > meilleurres){ + meilleurres = res; + } + } + return meilleurres; + } + + private static int ExploreMin(int nbr_allumettes, int profondeur){ + if (nbr_allumettes <= 0){ + return -1; + } + if (profondeur == 0){ + return 0; + } + int pire = 2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup, profondeur - coup); + if (res < pire){ + pire = res; + } + } + return pire; + } + + public static void main(String[] args) { + int nbr_allumettes = 5; + int profondeur = 6; + System.out.println(ExploreMax(nbr_allumettes, profondeur)); + } +} \ No newline at end of file diff --git a/TP1&TP2/MiniMax_versionBase.class b/TP1&TP2/MiniMax_versionBase.class new file mode 100644 index 0000000..55774f0 Binary files /dev/null and b/TP1&TP2/MiniMax_versionBase.class differ diff --git a/TP1&TP2/MiniMax_versionBase.java b/TP1&TP2/MiniMax_versionBase.java new file mode 100644 index 0000000..557c71c --- /dev/null +++ b/TP1&TP2/MiniMax_versionBase.java @@ -0,0 +1,35 @@ +public class MiniMax_versionBase { + + private static int ExploreMax(int nbr_allumettes){ + if (nbr_allumettes <= 0){ + return 1; + } + int meilleurres = -2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMin(nbr_allumettes - coup); + if (res > meilleurres){ + meilleurres = res; + } + } + return meilleurres; + } + + private static int ExploreMin(int nbr_allumettes){ + if (nbr_allumettes <= 0){ + return -1; + } + int pire = 2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup); + if (res < pire){ + pire = res; + } + } + return pire; + } + + public static void main(String[] args) { + int nbr_allumettes = 5; + System.out.println(ExploreMax(nbr_allumettes)); + } +} \ No newline at end of file diff --git a/TP1&TP2/MiniMax_versionMemoisation.class b/TP1&TP2/MiniMax_versionMemoisation.class new file mode 100644 index 0000000..465314f Binary files /dev/null and b/TP1&TP2/MiniMax_versionMemoisation.class differ diff --git a/TP1&TP2/MiniMax_versionMemoisation.java b/TP1&TP2/MiniMax_versionMemoisation.java new file mode 100644 index 0000000..660b45b --- /dev/null +++ b/TP1&TP2/MiniMax_versionMemoisation.java @@ -0,0 +1,59 @@ +import java.util.ArrayList; +public class MiniMax_versionMemoisation{ + + private static ArrayList max = new ArrayList(); + private static ArrayList min = new ArrayList(); + private static int Allumete; + + public MiniMax_versionMemoisation(int n){ + Allumete = n; + for(int i=0;i localAlpha){ + localAlpha = res; + if (localAlpha >= beta){ + return localAlpha; + } + } + } + return localAlpha; + } + + private static int ExploreMin(int nbr_allumettes, int alpha, int beta){ + if (nbr_allumettes <= 0){ + return -1; + } + int localBeta = beta; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup, alpha, localBeta); + if (res < localBeta){ + localBeta = res; + if (localBeta <= alpha){ + return localBeta; + } + } + } + return localBeta; + } + + public static void main(String[] args) { + int nbr_allumettes = 5; + System.out.println(ExploreMax(nbr_allumettes, Integer.MIN_VALUE, Integer.MAX_VALUE)); + } +} \ No newline at end of file diff --git a/TP1&TP2/MiniMax_versionarret.class b/TP1&TP2/MiniMax_versionarret.class new file mode 100644 index 0000000..02949c3 Binary files /dev/null and b/TP1&TP2/MiniMax_versionarret.class differ diff --git a/TP1&TP2/MiniMax_versionarret.java b/TP1&TP2/MiniMax_versionarret.java new file mode 100644 index 0000000..2cdbe0d --- /dev/null +++ b/TP1&TP2/MiniMax_versionarret.java @@ -0,0 +1,41 @@ +public class MiniMax_versionarret { + + private static int ExploreMax(int nbr_allumettes){ + if (nbr_allumettes <= 0){ + return 1; + } + int meilleurres = -2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMin(nbr_allumettes - coup); + if (res > meilleurres){ + meilleurres = res; + if (meilleurres == 1){ + break; + } + } + } + return meilleurres; + } + + private static int ExploreMin(int nbr_allumettes){ + if (nbr_allumettes <= 0){ + return -1; + } + int pire = 2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup); + if (res < pire){ + pire = res; + if (pire == -1){ + break; + } + } + } + return pire; + } + + public static void main(String[] args) { + int nbr_allumettes = 4; + System.out.println(ExploreMax(nbr_allumettes)); + } +} \ No newline at end of file diff --git a/TP1&TP2/Readme.md b/TP1&TP2/Readme.md new file mode 100644 index 0000000..ea6ef96 --- /dev/null +++ b/TP1&TP2/Readme.md @@ -0,0 +1,97 @@ +Ce fichier repertorie et explique les code qui se trouve dans ce fichier. + +## MiniMax_versionBase + +Ce code est la version de base vu en cours du jeu de Nim. +Il fonctionne et donne bien -1 en resultat. + +# Tableau d'Ă©tats visitĂ© + +| n (allumettes) | Nombre de nƓuds explorĂ©s | +|----------------|--------------------------| +| 5 | 46 | +| 7 | 157 | +| 13 | 6 094 | +| 19 | 235 957 | +| 31 | 353 693 521 | + + + +## MiniMax_versionprofondeur + +Ce code est une version optimisĂ© de la version vu en cours du jeu de Nim. +Celui-ci a un autre paramĂštre qui est profoncdeur qui limite les calcul et donne une approximation. +Il fonctionne et donne bien 0 en resultat si la profonceur est infĂ©rieur Ă  6 et si elle est de 6 ou plus elle donne bien -1 car 6 est la profondeur maximal de l'abre du jeu de Nim. + +# Tableau d'Ă©tats visitĂ© + +| Nombre d’allumettes | Profondeur max | Nombre de nƓuds (Ă©tats) | +|---------------------|----------------|-------------------------| +| 5 | 6 | 46 | +| 7 | 8 | 157 | +| 13 | 14 | 6 094 | +| 19 | 20 | 235 957 | +| 31 | 32 | 353 693 521 | + + + +## MiniMax_versionarret + +Ce code est une version optimisĂ© de la version vu en cours du jeu de Nim. +Celui-ci a une autre condition d'arret qui limite les calcul qui est donnĂ© par un chemin oĂč il y a une victiore ou une dĂ©faite. +Il fonctionne et donne bien -1 en resultat si le nombre d'allumettes est de 5 et si elle est de 4, elle donne bien 1. + +# Tableau d'Ă©tats visitĂ© + +| Nombre d’allumettes | NƓuds visitĂ©s | +|---------------------:|-------------:| +| 5 | 36 | +| 7 | 74 | +| 13 | 1 828 | +| 19 | 25 610 | +| 31 | 8 784 458 | + + +## MiniMax_versionMemoisation +Ce code est une version optimisĂ© de la version vu en cours du jeu de Nim. +Celui-ci garde en mĂ©moire avec un tableau pour le min et le max pour Ă©viter de recalculer des sous-arbres dĂ©jĂ  vu prĂ©cĂ©demment. +Il fonctionne avec les tests effectuĂ©. + +# Tableau d'Ă©tats visitĂ© + +| Nombre d’allumettes | NƓuds distincts (Ă©tats) visitĂ©s | +|---------------------:|-------------------------------:| +| 5 | 25 | +| 7 | 37 | +| 13 | 73 | +| 19 | 109 | +| 31 | 181 | + + +## MiniMax_version_AlphaBeta +Ce code est une version optimisĂ© de la version vu en cours du jeu de Nim. +Celui-ci permet de coupĂ© des partie de l'arbre de jeux, donc de visitĂ© moins de noeuds. +Il fonctionne avec les tests effectuĂ©. + +# Tableau d'Ă©tats visitĂ© + +| Nombre d’allumettes | NƓuds visitĂ©s | +|--------------------:|--------------:| +| 5 | 41 | +| 7 | 107 | +| 13 | 2 244 | +| 19 | 31 898 | +| 31 | 9 523 124 | + +## DiffĂ©rence de noeud visitĂ© entre MiniMax_version_AlphaBeta et MiniMax_versionBase +La diffĂ©rence entre le nombre de noeuds visitĂ© car alpha_beta ne regarde pas tous les sous-arbres, contrairement Ă  la version de base, cela se voit surtout avec une grande longueur de l'arbre de jeux. + +## Nombre d'Ă©tats visitĂ©s dans chaque version + +| Version | ParamĂštres initiaux | États explorĂ©s | +|--------------------------------|-----------------------------------|----------------| +| MiniMax_versionBase | `nbr_allumettes = 5` | 46 | +| MiniMax_versionarret | `nbr_allumettes = 5` | 36 | +| MiniMax_versionprofondeur | `nbr_allumettes = 5, profondeur=6`| 46 | +| MiniMax_versionMemoisation | `nbr_allumettes = 5` | 25 | +| MiniMax_version_AlphaBeta | `nbr_allumettes = 5` | 41 | \ No newline at end of file diff --git a/TP1&TP2/compteur/MIniMax_versionprofondeur_compteur.class b/TP1&TP2/compteur/MIniMax_versionprofondeur_compteur.class new file mode 100644 index 0000000..247b241 Binary files /dev/null and b/TP1&TP2/compteur/MIniMax_versionprofondeur_compteur.class differ diff --git a/TP1&TP2/compteur/MIniMax_versionprofondeur_compteur.java b/TP1&TP2/compteur/MIniMax_versionprofondeur_compteur.java new file mode 100644 index 0000000..aef6209 --- /dev/null +++ b/TP1&TP2/compteur/MIniMax_versionprofondeur_compteur.java @@ -0,0 +1,47 @@ +public class MIniMax_versionprofondeur_compteur { + + public static int compteur_noeud = 0; + + private static int ExploreMax(int nbr_allumettes, int profondeur){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return 1; + } + if (profondeur == 0){ + return 0; + } + int meilleurres = -2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMin(nbr_allumettes - coup, profondeur - coup); + if (res > meilleurres){ + meilleurres = res; + } + } + return meilleurres; + } + + private static int ExploreMin(int nbr_allumettes, int profondeur){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return -1; + } + if (profondeur == 0){ + return 0; + } + int pire = 2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup, profondeur - coup); + if (res < pire){ + pire = res; + } + } + return pire; + } + + public static void main(String[] args) { + int nbr_allumettes = 5; + int profondeur = 6; + System.out.println(ExploreMax(nbr_allumettes, profondeur)); + System.out.println(compteur_noeud); + } +} \ No newline at end of file diff --git a/TP1&TP2/compteur/MiniMax_versionBase_compteur.class b/TP1&TP2/compteur/MiniMax_versionBase_compteur.class new file mode 100644 index 0000000..c0805ee Binary files /dev/null and b/TP1&TP2/compteur/MiniMax_versionBase_compteur.class differ diff --git a/TP1&TP2/compteur/MiniMax_versionBase_compteur.java b/TP1&TP2/compteur/MiniMax_versionBase_compteur.java new file mode 100644 index 0000000..fd0b423 --- /dev/null +++ b/TP1&TP2/compteur/MiniMax_versionBase_compteur.java @@ -0,0 +1,40 @@ +public class MiniMax_versionBase_compteur { + + public static int compteur_noeud = 0; + + private static int ExploreMax(int nbr_allumettes){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return 1; + } + int meilleurres = -2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMin(nbr_allumettes - coup); + if (res > meilleurres){ + meilleurres = res; + } + } + return meilleurres; + } + + private static int ExploreMin(int nbr_allumettes){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return -1; + } + int pire = 2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup); + if (res < pire){ + pire = res; + } + } + return pire; + } + + public static void main(String[] args) { + int nbr_allumettes = 19; + System.out.println(ExploreMax(nbr_allumettes)); + System.out.println(compteur_noeud); + } +} \ No newline at end of file diff --git a/TP1&TP2/compteur/MiniMax_versionMemoisation_compteur.class b/TP1&TP2/compteur/MiniMax_versionMemoisation_compteur.class new file mode 100644 index 0000000..e3c0354 Binary files /dev/null and b/TP1&TP2/compteur/MiniMax_versionMemoisation_compteur.class differ diff --git a/TP1&TP2/compteur/MiniMax_versionMemoisation_compteur.java b/TP1&TP2/compteur/MiniMax_versionMemoisation_compteur.java new file mode 100644 index 0000000..d83ab15 --- /dev/null +++ b/TP1&TP2/compteur/MiniMax_versionMemoisation_compteur.java @@ -0,0 +1,63 @@ +import java.util.ArrayList; +public class MiniMax_versionMemoisation_compteur{ + + private static ArrayList max = new ArrayList(); + private static ArrayList min = new ArrayList(); + private static int Allumete; + public static int compteur_noeud = 0; + + public MiniMax_versionMemoisation_compteur(int n){ + Allumete = n; + for(int i=0;i localAlpha){ + localAlpha = res; + if (localAlpha >= beta){ + return localAlpha; + } + } + } + return localAlpha; + } + + private static int ExploreMin(int nbr_allumettes, int alpha, int beta){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return -1; + } + int localBeta = beta; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup, alpha, localBeta); + if (res < localBeta){ + localBeta = res; + if (localBeta <= alpha){ + return localBeta; + } + } + } + return localBeta; + } + + public static void main(String[] args) { + int nbr_allumettes = 31; + System.out.println(ExploreMax(nbr_allumettes, Integer.MIN_VALUE, Integer.MAX_VALUE)); + System.out.println(compteur_noeud); + } +} \ No newline at end of file diff --git a/TP1&TP2/compteur/MiniMax_versionarret_compteur.class b/TP1&TP2/compteur/MiniMax_versionarret_compteur.class new file mode 100644 index 0000000..8eb9c86 Binary files /dev/null and b/TP1&TP2/compteur/MiniMax_versionarret_compteur.class differ diff --git a/TP1&TP2/compteur/MiniMax_versionarret_compteur.java b/TP1&TP2/compteur/MiniMax_versionarret_compteur.java new file mode 100644 index 0000000..fe3475c --- /dev/null +++ b/TP1&TP2/compteur/MiniMax_versionarret_compteur.java @@ -0,0 +1,46 @@ +public class MiniMax_versionarret_compteur { + + public static int compteur_noeud = 0; + + private static int ExploreMax(int nbr_allumettes){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return 1; + } + int meilleurres = -2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMin(nbr_allumettes - coup); + if (res > meilleurres){ + meilleurres = res; + if (meilleurres == 1){ + break; + } + } + } + return meilleurres; + } + + private static int ExploreMin(int nbr_allumettes){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return -1; + } + int pire = 2; + for (int coup = 1; coup <= 3; coup++){ + int res = ExploreMax(nbr_allumettes - coup); + if (res < pire){ + pire = res; + if (pire == -1){ + break; + } + } + } + return pire; + } + + public static void main(String[] args) { + int nbr_allumettes = 19; + System.out.println(ExploreMax(nbr_allumettes)); + System.out.println(compteur_noeud); + } +} \ No newline at end of file diff --git a/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange.class b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange.class new file mode 100644 index 0000000..abd250b Binary files /dev/null and b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange.class differ diff --git a/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange.java b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange.java new file mode 100644 index 0000000..3a8ec04 --- /dev/null +++ b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange.java @@ -0,0 +1,50 @@ +import java.util.ArrayList; +import java.util.Collections; + +public class MiniMax_version_AlphaBeta_melange { + private static ArrayList list = new ArrayList(); + + private static int ExploreMax(int nbr_allumettes, int alpha, int beta){ + if (nbr_allumettes <= 0){ + return 1; + } + int localAlpha = alpha; + for (Integer coup : list){ + int res = ExploreMin(nbr_allumettes - coup, localAlpha, beta); + if (res > localAlpha){ + localAlpha = res; + if (localAlpha >= beta){ + return localAlpha; + } + } + } + return localAlpha; + } + + private static int ExploreMin(int nbr_allumettes, int alpha, int beta){ + if (nbr_allumettes <= 0){ + return -1; + } + int localBeta = beta; + for (Integer coup : list){ + int res = ExploreMax(nbr_allumettes - coup, alpha, localBeta); + if (res < localBeta){ + localBeta = res; + if (localBeta <= alpha){ + return localBeta; + } + } + } + return localBeta; + } + + public static void main(String[] args) { + list.add(1); + list.add(2); + list.add(3); + Collections.shuffle(list); + int nbr_allumettes = 5; + System.out.println(list); + System.out.println(ExploreMax(nbr_allumettes, Integer.MIN_VALUE, Integer.MAX_VALUE)); + } +} \ No newline at end of file diff --git a/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange_compteur.class b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange_compteur.class new file mode 100644 index 0000000..9d417c7 Binary files /dev/null and b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange_compteur.class differ diff --git a/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange_compteur.java b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange_compteur.java new file mode 100644 index 0000000..c0e65f0 --- /dev/null +++ b/TP1&TP2/version_liste_melange/MiniMax_version_AlphaBeta_melange_compteur.java @@ -0,0 +1,54 @@ +import java.util.ArrayList; +import java.util.Collections; + +public class MiniMax_version_AlphaBeta_melange_compteur { + private static ArrayList list = new ArrayList(); + public static int compteur_noeud = 0; + + private static int ExploreMax(int nbr_allumettes, int alpha, int beta){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return 1; + } + int localAlpha = alpha; + for (Integer coup : list){ + int res = ExploreMin(nbr_allumettes - coup, localAlpha, beta); + if (res > localAlpha){ + localAlpha = res; + if (localAlpha >= beta){ + return localAlpha; + } + } + } + return localAlpha; + } + + private static int ExploreMin(int nbr_allumettes, int alpha, int beta){ + compteur_noeud++; + if (nbr_allumettes <= 0){ + return -1; + } + int localBeta = beta; + for (Integer coup : list){ + int res = ExploreMax(nbr_allumettes - coup, alpha, localBeta); + if (res < localBeta){ + localBeta = res; + if (localBeta <= alpha){ + return localBeta; + } + } + } + return localBeta; + } + + public static void main(String[] args) { + list.add(1); + list.add(2); + list.add(3); + Collections.shuffle(list); + int nbr_allumettes = 5; + System.out.println(list); + System.out.println(ExploreMax(nbr_allumettes, Integer.MIN_VALUE, Integer.MAX_VALUE)); + System.out.println(compteur_noeud); + } +} \ No newline at end of file diff --git a/TP1/Minimax.class b/TP1/Minimax.class deleted file mode 100644 index 7c27f83..0000000 Binary files a/TP1/Minimax.class and /dev/null differ diff --git a/TP1/MinimaxAlphaBeta.java b/TP1/MinimaxAlphaBeta.java deleted file mode 100644 index adadc5c..0000000 --- a/TP1/MinimaxAlphaBeta.java +++ /dev/null @@ -1,58 +0,0 @@ -import java.util.*; - -public class MinimaxAlphaBeta { - public static int compteur = 0; // nombre d'Ă©tats visitĂ©s - public static Random random = new Random(); - - public static int exploreMax(int n, int alpha, int beta) { - compteur++; - if (n <= 0) return -1; - - int meilleur = Integer.MIN_VALUE; - - // coups possibles - List coups = Arrays.asList(1, 2, 3); - Collections.shuffle(coups, random); // ordre alĂ©atoire - - for (int c : coups) { - int res = exploreMin(n - c, alpha, beta); - meilleur = Math.max(meilleur, res); - alpha = Math.max(alpha, meilleur); - - // coupure alpha-beta - if (alpha >= beta) break; - } - return meilleur; - } - - public static int exploreMin(int n, int alpha, int beta) { - compteur++; - if (n <= 0) return +1; - - int pire = Integer.MAX_VALUE; - - // coups possibles - List coups = Arrays.asList(1, 2, 3); - Collections.shuffle(coups, random); // ordre alĂ©atoire - - for (int c : coups) { - int res = exploreMax(n - c, alpha, beta); - pire = Math.min(pire, res); - beta = Math.min(beta, pire); - - // coupure alpha-beta - if (alpha >= beta) break; - } - return pire; - } - - public static void main(String[] args) { - int[] tests = {5, 7, 13, 19, 31}; - - for (int n : tests) { - compteur = 0; - int resultat = exploreMax(n, Integer.MIN_VALUE, Integer.MAX_VALUE); - System.out.println("n=" + n + " → " + resultat + " | Ă©tats visitĂ©s=" + compteur); - } - } -} diff --git a/TP1/MinimaxMemo.class b/TP1/MinimaxMemo.class deleted file mode 100644 index 4fccfaa..0000000 Binary files a/TP1/MinimaxMemo.class and /dev/null differ diff --git a/TP1/MinimaxMemo.java b/TP1/MinimaxMemo.java deleted file mode 100644 index 15300b2..0000000 --- a/TP1/MinimaxMemo.java +++ /dev/null @@ -1,43 +0,0 @@ -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 deleted file mode 100644 index c7e77c8..0000000 Binary files a/TP1/MinimaxProfondeur.class and /dev/null differ diff --git a/TP1/MinimaxProfondeur.java b/TP1/MinimaxProfondeur.java deleted file mode 100644 index a37790e..0000000 --- a/TP1/MinimaxProfondeur.java +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index d9a4f18..0000000 Binary files a/TP1/MinimaxSimple.class and /dev/null differ diff --git a/TP1/MinimaxSimple.java b/TP1/MinimaxSimple.java deleted file mode 100644 index 440855e..0000000 --- a/TP1/MinimaxSimple.java +++ /dev/null @@ -1,33 +0,0 @@ -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 deleted file mode 100644 index fb7d9c3..0000000 Binary files a/TP1/MinimaxStop.class and /dev/null differ diff --git a/TP1/MinimaxStop.java b/TP1/MinimaxStop.java deleted file mode 100644 index 29a4acd..0000000 --- a/TP1/MinimaxStop.java +++ /dev/null @@ -1,34 +0,0 @@ -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); - } -} diff --git a/TP3/fr/iut_fbleau/GameAPI/AbstractBoard.class b/TP3/fr/iut_fbleau/GameAPI/AbstractBoard.class new file mode 100644 index 0000000..827e477 Binary files /dev/null and b/TP3/fr/iut_fbleau/GameAPI/AbstractBoard.class differ diff --git a/TP3/fr/iut_fbleau/GameAPI/AbstractBoard.java b/TP3/fr/iut_fbleau/GameAPI/AbstractBoard.java new file mode 100644 index 0000000..d606ba2 --- /dev/null +++ b/TP3/fr/iut_fbleau/GameAPI/AbstractBoard.java @@ -0,0 +1,99 @@ +package fr.iut_fbleau.GameAPI; + +import java.util.Iterator; +import java.util.Deque; + +/** + * An abstract class implementing the interface IBoard. + * + * used to implement some things to do with the update of the next player + * which is the same for all games and provides also a minimal + * implantation of the history mechanism. + */ +public abstract class AbstractBoard implements IBoard{ + + private Player currentPlayer ; + + private Deque history; + + private void setNextPlayer(){ + if (this.currentPlayer==Player.PLAYER1){ + this.currentPlayer= Player.PLAYER2; + } + else + this.currentPlayer= Player.PLAYER1; + } + + // Beware not checking if move is legal. + // To be used in do(AbstractPly c) + private void addPlyToHistory(AbstractPly c){ + this.history.addLast(c); + } + + // Beware not checking if history is not empty + // To be used in undo() + private void removePlyFromHistory(){ + this.history.removeLast(); + } + + + /** + * @return the current player + */ + public Player getcurrentPlayer(){ + return this.currentPlayer; + } + + /** + * Returns the game status + * + * @return true iff the game is over + */ + public abstract boolean isGameOver(); + + /** + * + * @return the result (null if not over) + */ + public abstract Result getResult(); + + /** + * checker of legal moves from this position + * + * @throws NullPointerException if the game is over + * @return the iterator + */ + public abstract boolean isLegal(AbstractPly c); + + + + /** + * constructor of Iterator over legal moves from this position + * + * @throws NullPointerException if the game is over + * @return the iterator + */ + public abstract Iterator iterator(); + + + + /** + * Plays a given move on the plateau. + * Should update history using + * @throws IllegalArgumentException if the move is always illegal (say from the wrong game) + * @throws IllegalStateException if the move is not legal in this position + * + * @param AbstractPly to be played + * + */ + public abstract void doPly(AbstractPly c); + + /** + * Resets the plateau to the position before the last move. + * + * @throws IllegalStateException if nothing to undo in history + * + */ + public abstract void undoPly(); + +} diff --git a/TP3/fr/iut_fbleau/GameAPI/AbstractGamePlayer.class b/TP3/fr/iut_fbleau/GameAPI/AbstractGamePlayer.class new file mode 100644 index 0000000..e914e9e Binary files /dev/null and b/TP3/fr/iut_fbleau/GameAPI/AbstractGamePlayer.class differ diff --git a/TP3/fr/iut_fbleau/GameAPI/AbstractGamePlayer.java b/TP3/fr/iut_fbleau/GameAPI/AbstractGamePlayer.java new file mode 100644 index 0000000..be251ee --- /dev/null +++ b/TP3/fr/iut_fbleau/GameAPI/AbstractGamePlayer.java @@ -0,0 +1,26 @@ +package fr.iut_fbleau.GameAPI; + +import java.util.Iterator; + +/** + * The abstract class for a game Player. + */ +public abstract class AbstractGamePlayer { + + // not a band, but which type of player I am in the game (PLAYER1 or PLAYER2). + private Player iAm; + + // Le joueur rĂ©el pourrait avoir besoin de connaĂźtre un constructeur de coup? + // pas pour l'instant. + + + /** + * + * + * @throws UnsupportedOperationException if the method is not yet implemented + * + * @throws IllegalStateException if the Situation is already in the bookmarks + */ + public abstract AbstractPly giveYourMove(IBoard p); + +} diff --git a/TP3/fr/iut_fbleau/GameAPI/AbstractPly.class b/TP3/fr/iut_fbleau/GameAPI/AbstractPly.class new file mode 100644 index 0000000..d7e2a47 Binary files /dev/null and b/TP3/fr/iut_fbleau/GameAPI/AbstractPly.class differ diff --git a/TP3/fr/iut_fbleau/GameAPI/AbstractPly.java b/TP3/fr/iut_fbleau/GameAPI/AbstractPly.java new file mode 100644 index 0000000..f831b22 --- /dev/null +++ b/TP3/fr/iut_fbleau/GameAPI/AbstractPly.java @@ -0,0 +1,5 @@ +package fr.iut_fbleau.GameAPI; + +public abstract class AbstractPly { + private Player joueur; +} diff --git a/TP3/fr/iut_fbleau/GameAPI/IBoard.class b/TP3/fr/iut_fbleau/GameAPI/IBoard.class new file mode 100644 index 0000000..5728bcd Binary files /dev/null and b/TP3/fr/iut_fbleau/GameAPI/IBoard.class differ diff --git a/TP3/fr/iut_fbleau/GameAPI/IBoard.java b/TP3/fr/iut_fbleau/GameAPI/IBoard.java new file mode 100644 index 0000000..2bf6d91 --- /dev/null +++ b/TP3/fr/iut_fbleau/GameAPI/IBoard.java @@ -0,0 +1,69 @@ +package fr.iut_fbleau.GameAPI; + +import java.util.Iterator; + +/** + * The interface Board. + */ +public interface IBoard { + + + /** + * @return the current player + */ + public Player getcurrentPlayer(); + + /** + * Returns the game status + * + * @return true iff the game is over + */ + public boolean isGameOver(); + + /** + * + * @return the result (null if not over) + */ + public Result getResult(); + + /** + * checker of legal moves from this position + * + * @throws NullPointerException if the game is over + * @return the iterator + */ + public boolean isLegal(AbstractPly c); + + + + /** + * constructor of Iterator over legal moves from this position + * + * @throws NullPointerException if the game is over + * @return the iterator + */ + public Iterator iterator(); + + + + /** + * Plays a given move on the plateau. + * Should update history using + * @throws IllegalArgumentException if the move is always illegal (say from the wrong game) + * @throws IllegalStateException if the move is not legal in this position + * + * @param AbstractPly to be played + * + */ + public void doPly(AbstractPly c); + + /** + * Resets the plateau to the position before the last move. + * + * @throws IllegalStateException if nothing to undo in history + * + */ + public void undoPly(); + + +} diff --git a/TP3/fr/iut_fbleau/GameAPI/Player.class b/TP3/fr/iut_fbleau/GameAPI/Player.class new file mode 100644 index 0000000..c659c8b Binary files /dev/null and b/TP3/fr/iut_fbleau/GameAPI/Player.class differ diff --git a/TP3/fr/iut_fbleau/GameAPI/Player.java b/TP3/fr/iut_fbleau/GameAPI/Player.java new file mode 100644 index 0000000..2831093 --- /dev/null +++ b/TP3/fr/iut_fbleau/GameAPI/Player.java @@ -0,0 +1,6 @@ +package fr.iut_fbleau.GameAPI; + +public enum Player { + PLAYER1, + PLAYER2 +} diff --git a/TP3/fr/iut_fbleau/GameAPI/Result.class b/TP3/fr/iut_fbleau/GameAPI/Result.class new file mode 100644 index 0000000..4234ba9 Binary files /dev/null and b/TP3/fr/iut_fbleau/GameAPI/Result.class differ diff --git a/TP3/fr/iut_fbleau/GameAPI/Result.java b/TP3/fr/iut_fbleau/GameAPI/Result.java new file mode 100644 index 0000000..9417e13 --- /dev/null +++ b/TP3/fr/iut_fbleau/GameAPI/Result.java @@ -0,0 +1,11 @@ +package fr.iut_fbleau.GameAPI; + +/** + * To output the result of a 2 player game that is symmetric. + * from the perspective of the player PLAYER1. + */ +public enum Result { + WIN, + DRAW, + LOSS; +} diff --git a/TP3/fr/iut_fbleau/Nim/NimBoard.class b/TP3/fr/iut_fbleau/Nim/NimBoard.class new file mode 100644 index 0000000..d690ef3 Binary files /dev/null and b/TP3/fr/iut_fbleau/Nim/NimBoard.class differ diff --git a/TP3/fr/iut_fbleau/Nim/NimBoard.java b/TP3/fr/iut_fbleau/Nim/NimBoard.java new file mode 100644 index 0000000..586adf3 --- /dev/null +++ b/TP3/fr/iut_fbleau/Nim/NimBoard.java @@ -0,0 +1,199 @@ +package fr.iut_fbleau.Nim; + +import fr.iut_fbleau.GameAPI.AbstractBoard; +import fr.iut_fbleau.GameAPI.AbstractPly; +import fr.iut_fbleau.GameAPI.Player; +import fr.iut_fbleau.GameAPI.Result; + +import java.util.Iterator; +import java.util.ArrayList; +import java.util.Deque; +import java.util.ArrayDeque; + +/** + * ReprĂ©sente le plateau du jeu de Nim. + * Le jeu de Nim se joue avec un certain nombre d'allumettes. + * Les joueurs retirent Ă  tour de rĂŽle entre 1 et maxParCoup allumettes. + * Le joueur qui retire la derniĂšre allumette perd (variante misĂšre). + */ +public class NimBoard extends AbstractBoard { + + private int allumettesRestantes; + private int maxParCoup; + private int allumettesInitiales; + private Player currentPlayer; + private Deque history; + private boolean gameOver; + private Result result; + + /** + * Constructeur du plateau de Nim + * + * @param allumettesInitiales le nombre d'allumettes au dĂ©but du jeu + * @param maxParCoup le nombre maximum d'allumettes qu'on peut retirer par coup + */ + public NimBoard(int allumettesInitiales, int maxParCoup) { + if (allumettesInitiales <= 0) { + throw new IllegalArgumentException("Le nombre d'allumettes doit ĂȘtre positif"); + } + if (maxParCoup <= 0) { + throw new IllegalArgumentException("Le nombre maximum par coup doit ĂȘtre positif"); + } + + this.allumettesInitiales = allumettesInitiales; + this.allumettesRestantes = allumettesInitiales; + this.maxParCoup = maxParCoup; + this.currentPlayer = Player.PLAYER1; + this.history = new ArrayDeque<>(); + this.gameOver = false; + this.result = null; + } + + /** + * @return le nombre d'allumettes restantes + */ + public int getAllumettesRestantes() { + return this.allumettesRestantes; + } + + /** + * @return le nombre maximum d'allumettes par coup + */ + public int getMaxParCoup() { + return this.maxParCoup; + } + + @Override + public Player getcurrentPlayer() { + return this.currentPlayer; + } + + @Override + public boolean isGameOver() { + return this.gameOver; + } + + @Override + public Result getResult() { + return this.result; + } + + @Override + public boolean isLegal(AbstractPly c) { + if (this.gameOver) { + throw new NullPointerException("Le jeu est terminĂ©"); + } + + if (!(c instanceof NimPly)) { + return false; + } + + NimPly coup = (NimPly) c; + + if (coup.getJoueur() != this.currentPlayer) { + return false; + } + + // VĂ©rifier que le nombre d'allumettes est valide + int nbAllumettes = coup.getNombreAllumettesPrises(); + return nbAllumettes >= 1 && + nbAllumettes <= this.maxParCoup && + nbAllumettes <= this.allumettesRestantes; + } + + @Override + public Iterator iterator() { + if (this.gameOver) { + throw new NullPointerException("Le jeu est terminĂ©"); + } + + ArrayList coups = new ArrayList<>(); + int maxRetirage = Math.min(this.maxParCoup, this.allumettesRestantes); + + for (int i = 1; i <= maxRetirage; i++) { + coups.add(new NimPly(this.currentPlayer, i)); + } + + return coups.iterator(); + } + + @Override + public void doPly(AbstractPly c) { + if (!(c instanceof NimPly)) { + throw new IllegalArgumentException("Le coup doit ĂȘtre un NimPly"); + } + + if (!isLegal(c)) { + throw new IllegalStateException("Ce coup n'est pas lĂ©gal"); + } + + NimPly coup = (NimPly) c; + + // Retirer les allumettes + this.allumettesRestantes -= coup.getNombreAllumettesPrises(); + + // Ajouter le coup Ă  l'historique + this.history.addLast(c); + + // VĂ©rifier si le jeu est terminĂ© + if (this.allumettesRestantes == 0) { + this.gameOver = true; + // Dans la variante misĂšre : celui qui prend la derniĂšre allumette perd + if (this.currentPlayer == Player.PLAYER1) { + this.result = Result.LOSS; + } else { + this.result = Result.WIN; + } + } + + // Changer de joueur + setNextPlayer(); + } + + @Override + public void undoPly() { + if (this.history.isEmpty()) { + throw new IllegalStateException("Rien Ă  annuler dans l'historique"); + } + + AbstractPly dernierCoup = this.history.removeLast(); + NimPly coup = (NimPly) dernierCoup; + + // Remettre les allumettes + this.allumettesRestantes += coup.getNombreAllumettesPrises(); + + // Revenir au joueur prĂ©cĂ©dent + setNextPlayer(); + + // RĂ©initialiser l'Ă©tat du jeu + this.gameOver = false; + this.result = null; + } + + /** + * Change le joueur courant + */ + private void setNextPlayer() { + if (this.currentPlayer == Player.PLAYER1) { + this.currentPlayer = Player.PLAYER2; + } else { + this.currentPlayer = Player.PLAYER1; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Jeu de Nim\n"); + sb.append("Allumettes restantes : ").append(allumettesRestantes).append("\n"); + sb.append("Maximum par coup : ").append(maxParCoup).append("\n"); + sb.append("Joueur courant : ").append(currentPlayer).append("\n"); + + if (gameOver) { + sb.append("Jeu terminĂ© - RĂ©sultat (du point de vue de PLAYER1) : ").append(result).append("\n"); + } + + return sb.toString(); + } +} + diff --git a/TP3/fr/iut_fbleau/Nim/NimBotPlayer.class b/TP3/fr/iut_fbleau/Nim/NimBotPlayer.class new file mode 100644 index 0000000..3eae923 Binary files /dev/null and b/TP3/fr/iut_fbleau/Nim/NimBotPlayer.class differ diff --git a/TP3/fr/iut_fbleau/Nim/NimBotPlayer.java b/TP3/fr/iut_fbleau/Nim/NimBotPlayer.java new file mode 100644 index 0000000..be46efa --- /dev/null +++ b/TP3/fr/iut_fbleau/Nim/NimBotPlayer.java @@ -0,0 +1,166 @@ +package fr.iut_fbleau.Nim; + +import fr.iut_fbleau.GameAPI.AbstractGamePlayer; +import fr.iut_fbleau.GameAPI.AbstractPly; +import fr.iut_fbleau.GameAPI.IBoard; +import fr.iut_fbleau.GameAPI.Player; +import fr.iut_fbleau.GameAPI.Result; + +import java.util.Iterator; + +/** + * ReprĂ©sente un joueur bot pour le jeu de Nim. + * Le bot utilise l'algorithme MiniMax avec Ă©lagage Alpha-Beta pour choisir le meilleur coup. + */ +public class NimBotPlayer extends AbstractGamePlayer { + + private Player joueur; + + /** + * Constructeur d'un bot joueur de Nim + * + * @param joueur le type de joueur (PLAYER1 ou PLAYER2) + */ + public NimBotPlayer(Player joueur) { + this.joueur = joueur; + } + + @Override + public AbstractPly giveYourMove(IBoard p) { + if (!(p instanceof NimBoard)) { + throw new IllegalArgumentException("Le plateau doit ĂȘtre un NimBoard"); + } + + NimBoard plateau = (NimBoard) p; + + System.out.println("\n" + plateau); + System.out.println("Le bot rĂ©flĂ©chit..."); + + AbstractPly meilleurCoup = findBestMove(plateau); + + System.out.println("Le bot joue : " + meilleurCoup); + + return meilleurCoup; + } + + /** + * Trouve le meilleur coup Ă  jouer en utilisant l'algorithme MiniMax avec Alpha-Beta + */ + private AbstractPly findBestMove(NimBoard plateau) { + AbstractPly meilleurCoup = null; + int meilleureValeur; + + if (this.joueur == Player.PLAYER1) { + meilleureValeur = Integer.MIN_VALUE; + + Iterator coups = plateau.iterator(); + while (coups.hasNext()) { + AbstractPly coup = coups.next(); + + plateau.doPly(coup); + int score = minimax(plateau, Integer.MIN_VALUE, Integer.MAX_VALUE, false); + plateau.undoPly(); + + if (score > meilleureValeur) { + meilleureValeur = score; + meilleurCoup = coup; + } + } + } else { + meilleureValeur = Integer.MAX_VALUE; + + Iterator coups = plateau.iterator(); + while (coups.hasNext()) { + AbstractPly coup = coups.next(); + + plateau.doPly(coup); + int score = minimax(plateau, Integer.MIN_VALUE, Integer.MAX_VALUE, true); + plateau.undoPly(); + + if (score < meilleureValeur) { + meilleureValeur = score; + meilleurCoup = coup; + } + } + } + + return meilleurCoup; + } + + /** + * Algorithme MiniMax avec Ă©lagage Alpha-Beta + * + * @param plateau le plateau de jeu + * @param alpha la valeur alpha pour l'Ă©lagage + * @param beta la valeur beta pour l'Ă©lagage + * @param isMaximizing true si on maximise, false si on minimise + * @return l'Ă©valuation de la position + */ + private int minimax(NimBoard plateau, int alpha, int beta, boolean isMaximizing) { + // Condition terminale : jeu fini + if (plateau.isGameOver()) { + Result result = plateau.getResult(); + if (result == Result.WIN) { + return 1; // PLAYER1 gagne + } else if (result == Result.LOSS) { + return -1; // PLAYER1 perd (PLAYER2 gagne) + } else { + return 0; // Match nul + } + } + + if (isMaximizing) { + // Maximiser pour PLAYER1 + int max = Integer.MIN_VALUE; + + Iterator coups = plateau.iterator(); + while (coups.hasNext()) { + AbstractPly coup = coups.next(); + + plateau.doPly(coup); + int eval = minimax(plateau, alpha, beta, false); + plateau.undoPly(); + + max = Math.max(max, eval); + alpha = Math.max(alpha, eval); + + // Élagage Beta + if (beta <= alpha) { + break; + } + } + + return max; + } else { + // Minimiser pour PLAYER2 + int min = Integer.MAX_VALUE; + + Iterator coups = plateau.iterator(); + while (coups.hasNext()) { + AbstractPly coup = coups.next(); + + plateau.doPly(coup); + int eval = minimax(plateau, alpha, beta, true); + plateau.undoPly(); + + min = Math.min(min, eval); + beta = Math.min(beta, eval); + + // Élagage Alpha + if (beta <= alpha) { + break; + } + } + + return min; + } + } + + /** + * @return le type de joueur + */ + public Player getPlayer() { + return this.joueur; + } +} + diff --git a/TP3/fr/iut_fbleau/Nim/NimGame.class b/TP3/fr/iut_fbleau/Nim/NimGame.class new file mode 100644 index 0000000..aaa4e53 Binary files /dev/null and b/TP3/fr/iut_fbleau/Nim/NimGame.class differ diff --git a/TP3/fr/iut_fbleau/Nim/NimGame.java b/TP3/fr/iut_fbleau/Nim/NimGame.java new file mode 100644 index 0000000..b2445c7 --- /dev/null +++ b/TP3/fr/iut_fbleau/Nim/NimGame.java @@ -0,0 +1,79 @@ +package fr.iut_fbleau.Nim; + +import fr.iut_fbleau.GameAPI.Player; +import fr.iut_fbleau.GameAPI.AbstractPly; +import java.util.Scanner; + +/** + * Classe principale pour jouer au jeu de Nim. + * Cette classe permet de lancer une partie entre deux joueurs. + */ +public class NimGame { + + public static void main(String[] args) { + System.out.println("=== Jeu de Nim ===\n"); + + Scanner scanner = new Scanner(System.in); + + // Demander le nombre d'allumettes + int allumettesInitiales = 0; + while (allumettesInitiales <= 0) { + System.out.print("Avec combien d'allumettes voulez-vous commencer ? (minimum 1) : "); + try { + allumettesInitiales = scanner.nextInt(); + if (allumettesInitiales <= 0) { + System.out.println("Le nombre doit ĂȘtre positif !"); + } + } catch (Exception e) { + System.out.println("EntrĂ©e invalide. Veuillez entrer un nombre."); + scanner.nextLine(); // vider le buffer + } + } + + // Maximum par coup fixĂ© Ă  3 + int maxParCoup = 3; + + NimBoard plateau = new NimBoard(allumettesInitiales, maxParCoup); + + // CrĂ©er les joueurs + NimPlayer joueur1 = new NimPlayer(Player.PLAYER1); + NimBotPlayer joueur2 = new NimBotPlayer(Player.PLAYER2); + + System.out.println("\nConfiguration du jeu :"); + System.out.println("- Nombre d'allumettes : " + allumettesInitiales); + System.out.println("- Maximum par coup : " + maxParCoup); + System.out.println("- RĂšgle : Le joueur qui prend la derniĂšre allumette PERD"); + System.out.println("- PLAYER1 : Humain"); + System.out.println("- PLAYER2 : Bot (MiniMax avec Alpha-Beta)\n"); + + // Boucle de jeu + while (!plateau.isGameOver()) { + // Obtenir le coup du joueur actif + AbstractPly coup; + if (plateau.getcurrentPlayer() == Player.PLAYER1) { + coup = joueur1.giveYourMove(plateau); + } else { + coup = joueur2.giveYourMove(plateau); + } + + // Jouer le coup + plateau.doPly(coup); + + System.out.println("\n>>> " + coup); + } + + // Afficher le rĂ©sultat + System.out.println("\n=== Fin de la partie ==="); + System.out.println(plateau); + + // DĂ©terminer le gagnant en utilisant l'enum Result + if (plateau.getResult() == fr.iut_fbleau.GameAPI.Result.WIN) { + System.out.println("Le PLAYER1 a gagnĂ© !"); + } else if (plateau.getResult() == fr.iut_fbleau.GameAPI.Result.LOSS) { + System.out.println("Le PLAYER2 (Bot) a gagnĂ© !"); + } else { + System.out.println("Match nul !"); + } + } +} + diff --git a/TP3/fr/iut_fbleau/Nim/NimPlayer.class b/TP3/fr/iut_fbleau/Nim/NimPlayer.class new file mode 100644 index 0000000..5307198 Binary files /dev/null and b/TP3/fr/iut_fbleau/Nim/NimPlayer.class differ diff --git a/TP3/fr/iut_fbleau/Nim/NimPlayer.java b/TP3/fr/iut_fbleau/Nim/NimPlayer.java new file mode 100644 index 0000000..e0168c0 --- /dev/null +++ b/TP3/fr/iut_fbleau/Nim/NimPlayer.java @@ -0,0 +1,66 @@ +package fr.iut_fbleau.Nim; + +import fr.iut_fbleau.GameAPI.AbstractGamePlayer; +import fr.iut_fbleau.GameAPI.AbstractPly; +import fr.iut_fbleau.GameAPI.IBoard; +import fr.iut_fbleau.GameAPI.Player; + +import java.util.Scanner; +import java.util.Iterator; + +/** + * ReprĂ©sente un joueur humain pour le jeu de Nim. + */ +public class NimPlayer extends AbstractGamePlayer { + + private Player joueur; + private Scanner scanner; + + public NimPlayer(Player joueur) { + this.joueur = joueur; + this.scanner = new Scanner(System.in); + } + + @Override + public AbstractPly giveYourMove(IBoard p) { + if (!(p instanceof NimBoard)) { + throw new IllegalArgumentException("Le plateau doit ĂȘtre un NimBoard"); + } + + NimBoard plateau = (NimBoard) p; + + System.out.println("\n" + plateau); + System.out.println("C'est ton tour joueur : " + this.joueur); + + // Afficher les coups possibles + System.out.println("Coups possibles :"); + Iterator coups = plateau.iterator(); + int compteur = 1; + while (coups.hasNext()) { + NimPly coup = (NimPly) coups.next(); + System.out.println(" " + compteur + ". Retirer " + coup.getNombreAllumettesPrises() + " allumette(s)"); + compteur++; + } + + // Demander au joueur de choisir + int maxAllumettes = Math.min(plateau.getMaxParCoup(), plateau.getAllumettesRestantes()); + int choix = -1; + + while (choix < 1 || choix > maxAllumettes) { + System.out.print("Combien d'allumettes voulez-vous retirer ? (1-" + maxAllumettes + ") : "); + try { + choix = scanner.nextInt(); + if (choix < 1 || choix > maxAllumettes) { + System.out.println("Choix invalide. Veuillez choisir entre 1 et " + maxAllumettes); + } + } catch (Exception e) { + System.out.println("EntrĂ©e invalide. Veuillez entrer un nombre."); + scanner.nextLine(); // vider le buffer + } + } + + return new NimPly(this.joueur, choix); + } +} + + diff --git a/TP3/fr/iut_fbleau/Nim/NimPly.class b/TP3/fr/iut_fbleau/Nim/NimPly.class new file mode 100644 index 0000000..b37ab20 Binary files /dev/null and b/TP3/fr/iut_fbleau/Nim/NimPly.class differ diff --git a/TP3/fr/iut_fbleau/Nim/NimPly.java b/TP3/fr/iut_fbleau/Nim/NimPly.java new file mode 100644 index 0000000..7c6396f --- /dev/null +++ b/TP3/fr/iut_fbleau/Nim/NimPly.java @@ -0,0 +1,38 @@ +package fr.iut_fbleau.Nim; + +import fr.iut_fbleau.GameAPI.AbstractPly; +import fr.iut_fbleau.GameAPI.Player; + +/** + * ReprĂ©sente un coup dans le jeu de Nim. + * Un coup consiste Ă  retirer un certain nombre d'allumettes. + */ +public class NimPly extends AbstractPly { + + private Player joueur; + private int nombreAllumettesPrises; + + public NimPly(Player joueur, int nombreAllumettesPrises) { + this.joueur = joueur; + this.nombreAllumettesPrises = nombreAllumettesPrises; + } + + /** + * @return le joueur qui effectue le coup + */ + public Player getJoueur() { + return this.joueur; + } + + /** + * @return le nombre d'allumettes prises + */ + public int getNombreAllumettesPrises() { + return this.nombreAllumettesPrises; + } + + public String toString() { + return "Joueur " + joueur + " retire " + nombreAllumettesPrises + " allumette(s)"; + } +} + diff --git a/test b/test deleted file mode 100644 index e69de29..0000000