package com.anibal.prueba_pooproyect;

import java.util.Random;

/**
 * clase encargada del analisis del tablero para decidir la mejor jugada.
 */
public class Bot_analisis {
    /**
     * constructor del cerebro del bot, aca se crea el tablero de puntajes para el humano y para el bot
     * @param board tablero de entrada
     * @param m alto del tablero
     * @param n ancho del tablero
     */
    Bot_analisis(Board board, int m, int n) {
        this.board = board;
        this.n = n; // coordenada X
        this.m = m; // coordenada Y
        botValueBoard = new int[m][n];
        movimiento = new int[2];
        movimientoAGR = new int[2];
        movimientoDEF = new int[2];
        valueBoard = new int[m][n]; // creación del tablero, originalmente se asignan todos en 0 ARREGLO DE ENTEROS
        resetBoard(); // asigna valores de 0 a todos los puntos del tablero (0 es el valor neutro)
    }

    /**
     * metodo utilizado para resetear valueboard y botvalueBoard.
     */
    public void resetBoard() {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                valueBoard[i][j] = 0;
                botValueBoard[i][j] = 0;

            }
        }
    }

    public void analizeBoard(Board board, int xMove, int yMove) {
        this.board = board;
        /*int yInicio, xInicio, yFinal, xFinal;
        // setear limites para el analisis
        if (yMove - 5 >= 1) yInicio = yMove - 5;
        else
            yInicio = 1; // partir en 1 para no tener problemas con analisis de puntaje (toma posicion actual -1 en ambos ejes!)
        if (xMove - 5 >= 1) xInicio = xMove - 5;
        else xInicio = 1; //partir del 1 para no tener problemas en el analisis de puntaje
        if (yMove + 5 < n) yFinal = yMove + 5;
        else yFinal = n;
        if (xMove + 5 < m) xFinal = xMove + 5;
        else xFinal = m;
        System.out.println(yInicio + " " + yFinal + " " + xInicio + " " + xFinal);*/
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                String move = i + " " + j;
                if (board.getEmpties().contains(move)) {
                    thinkNextMove(i, j, '1'); // analized player es el jugador contrario al que se le analizan las jugadas
                    thinkNextMove(i, j, '2');  // analiza para jugar a ganar
                }

            }
        }
        chooseSmartMove();

    }

    /**
     * Metodo utilizado para elegir dentro del tablero con todos los puntajes asignados cual es el movimiento mas alto entre ambos,
     * tablero defensivo y agresivo. el agresivo es cuando el bot prioriza ganar y defensivo cuando prioriza no perder
     */
    public void chooseSmartMove() {
        int maxValue = 0;
        int maxBotValue = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if ((valueBoard[i][j] > maxValue) && board.getEmpties().contains(i + " " + j)) {
                    maxValue = valueBoard[i][j];
                    movimientoDEF[0] = i;
                    movimientoDEF[1] = j;
                }
                if ((botValueBoard[i][j] > maxBotValue) && board.getEmpties().contains(i + " " + j)) {
                    maxBotValue = botValueBoard[i][j];
                    movimientoAGR[0] = i;
                    movimientoAGR[1] = j;
                }
            }
        }
        if (maxBotValue >= maxValue) {
            movimiento[0] = movimientoAGR[0];
            movimiento[1] = movimientoAGR[1];
        } else {
            movimiento[0] = movimientoDEF[0];
            movimiento[1] = movimientoDEF[1];
        }
    }

    /**
     * utilizado para acceder a movimiento desde el mainactivity
     * @return coordenadas en un arreglo de enteros
     */
    public int[] getMovimientoCoordinates() {
        return movimiento;
    }

    /**
     * metodo utilizado para pensar en el siguiente movimiento
     * @param i coordenada de analisis (y en el plano cartesiano)
     * @param j coordenad de analisis (x en el plano cartesiano)
     * @param analizedPlayer char del jugador a analizar, 1 para humano, 2 para bot
     */
    private void thinkNextMove(int i, int j, char analizedPlayer) {
        checkRow(analizedPlayer, i, j);
        checkCol(analizedPlayer, i, j);
        checkLeftDiagonal(analizedPlayer, i, j);
        checkRightDiagonal(analizedPlayer, i, j);
        checkUpCol(analizedPlayer, i, j);
        checkInvRow(analizedPlayer, i, j);
        checkLeftUpDiagonal(analizedPlayer, i, j);
        checkRightUpDiagonal(analizedPlayer, i, j);
    }

    /**
     * metodo para chekear fila
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkRow(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;

        for (int y = -1; y < 5; y++) {
            if ((i + y) < m && j < n && i + y >= 0) {

                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i + y, j);

            } // no es necesario agregar alguan salida ya que al comparar en el evalauteBoard es un switch, si no cumple no cumple nomas
            else stringOfPlay = stringOfPlay + ".";
        }
        if (jugador == '1') evaluatePlayerBoard(i, j);
        else evaluateBotBoard(i, j);
    }
    /**
     * metodo para chekear fila en sentido contrario
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */

    public void checkInvRow(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;
        for (int y = -1; y < 5; y++) {
            if (i < m && j - y >= 0 && j - y < n && i >= 0) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i, j - y);
            } // no es necesario agregar alguan salida ya que al comparar en el evalauteBoard es un switch, si no cumple no cumple nomas
            else stringOfPlay = stringOfPlay + ".";
        }
        if (jugador == '1') evaluatePlayerBoard(i, j);
        else evaluateBotBoard(i, j);
    }

    /**
     * metodo para chekear columna
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkCol(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;
        for (int y = -1; y < 5; y++) {
            if ((j + y) < n && (j + y) >= 0) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i, j + y);
            } else stringOfPlay = stringOfPlay + ".";
        }
        if (jugador == '1') evaluatePlayerBoard(i, j);
        else evaluateBotBoard(i, j);
    }

    /**
     * metodo para chekear columna en sentido inverso
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkUpCol(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;

        for (int y = -1; y < 5; y++) {
            if (i - y < m && (i - y) >= 0 && j - y < n) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i - y, j);
            } else stringOfPlay = stringOfPlay + ".";
        }
        if (jugador == '1') evaluatePlayerBoard(i, j);
        else evaluateBotBoard(i, j);
    }

    /**
     * metodo para chekear diagonal descendiente hacia la izquierda
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkLeftDiagonal(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;
        for (int y = -1; y < 5; y++) {
            if ((i + y) < m && (j - y) >= 0 && (i + y) >= 0 && (j - y) < n) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i + y, j - y);
            } else stringOfPlay = stringOfPlay + ".";

        }
        evaluatePlayerBoard(i, j);

    }
    /**
     * metodo para chekear diagonal ascendiente hacia la izquierda
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkLeftUpDiagonal(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;
        for (int y = -1; y < 5; y++) {
            if ((i - y) < m && (j - y) >= 0 && (i - y) >= 0 && (j - y) < n) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i - y, j - y);
            } else stringOfPlay = stringOfPlay + ".";

        }
        evaluatePlayerBoard(i, j);

    }
    /**
     * metodo para chekear diagonal descendiente hacia la derecha
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkRightDiagonal(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;
        for (int y = -1; y < 5; y++) {
            if ((i + y) < m && (j + y) < n && i + y >= 0 && j + y >= 0) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i + y, j + y);
            } else stringOfPlay = stringOfPlay + ".";
        }
        if (jugador == '1') evaluatePlayerBoard(i, j);
        else evaluateBotBoard(i, j);

    }
    /**
     * metodo para chekear diagonal ascendiente hacia la derecha
     * @param jugador char de entrada
     * @param i coordenada
     * @param j cordenada
     */
    public void checkRightUpDiagonal(char jugador, int i, int j) {
        stringOfPlay = "";
        char jugadorActual = jugador;
        for (int y = -1; y < 5; y++) {
            if ((i - y) >= 0 && (i - y) < m && (j + y) < n && j + y >= 0) {
                if (y == 0) stringOfPlay = stringOfPlay + jugador;
                else stringOfPlay = stringOfPlay + board.returnCordinates(i - y, j + y);
            } else stringOfPlay = stringOfPlay + ".";
        }
        if (jugador == '1') evaluatePlayerBoard(i, j);
        else evaluateBotBoard(i, j);

    }

    /**
     * metodo con los puntajes al momento de evaluar el tablero , se invoca deesde cada checkXXXXXX()
     * y se compara el string en el case, este corresponde al tablero como si el bot jugara en la futura posicion
     * @param x coordenada
     * @param y coordenada
     */
    public void evaluateBotBoard(int x, int y) {

        switch (stringOfPlay) {
            // cases con score positiva (jugador "suma puntos")
            case ("22222."):
                if (botValueBoard[x][y] < 100000000) {
                    botValueBoard[x][y] = 100000000;
                }
            case (".22222"):
                if (botValueBoard[x][y] < 100000000) {
                    botValueBoard[x][y] = 100000000;
                }
            case ("222221"):
                if (botValueBoard[x][y] < 10000000) {
                    botValueBoard[x][y] = 10000000;
                }

            case (".2222."):
                if (botValueBoard[x][y] < 1000000) {
                    botValueBoard[x][y] = 1000000;
                }
            case ("2222.."):
                if (botValueBoard[x][y] < 109000)
                    botValueBoard[x][y] = 109000;

            case (".22.22"):
                if (botValueBoard[x][y] < 100000) {
                    botValueBoard[x][y] = 100000;
                }
            case (".22221"):
                if (botValueBoard[x][y] < 100000) {
                    botValueBoard[x][y] = 100000;

                }

            case ("212222"):
                if (botValueBoard[x][y] < 100000) {
                    botValueBoard[x][y] = 100000;

                }
            case ("12222."):
                if (botValueBoard[x][y] < 100000)
                    botValueBoard[x][y] = 100000;

            case ("2222.1"):
                if (botValueBoard[x][y] < 100000)
                    botValueBoard[x][y] = 100000;
            case ("21222."):
                if (botValueBoard[x][y] < 10000)
                    botValueBoard[x][y] = 10000;
            case (".222.."):
                if (botValueBoard[x][y] < 10000)
                    botValueBoard[x][y] = 10000;
            case (".222.1"):
                if (botValueBoard[x][y] < 1000)
                    botValueBoard[x][y] = 1000;
            case ("222..."):
                if (botValueBoard[x][y] < 1000)
                    botValueBoard[x][y] = 1000;
            case ("222..1"):
                if (botValueBoard[x][y] < 1000)
                    botValueBoard[x][y] = 1000;
            case (".22.2."):
                if (botValueBoard[x][y] < 1000)
                    botValueBoard[x][y] = 1000;
            case (".22..2"):
                if (botValueBoard[x][y] < 500)
                    botValueBoard[x][y] = 500;
            case ("122..2"):
                if (botValueBoard[x][y] < 200)
                    botValueBoard[x][y] = 200;
            case ("22..2."):
                if (botValueBoard[x][y] < 200)
                    botValueBoard[x][y] = 200;
            case ("22...."):
                if (botValueBoard[x][y] < 100)
                    botValueBoard[x][y] = 100;
            case (".22..."):
                if (botValueBoard[x][y] < 100)
                    botValueBoard[x][y] = 100;
            case ("....22"):
                if (botValueBoard[x][y] < 100)
                    botValueBoard[x][y] = 100;
                // cases con score negativa (bot "suma puntos")

        }
    }

    /**
     * metodo similar al del bot pero para comparar como si el humano jugara en la siguiente posicion
     * @param x coordenada
     * @param y coordenada
     */
    public void evaluatePlayerBoard(int x, int y) {

        switch (stringOfPlay) {
            // cases con score positiva (jugador "suma puntos")
            case ("11111."):
                if (valueBoard[x][y] < 100000000) {
                    valueBoard[x][y] = 100000000;
                }
            case (".11111"):
                if (valueBoard[x][y] < 100000000) {
                    valueBoard[x][y] = 100000000;
                }
            case ("111112"):
                if (valueBoard[x][y] < 10000000) {
                    valueBoard[x][y] = 10000000;
                }

            case (".1111."):
                if (valueBoard[x][y] < 1000000) {
                    valueBoard[x][y] = 1000000;
                }
            case ("1111.."):
                if (valueBoard[x][y] < 109000)
                    valueBoard[x][y] = 109000;
            case ("12111."):
                if (valueBoard[x][y] < 105000)
                    valueBoard[x][y] = 105000;
            case (".11.11"):
                if (valueBoard[x][y] < 100000) {
                    valueBoard[x][y] = 100000;
                }
            case (".11112"):
                if (valueBoard[x][y] < 100000) {
                    valueBoard[x][y] = 100000;

                }
            case ("121111"):
                if (valueBoard[x][y] < 100000) {
                    valueBoard[x][y] = 100000;

                }
            case ("21111."):
                if (valueBoard[x][y] < 100000)
                    valueBoard[x][y] = 100000;

            case ("1111.2"):
                if (valueBoard[x][y] < 100000)
                    valueBoard[x][y] = 100000;
            case (".111.."):
                if (valueBoard[x][y] < 10000)
                    valueBoard[x][y] = 10000;
            case (".111.2"):
                if (valueBoard[x][y] < 1000)
                    valueBoard[x][y] = 1000;
            case ("111..."):
                if (valueBoard[x][y] < 1000)
                    valueBoard[x][y] = 1000;
            case ("111..2"):
                if (valueBoard[x][y] < 1000)
                    valueBoard[x][y] = 1000;
            case (".11.1."):
                if (valueBoard[x][y] < 1000)
                    valueBoard[x][y] = 1000;
            case (".11..1"):
                if (valueBoard[x][y] < 500)
                    valueBoard[x][y] = 500;
            case ("211..1"):
                if (valueBoard[x][y] < 200)
                    valueBoard[x][y] = 200;
            case ("11..1."):
                if (valueBoard[x][y] < 200)
                    valueBoard[x][y] = 200;
            case ("11...."):
                if (valueBoard[x][y] < 100)
                    valueBoard[x][y] = 100;
            case (".11..."):
                if (valueBoard[x][y] < 100)
                    valueBoard[x][y] = 100;
            case ("....11"):
                if (valueBoard[x][y] < 100)
                    valueBoard[x][y] = 100;
                // cases con score negativa (bot "suma puntos")

        }
    }

    /**
     * metodo encargado de realizar una jugada random en el "centro" del tablero.
     */
    public void makeRandomMove() {
        boolean flagJugada = true;
        Random r = new Random();
        while (flagJugada) {
            int xMove = r.nextInt(5) + 5;
            int yMove = r.nextInt(5) + 5;
            String move = xMove + " " + yMove; // string del movimiento para comparar
            if (board.getEmpties().contains(move)) {
                movimiento[0] = xMove;
                movimiento[1] = yMove;
                flagJugada = false;
            }
        }

    }


    private String stringOfPlay;
    private int[] movimientoDEF, movimientoAGR, movimiento;
    private int[][] valueBoard, botValueBoard; // tablero (valores enteros)en el que se evaluan las posiciones y puntos para decidir siguiente jugada
    private int n, m;
    private Board board;


}
