This commit is contained in:
SimonSayeBabu 2024-09-22 18:08:41 +02:00
parent 9862082bf2
commit f92959247b
12 changed files with 269 additions and 215 deletions

View File

@ -1,81 +0,0 @@
public class MiniMax {
/*
Variable donnant le nombre d'allumettes au départ du jeu (remplacée par un argument en ligne de commande)
*/
public static int depart = 5000;
private static int[] J1;
private static int[] J2;
private static int compteur;
public static void main(String[] args) {
compteur = 0;
int n = depart;
//int n = Integer.parseInt(args[0]);
J1 = new int[n+1];
J2 = new int[n+1];
System.out.println(Nim(n));
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+" ; ");
}
System.out.println();
System.out.println("Compteur : "+compteur);
}
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
*/
public static int exploreMax(int allumette) {
compteur++;
if (J1[allumette] != 0){
return J1[allumette];
}
int n = allumette;
for (int i=1;allumette>1&&i<3;i++){
allumette--;
int v=exploreMin(allumette);
if (v == 1){
J1[n]=1;
return 1;
}
}
J1[n] = -1;
return -1;
}
/*
Vérifie les issues possibles des coups du J2 et renvoie -1 si le J2 a une opportunité de gagner a coup sur
*/
public static int exploreMin(int allumette){
compteur++;
if (J2[allumette] != 0){
return J2[allumette];
}
int n = allumette;
for (int i=0;allumette>1&&i<3;i++){
allumette--;
int v=exploreMax(allumette);
if (v == -1){
J2[n]=-1;
return v;
}
}
J2[n] = 1;
return 1;
}
}

BIN
MiniMaxOptiCarnet.class Normal file

Binary file not shown.

95
MiniMaxOptiCarnet.java Normal file
View File

@ -0,0 +1,95 @@
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[] tests = {5,11,17,42,100};
private static int[] J1;
private static int[] J2;
static long debut;
private static int compteur;
private static int limite;
public static void main(String[] args) {
limite = 0;
try {
for(int n: tests) {
J1 = new int[limite + 1];
J2 = new int[limite + 1];
compteur = 0;
debut = System.nanoTime();
compteur = 0;
System.out.print(n + " allumettes : ");
int s = Nim(n);
if (s == 1) {
System.out.print("Gagné ;");
} else {
System.out.print("Perdu ;");
}
long fin = System.nanoTime();
System.out.print(" Temps écoulé (ms) : "+((fin-debut)/1000000)+" ;");
System.out.println(" Compteur = " + compteur);
}
} 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;
}
}

68
MiniMaxPetiteOpti.java Normal file
View File

@ -0,0 +1,68 @@
public class MiniMaxPetiteOpti {
public static int[] tests = {5,11,17,42,100};
private static int compteur;
static long debut;
public static void main(String[] args) {
for(int n: tests) {
debut = System.nanoTime();
compteur = 0;
System.out.print(n + " allumettes : ");
int s = Nim(n);
if (s == 1) {
System.out.print("Gagné ;");
} else {
System.out.print("Perdu ;");
}
long fin = System.nanoTime();
System.out.print(" Temps écoulé (ms) : "+((fin-debut)/1000000)+" ;");
System.out.println(" Compteur = " + compteur);
}
}
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
*/
public static int exploreMax(int allumette) {
compteur++;
if ((System.nanoTime()-debut)/1000000 > 100000 ){
System.out.println("TimeOut au bout de 100 secondes");
System.exit(-1);
}
for (int i=0;allumette>1&&i<3;i++){
allumette--;
int v=exploreMin(allumette);
if (v==1){
return v;
}
}
return -1;
}
/*
Vérifie les issues possibles des coups du J2 et renvoie -1 si le J2 a une opportunité de gagner a coup sur
*/
public static int exploreMin(int allumette){
compteur++;
for (int i=0;allumette>1&&i<3;i++){
allumette--;
int v=exploreMax(allumette);
if (v==-1){
return v;
}
}
return 1;
}
}

70
MiniMaxSansOpti.java Normal file
View File

