/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package tictactoecodingame; import static java.lang.Math.max; import static java.lang.Math.min; import java.util.ArrayList; /** * * @author Alain */ public class AlgoRechercheMinMax extends AlgoRecherche { /* Le but de cet algorithme est d'implémenter la méthode MinMax au jeu TicTacToe. La fonction d'évaluation est ici assez simple elle retourne 1 sur le noeud si l'ordi gagne la partie et -1 si l'ordi perd la partie. Cet algorithme est implémenté avec l'amélioration alpha beta. */ Joueur humain; Joueur ordi; public AlgoRechercheMinMax(Joueur _ordi1, Joueur _joueur1){ ordi = _ordi1; humain = _joueur1; } double[] scores = {-1,1,0}; // Score -1 si partie perdue, 1 si partie gagnée et 0 si égalité. @Override public Coup meilleurCoup(Plateau _plateau, Joueur _joueur, boolean ponder){ /* MeilleurCoup prend en paramètre un plateau, un joueur (non utilisé ici mais qui serait l'ordi) et un boolean ponder pour laisser l'ordi réfléchir. */ double inf = Double.POSITIVE_INFINITY; double bestScore = -1 * inf; CoupTicTacToe meilleur_coup = null ; double alpha = -1 * inf; // méthode alpha beta double beta = inf; ArrayList<Coup> coups = _plateau.getListeCoups(ordi); for (int i = 0; i < coups.size(); i++){ _plateau.sauvegardePosition(0); // Pour pouvoir revenir à cet état une fois les simulations finies et les scores calculés. _plateau.joueCoup(coups.get(i)); double score = minimax(_plateau,humain,1,false,alpha,beta); //False car l'ordi a déjà placé son premier coup Coup coup_provisoire = coups.get(i); _plateau.restaurePosition(0); // Retour à la configuration initiale après calcul des scores. if (score > bestScore){ // On modifie le bestScore si on en trouve un meilleur. bestScore = score; meilleur_coup = (CoupTicTacToe)coup_provisoire; } } return meilleur_coup; // changer le tour du joueur } public double minimax(Plateau _plateau,Joueur _joueur,int profondeur,boolean isMaximizing, double alpha, double beta){ /* minimax prend en paramètre un plateau, le joueur qui va jouer, la profondeur, un boolean pour savoir si on doit maximiser ou minimiser et des doubles alpha et beta pour implémenter la méthode alpha beta. */ if (_plateau.partieTerminee()){ if(_plateau.partieNulle()){ return 0; } else{ Joueur gagnant = _plateau.vainqueur(); //Il faut connaitre le vainqueur int resultat = gagnant.getIdJoueur(); return scores[resultat];} } if (isMaximizing) { //ordi qui joue double inf = Double.POSITIVE_INFINITY; double bestScore = -1 * inf; ArrayList<Coup> coups = _plateau.getListeCoups(ordi); for (int i = 0; i < coups.size(); i++){ // On suit le même principe que précédemment. _plateau.sauvegardePosition(profondeur); _plateau.joueCoup(coups.get(i)); double score = minimax(_plateau,humain,profondeur + 1,false, alpha, beta); _plateau.restaurePosition(profondeur); bestScore = max(score,bestScore); alpha = max(alpha,score); // Méthode alpha beta if (beta <= alpha){ break; // Ne vérifié pas les cas où on sait que les branches suivantes auront une évaluation inférieure à une déjà possible. } } return bestScore; } else { // Humain ou autre ordi qui joue double inf = Double.POSITIVE_INFINITY; double bestScore = inf; ArrayList<Coup> coups = _plateau.getListeCoups(humain); for (int i = 0; i < coups.size(); i++){ // On suit le même principe que précédemment. _plateau.sauvegardePosition(profondeur); _plateau.joueCoup(coups.get(i)); double score = minimax(_plateau,ordi,profondeur + 1,true,alpha,beta); _plateau.restaurePosition(profondeur); bestScore = min(score,bestScore); beta = min(beta,score); if (beta <= alpha){ break; // Ne vérifié pas les cas où on sait que les branches suivantes auront une évaluation supérieure à une déjà possible. } } return bestScore; } } }