

import java.util.List;
import java.util.ArrayList;

/**
 * KalahaPosicion define una Posicion. Esta clase hereda de la clase Posicion.
 * Una KalahaPosicion consiste en un tablero de kalaha y metodos para jugar una partida
 * de kalaha. 
 * 
 */
public class KalahaPosicion extends Posicion implements Cloneable
{
	/**
	 * tablero representa el tablero de kalaha. Los elementos 0-5 del array son los hoyos de arriba del tablero.
	 * Los elementos 7-12 del array son los hoys de abajo del tablero.
	 * Los elementos 6 y 13 del array son los mancalas del jugador de arriba y abajo del tablero, respectivamente.
	 */
	protected int tablero[] = new int[14];
	
	/**
	 * Piedras iniciales a colocar en cada hoyo al comienzo del juego.
	 */
	protected static int PIEDRASINICIALES; 
	/**
	 * Hoyos iniciales al comienzo del juego por cada jugador.
	 */
	protected static int HOYOSINICIALES; 
	
	/**
	 * Construye un objeto KalahaPositon dadas las piedras iniciales en cada hoyo (a excepcion de los mancalas).
	 * @param PIEDRAS las piedras iniciales a colocar en cada hoyo al comienzo del juego.
	 */
	public KalahaPosicion(int PIEDRAS, int HOYOS)
	{
		PIEDRASINICIALES = PIEDRAS;
		HOYOSINICIALES = HOYOS;
		if (HOYOS == 5){
			
		for (int i = 0; i < 5; i++)
		{
			tablero[i] = PIEDRASINICIALES;
		}
		for (int i = 6; i < 11; i++)
		{
			tablero[i] = PIEDRASINICIALES;
		}			
		}else{
		for (int i = 0; i < 6; i++)
		{
			tablero[i] = PIEDRASINICIALES;
		}
		for (int i = 7; i < 13; i++)
		{
			tablero[i] = PIEDRASINICIALES;
		}
		}
	}
	
	/**
	 * Construye un objeto KalahaPositon.
	 */
	public KalahaPosicion(){	
	}
	
	// FUNCIONES AUXILIARES PARA EVALUACION ESTATICA DE ESTADOS, INTELIGENCIA DE LA CPU
	
	// La funcion suma_piedras devuelve la diferencia de piedras del jugador y la maquina entre sus
	// hoyos y mancalas
	protected int suma_piedras(){
		int piedras = 0;
		if (HOYOSINICIALES==6){
			piedras = tablero[0] + tablero[1] + tablero[2] + tablero[3] + tablero[4] + tablero[5] + tablero[6] - 
					  tablero[7] - tablero[8] - tablero[9] - tablero[10] - tablero[11] - tablero[12] - tablero[13]; 
		}else{
			piedras = tablero[0] + tablero[1] + tablero[2] + tablero[3] + tablero[4] + tablero[5] - 
					  tablero[6] - tablero[7] - tablero[8] - tablero[9] - tablero[10] - tablero[11];
		}
		return piedras;
	}
	
	// La funcion cuenta_huecos cuenta la diferencia entre el numero de huecos en la fila de los jugadores
	protected int cuenta_huecos(){
		int huecos = 0;
		if (HOYOSINICIALES==6){
			for (int i=0;i<6;i++){
				if (tablero[i] == 0){
					huecos += 1; 
				}
			}
			for (int i=7;i<13;i++){
				if (tablero[i] == 0){
					huecos -= 1; 
				}
			}
		}else{
			for (int i=0;i<5;i++){
				if (tablero[i] == 0){
					huecos += 1; 
				}
			}
			for (int i=6;i<11;i++){
				if (tablero[i] == 0){
					huecos -= 1; 
				}
			}
		}
		return huecos;
	}
	
	// La funcion ultimo_hueco, da un peso positivo a tener el ultimo hueco vacio, pues
	// al repartir cuando caiga una piedra alli, se podra pasar al mancala y obtener turno extra
	