@ -0,0 +1,70 @@
public class MiniMaxSansOpti {
public static int[] tests = {5,11,17,42,100};
private static int compteur;
static long debut;
public static void main(String[] args) {
for(int n: tests) {
debut = System.nanoTime();
compteur = 0;
System.out.print(n + " allumettes : ");
int s = Nim(n);
if (s == 1) {
System.out.print("Gagné ;");
} else {
System.out.print("Perdu ;");
}
long fin = System.nanoTime();
System.out.print(" Temps écoulé (ms) : "+((fin-debut)/1000000)+" ;");
System.out.println(" Compteur = " + compteur);
}
}
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
*/
public static int exploreMax(int allumette) {
compteur++;
if ((System.nanoTime()-debut)/1000000 > 100000 ){
System.out.println("TimeOut au bout de 100 secondes");
System.exit(-1);
}
int max = -1;
for (int i=0;allumette>1&&i<3;i++){
allumette--;
int v=exploreMin(allumette);
if (v > max){
max = v;
}
}
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
*/
public static int exploreMin(int allumette){
compteur++;
int min = 1;
for (int i=0;allumette>1&&i<3;i++){
allumette--;
int v=exploreMax(allumette);
if (v<min){
min = v;
}
}
return min;
}
}

36
RapportNim.md Normal file
View File

@ -0,0 +1,36 @@
# Rapport Jeu de Nim
**Membres du groupe :** Axel Pietrois et Simon Saye Babu</br>
## Avancement
La **version de base de Minimax** a été implémentée pour rappel voici son fonctionnement :</br>
Le joueur1 va faire un *exploreMax* de ces coups possible, pour chaque coup, si celui ci n'est pas final la fonction *exploreMin* est lancé sur celui ci. Ensuite *exploreMax* sur les choix de n+1 ainsi de suite, jusqu'a que l'un des joueur tombe sur un coups final ce qui garantie la victoire/la perte de coup. </br>
Dans exploreMax, si il y a une possibilité de perdre dans une branche elle vaudra -1 si elle est obligatoirement victorieuse elle vaudra 1 et inversement pour exploreMin.
exploreMin represente le meilleur choix du joueur2 (qui est le pire choix pour joueur1 d'ou explore**MIN**).
### Version avec carnet
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.
## Test et comparaison
### Version non optimisée
5 allumettes : Perdu ; Temps écoulé (ms) : 3 ; Compteur = 15
11 allumettes : Gagné ; Temps écoulé (ms) : 0 ; Compteur = 600
17 allumettes : Perdu ; Temps écoulé (ms) : 0 ; Compteur = 23249
42 allumettes : TimeOut au bout de 100 secondes
## Version optimisée
5 allumettes : Perdu ; Temps écoulé (ms) : 4 ; Compteur = 15
11 allumettes : Gagné ; Temps écoulé (ms) : 0 ; Compteur = 228
17 allumettes : Perdu ; Temps écoulé (ms) : 0 ; Compteur = 5601
42 allumettes : Gagné ; Temps écoulé (ms) : 7089 ; Compteur = 659108914
100 allumettes : TimeOut au bout de 100 secondes
## Version avec carnet
5 allumettes : Perdu ; Temps écoulé (ms) : 3 ; Compteur = 13
11 allumettes : Gagné ; Temps écoulé (ms) : 0 ; Compteur = 49
17 allumettes : Perdu ; Temps écoulé (ms) : 0 ; Compteur = 85
42 allumettes : Gagné ; Temps écoulé (ms) : 0 ; Compteur = 235
100 allumettes : Gagné ; Temps écoulé (ms) : 0 ; Compteur = 583
## Graphique
![Image du graphique](graph.png)

Binary file not shown.

View File

@ -1,13 +0,0 @@
public class AbreNim {
private Noeud root;
public AbreNim(int valeur) {
this.root = new Noeud(valeur);
}
public Noeud getRoot() {
return root;
}
}

View File

@ -1,17 +0,0 @@
public class Etat {
private int nb_alumettes;
private int statut;
public Etat(int nb,int statut){
this.nb_alumettes = nb;
this.statut = statut;
}
public int getNb_alumettes() {
return nb_alumettes;
}
public int getStatut() {
return statut;
}
}

Binary file not shown.

View File

@ -1,22 +0,0 @@
public class Noeud {
private Integer valeur;
public Noeud[] child = new Noeud[3];
private int Etat;
public Noeud(Integer etiquette) {
this.valeur = etiquette;
}
public int getValeur()
{
return valeur;
}
public int getEtat(){
return Etat;
}
public void setEtat(int newEtat){
this.Etat = newEtat;
}
}

View File

@ -1,82 +0,0 @@
import java.util.ArrayList;
import java.util.List;
import AbreNim;
import Noeud;
public class nim {
public static void main(String[] args) {
AbreNim AN = AbreNim(5);
System.out.println(exploreMax(AN.getRoot()));
}
/**
* Determine si le joueur gagne ou perd grace a exploreMin.
* @param allumette le nombre d'allumette au tour du joueur
* @return -1 si perdant ou 1 si gagnant
*/
public static boolean exploreMax(Noeud root) {
allumette = root.getValeur();
allumette -= 3;
for(int i=0;allumette>1&&i<3;i++) {
root.child[i] = new Noeud(allumette);
if (checkEtat(root.child[i])==1) {
return true;
}
allumette++;
}
boolean childtest;
for (int i = 2; i >=0; i--) {
if (root.child[i].getEtat()==0) {
childtest = exploreMin(root.child[i]);
if (childtest) {
return true;
}
}
}
}
/**
* Determine si le joueur gagne ou perd grace a exploreMax.
* @param allumette le nombre d'allumette au tour du joueur
* @return -1 si gagnant ou 1 si perdant
*/
public static boolean exploreMin(Noeud root){
allumette = root.getValeur();
allumette -= 3;
for(int i=0;allumette>1&&i<3;i++) {
root.child[i] = new Noeud(allumette);
if (checkEtat(root.child[i])==-1) {
return true;
}
allumette++;
}
boolean childtest = false;
for (int i = 2; i >=0; i--) {
if (root.child[i].getEtat()==0) {
childtest = exploreMax(root.child[i]);
if (childtest) {
return true;
}
}
}
}
public static int checkEtat(Noeud node){
if(node.getValeur()<1){
node.setEtat(-1);
return -1;
}
else if (node.getValeur()==1) {
node.setEtat(1);
return 1;
}
node.setEtat(0);
return 0;
}
}