/*
 * 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_9x9 extends AlgoRecherche {
    /* Le but de cet algorithme est d'implémenter la méthode MinMax au jeu TicTacToe9x9. La fonction d'évaluation est ici plus compliqué elle retourne 10 sur le noeud
    si l'ordi gagne une case et -10 si l'ordi perd une case. Cet algorithme est implémenté avec l'amélioration alpha beta.
    */
    
    Joueur humain;
    Joueur ordi;
    
    public AlgoRechercheMinMax_9x9(Joueur _ordi1, Joueur _joueur1){
        ordi = _ordi1;
        humain = _joueur1;
    }
    
    double[] scores = {-1000,1000,0};

    @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 pour laisser l'ordi réfléchir.
        
        */
      double inf = Double.POSITIVE_INFINITY;
      double bestScore = -1 * inf;
      CoupTicTacToe meilleur_coup = null ;
      GrilleTicTacToe9x9 _plateau1 = (GrilleTicTacToe9x9) _plateau;
      CoupTicTacToe coup_humain = _plateau1.dernierCoup;
      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);
        _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);
        if (score > bestScore){
            bestScore = score;
            meilleur_coup = (CoupTicTacToe)coup_provisoire;
                }
            }
      _plateau1.dernierCoup = coup_humain;
      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 faudrait connaitre le vainqueur
                if (gagnant != null){
                int resultat = gagnant.getIdJoueur();
                return scores[resultat];}
                else{
                    return 0;
                }
            }
        }
        if(profondeur>5){
            return evaluation(_plateau);
        }
    
        
        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++){
        _plateau.sauvegardePosition(profondeur);
        _plateau.joueCoup(coups.get(i));
            double score = minimax(_plateau,humain,profondeur + 1,false,alpha,beta);
            _plateau.restaurePosition(profondeur);
            alpha = max(alpha,score);
            if (beta <= alpha){
                break;
            }
            bestScore = max(score,bestScore);
        }
      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++){
                _plateau.sauvegardePosition(profondeur);
                _plateau.joueCoup(coups.get(i)); 
                double score = minimax(_plateau,ordi,profondeur + 1,true,alpha,beta);
                _plateau.restaurePosition(profondeur);
                  beta = min(beta,score);
                  if (beta <= alpha){
                  break;
            }
                bestScore = min(score,bestScore);
        }
            
            return bestScore;
        }
    }
    
    public double evaluation(Plateau _plateau1){ // Fonction d'évaluation pour attribuer un score si une case a été remportée ou non.
        GrilleTicTacToe9x9 _plateau = (GrilleTicTacToe9x9) _plateau1;
        double delta = 0;
        for(int i = 0; i < 3; i++){ // abscisse de la case 3x3
            for(int j = 0; j < 3; j++){ //ordonnée de la case 3x3
                for(int k = 0; k < 3; k++){ // absisse de la case 9x9
                    for(int l = 0; l< 3; l++){ // ordonnée de la case 9x9
                        Case case1 = new Case(3*i + k, 3*j + l);
                        Piece p = _plateau.getPiece(case1);
                        if (p!= null && p.getJoueur() == humain){
                            if (_plateau.caseGagnante(_plateau.grille9x9, 3*i, 3*j, 3*i + k, 3*j + l)){ // Si l'humain gagne
                                delta = delta - 10;
                                return delta;}
                        }
                         if (p!= null && p.getJoueur() == ordi){
                            if (_plateau.caseGagnante(_plateau.grille9x9, 3*i, 3*j, 3*i + k, 3*j + l)){ // Si l'ordi gagne
                                delta = delta + 10;
                                return delta;}   
                        }
                            
                        
                        
                    }
                }
            }
        }
    
  return 0;  }
    
    
}