	protected int ultimo_hueco(){
		int ultimo= 0;
		if (HOYOSINICIALES==6){
			if (PIEDRASINICIALES == 3){
				if (tablero[5] == 0)
					ultimo += 3;
				if (tablero[12] == 0)
					ultimo -= 3;
			}
			if (PIEDRASINICIALES == 4){
				if (tablero[5] == 0)
					ultimo += 3;
				if (tablero[12] == 0)
					ultimo -= 3;
			}
			if (PIEDRASINICIALES == 5){
				if (tablero[5] == 0)
					ultimo += 3;
				if (tablero[12] == 0)
					ultimo -= 3;
			}
			if (PIEDRASINICIALES == 6){
				if (tablero[5] == 0)
					ultimo += 3;
				if (tablero[12] == 0)
					ultimo -= 3;
			}
		}else{
			if (PIEDRASINICIALES == 3){
				if (tablero[4] == 0)
					ultimo += 3;
				if (tablero[10] == 0)
					ultimo -= 3;
			}
			if (PIEDRASINICIALES == 4){
				if (tablero[4] == 0 )
					ultimo += 3;
				if (tablero[10] == 0 )
					ultimo -= 3;
			}
			if (PIEDRASINICIALES == 5){
				if (tablero[4] == 0 )
					ultimo += 3;
				if (tablero[10] == 0 )
					ultimo -= 3;
			}
			if (PIEDRASINICIALES == 6){
				if (tablero[4] == 0 )
					ultimo += 3;
				if (tablero[10] == 0 )
					ultimo -= 3;
			}
			
			
		}
		return ultimo;
		
	}
	
	// La funcion enfrente devuelve las piedras de enfrente del jugador;
	
	public int enfrente (int pos){

		if (HOYOSINICIALES == 5){
			if (pos == 0){
				return tablero[10];
			}
			if (pos == 1){
				return tablero[9];
			}
			if (pos == 2){
				return tablero[8];
			}
			if (pos == 3){
				return tablero[7];
			}
			if (pos == 4){
				return tablero[6];
			}
		}
		else{
			if (pos == 0){
				return tablero[12];
			}
			if (pos == 1){
				return tablero[11];
			}
			if (pos == 2){
				return tablero[10];
			}
			if (pos == 3){
				return tablero[9];
			}
			if (pos == 4){
				return tablero[8];
			}
			if (pos == 5){
				return tablero[7];
			}
		}
		return 0;
	}
	
	
	// La funcion robar es una funcion auxiliar de la funcion nomeroban, que devuelve la
	// piedras de enfrente del hoyo en que cae la ultima piedra si hay robo
	
	public int robar(int posicion,int cantidad){
		int piedras = 0;
		int pos = 0;
		if (HOYOSINICIALES == 5){
			if(cantidad < 13){
				pos = posicion + cantidad;
				if (pos > 11){
					pos = pos - 12;
				}
				if (pos>=0 && pos<5 && tablero[pos]==0) 
					piedras = enfrente(pos);
			}
		}
		if (HOYOSINICIALES == 6){
			if(cantidad < 15){
				pos = posicion + cantidad;
				if (pos > 13){
					pos = pos - 14;
				}
				if (pos>=0 && pos<6 && tablero[pos]==0) 
					piedras = enfrente(pos);
			}
		}
		
		return piedras;
	}
	
	
	// La funcion nomeroban, valora que tras realizarse el movimiento, el jugador contrario
	// realice algun movimiento que captures piedras de un hoyo del jugador.
	
	public int nomeroban(){
		int robo = 0;
		if (HOYOSINICIALES == 5){
			for (int i=0;i<5;i++){
				robo+=  robar (i,tablero[i]); 
		
					}
				}
			
		else if (HOYOSINICIALES == 6){
			for (int i=0;i<5;i++){
				robo+=  robar (i,tablero[i]); 
					
						}
					}		
		return robo;		
	}
	
	
	// La funcion MancalaGanador, comprueba que la maquina tenga mas de la mitad
	// de las piedras en juego y por tanto es ganadora y penaliza que sea el jugador
	// quien lo tenga
	
	protected int mancalaGanador(){
		int ganador = 0;
		if (HOYOSINICIALES==6){
			if (PIEDRASINICIALES == 3){
				if (tablero[6] >= 19 )
					ganador += 1000;
				if (tablero[13] >= 19 )
					ganador -= 1000;
			}
			if (PIEDRASINICIALES == 4){
				if (tablero[6] >= 25 )
					ganador += 1000;
				if (tablero[13] >= 25 )
					ganador -= 1000;
			}
			if (PIEDRASINICIALES == 5){
				if (tablero[6] >= 31 )
					ganador += 1000;
				if (tablero[13] >= 31 )
					ganador -= 1000;
			}
			if (PIEDRASINICIALES == 6){
				if (tablero[6] >= 37 )
					ganador += 1000;
				if (tablero[13] >= 37 )
					ganador -= 1000;
			}
		}else{
			if (PIEDRASINICIALES == 3){
				if (tablero[5] >= 16 )
					ganador += 1000;
				if (tablero[11] >= 16 )
					ganador -= 1000;
			}
			if (PIEDRASINICIALES == 4){
				if (tablero[5] >= 21 )
					ganador += 1000;
				if (tablero[11] >= 21 )
					ganador -= 1000;
			}
			if (PIEDRASINICIALES == 5){
				if (tablero[5] >= 26 )
					ganador += 1000;
				if (tablero[11] >= 26 )
					ganador -= 1000;
			}
			if (PIEDRASINICIALES == 6){
				if (tablero[5] >= 31 )
					ganador += 1000;
				if (tablero[11] >= 31 )
					ganador -= 1000;
			}
			
			
		}
		return ganador;
	}
	
	// Funcion de evaluacion estatica
	@Override
	protected int valor() 
	{
		int valorActual = 0;
		valorActual += suma_piedras()+cuenta_huecos()+ ultimo_hueco()+ nomeroban() + mancalaGanador();
		return valorActual;
	}
	
	/**
	 * Realiza un movimiento dado un numero de hoyo. 
	 */
	protected void Mover(int hoyo){
		Mover(new KalahaMover(hoyo));
	}

	@Override
	protected void Mover(Mover m) 
	{
		KalahaMover km = (KalahaMover) m;
		int hoyo = km.hoyo;	
		int stones = tablero[hoyo];
		tablero[hoyo] = 0;
		int hoyofin = 0;
		
		if (HOYOSINICIALES == 6){
		for (int i = stones; i > 0; i--) 
		{
			hoyo++;
			if (hoyo > 13)
				hoyo = 0;
			if (maxTurn && hoyo == 13)
				hoyo = 0;
			if (!maxTurn && hoyo == 6)
				hoyo = 7;
			hoyofin = hoyo;
			this.tablero[hoyo] += 1;
		}
		}else{
		for (int i = stones; i > 0; i--) 
		{
			hoyo++;
			if (hoyo > 11)
				hoyo = 0;
			if (maxTurn && hoyo == 11)
				hoyo = 0;
			if (!maxTurn && hoyo == 5)
				hoyo = 6;
			hoyofin = hoyo;
			this.tablero[hoyo] += 1;
		}			
		}
		// Comprueba si la ultima piedra cae en un hoyo vacio del jugador que realiza el movimiento, y el oponente contiene semillas,
		// las semillas son capturadas por el jugador y las lleva a su mancala.
		if (HOYOSINICIALES == 6){
		if (this.tablero[hoyofin] == 1 && hoyofin != 6 && hoyofin != 13 && this.tablero[-1 * (hoyofin - 6) + 6] != 0)
		{
			int oppositePool = -1 * (hoyofin - 6) + 6;
			if (maxTurn && hoyofin < 6) 
			{
				this.tablero[6] += this.tablero[oppositePool] + this.tablero[hoyofin];
				this.tablero[oppositePool] = 0;
				this.tablero[hoyofin] = 0;
			}
			if (!maxTurn && hoyofin > 6 && hoyofin < 13) 
			{
				this.tablero[13] += this.tablero[oppositePool] + this.tablero[hoyofin];
				this.tablero[oppositePool] = 0;
				this.tablero[hoyofin] = 0;
			}
		}
		}else{
		if (this.tablero[hoyofin] == 1 && hoyofin != 5 && hoyofin != 11 && this.tablero[-1 * (hoyofin - 5) + 5] != 0)
		{
			int oppositePool = -1 * (hoyofin - 5) + 5;
			if (maxTurn && hoyofin < 5) 
			{
				this.tablero[5] += this.tablero[oppositePool] + this.tablero[hoyofin];
				this.tablero[oppositePool] = 0;
				this.tablero[hoyofin] = 0;
			}
			if (!maxTurn && hoyofin > 5 && hoyofin < 11) 
			{
				this.tablero[11] += this.tablero[oppositePool] + this.tablero[hoyofin];
				this.tablero[oppositePool] = 0;
				this.tablero[hoyofin] = 0;
			}
		}	
		}
		// Cuando un jugador se queda sin piedras en sus hoyos, la partida finaliza. 
		// El otro jugador lleva todas las piedras restantes en sus hoyos a su mancala, y gana
		// el jugador con mas piedras en su mancala.
		if (HOYOSINICIALES == 6){
		if (tablero[0] + tablero[1] + tablero[2] + tablero[3] + tablero[4] + tablero[5] == 0) 
		{
			for (int i = 7; i < 13; i++) 
			{
				int addStones = tablero[i];
				tablero[i] = 0;
				if (maxTurn)
					tablero[13] += addStones;
				else
					tablero[6] += addStones;
			}
		}
		if (tablero[7] + tablero[8] + tablero[9] + tablero[10] + tablero[11] + tablero[12] == 0) 
		{
			for (int i = 0; i < 6; i++) 
			{
				int addStones = tablero[i];
				tablero[i] = 0;
				if (!maxTurn)
					tablero[6] += addStones;
				else
					tablero[13] += addStones;
			}
		}
		}else{
			if (tablero[0] + tablero[1] + tablero[2] + tablero[3] + tablero[4] == 0) 
			{
				for (int i = 6; i < 11; i++) 
				{
					int addStones = tablero[i];
					tablero[i] = 0;
					if (maxTurn)
						tablero[11] += addStones;
					else
						tablero[5] += addStones;
				}
			}
			if (tablero[6] + tablero[7] + tablero[8] + tablero[9] + tablero[10] == 0) 
			{
				for (int i = 0; i < 5; i++) 
				{
					int addStones = tablero[i];
					tablero[i] = 0;
					if (!maxTurn)
						tablero[5] += addStones;
					else
						tablero[11] += addStones;
				}
			}	
		}
		// Si la ultima piedras cae en el mancala del jugador, el jugador obtiene un turno extra.
		if (HOYOSINICIALES == 6){
		if (hoyofin == 6 && maxTurn) this.maxTurn = !this.maxTurn;
		if (hoyofin == 13 && !maxTurn) this.maxTurn = !this.maxTurn;
		this.maxTurn = !this.maxTurn;
		}else{
		if (hoyofin == 5 && maxTurn) this.maxTurn = !this.maxTurn;
		if (hoyofin == 11 && !maxTurn) this.maxTurn = !this.maxTurn;
		this.maxTurn = !this.maxTurn;
		}
			
	}
	
	@Override
	protected Posicion copiar() 
	{
		KalahaPosicion kp = new KalahaPosicion();
		kp.maxTurn = maxTurn;
		kp.tablero = tablero.clone();
		return kp;
	}
	
	/**
	 * Se usa para optimizar el horizonte del turno de max
	 * Si es el turno de max, la busqueda alpha-beta es de mayor profundidad, en otro caso no.
	 * @return Devuelve true si es el turno de max.
	 */
	@Override
	public boolean unclear(){
		return maxTurn;
	}

	@Override
	protected List<Mover> MovimientosPosibles()
	{
		List<Mover> npmList = new ArrayList<Mover>();
		if (!gameOver()) 
		{
			if (maxTurn) 
			{	
				if (HOYOSINICIALES == 6){
				for (int hoyoNumber = 0; hoyoNumber <= 5; hoyoNumber++)			
					if (tablero[hoyoNumber] != 0)
						npmList.add(new KalahaMover(hoyoNumber));
				}else{
				for (int hoyoNumber = 0; hoyoNumber <= 4; hoyoNumber++)			
					if (tablero[hoyoNumber] != 0)
						npmList.add(new KalahaMover(hoyoNumber));	
				}
			}
			else
			{
				if (HOYOSINICIALES == 6){				
				for (int hoyoNumber = 7; hoyoNumber <= 12; hoyoNumber++)
					if (tablero[hoyoNumber] != 0)
						npmList.add(new KalahaMover(hoyoNumber));
				}else{
				for (int hoyoNumber = 6; hoyoNumber <= 11; hoyoNumber++)
					if (tablero[hoyoNumber] != 0)
						npmList.add(new KalahaMover(hoyoNumber));	
				}
			}
		}
		return npmList;
	}
		
	@Override
	/**
	 * Comprueba si el mancala del jugador es mas de 6 veces las piedras iniciales por hueco 
	 * (si posee mas de la mitad) o si ambos jugadores tienen las mismas, entonces acaba el juego.
	 */
	protected boolean gameOver()
	{
		if (HOYOSINICIALES == 5){
			return (tablero[5] > 5 * PIEDRASINICIALES || tablero[11] > 5 * PIEDRASINICIALES)    || 
		       (tablero[5] == 5 * PIEDRASINICIALES && tablero[11] == 5 * PIEDRASINICIALES);
		}
		return (tablero[6] > 6 * PIEDRASINICIALES || tablero[13] > 6 * PIEDRASINICIALES)    || 
		       (tablero[6] == 6 * PIEDRASINICIALES && tablero[13] == 6 * PIEDRASINICIALES);
	}
	
	/**
	 * Metodo (para GUI) para imprimir la KalahaPositon.
	 *//*
	public String toString() 
	{
		String s = "\n";
		s += "      5  4  3  2  1  0\n     ";

		for (int i = 5; i > -1; i--) 
		{
			s += "(" + tablero[i] + ')';
		}
		s += "\n";
		s += "6 (" + tablero[6] + ')' + "                  " + '(' + tablero[13] + ") 13" + '\n' + "     ";
		for (int i = 7; i < 13; i++) 
		{
			s += "(" + tablero[i] + ')';
		}
		s += "\n ";
		s += "     7  8  9 10 11 12";

		return s;
	}
*/
	public int evaluarPosicion() {
		// TODO Auto-generated method stub
		return 0;
	}
}
