78. Inteligencia Artificial (7).Lógica para evitar un jaque(2)
- En este capítulo del curso de programación en c# con visual studio 2017 vamos a continuar con nuestra serie de entradas relacionadas con un tema de moda: la inteligencia artificial. En la entrada anterior enseñamos a nuestro agente dos mecanismos para evitar el jaque de nuestro adversario.
- En esta entrada aprenderemos a evitar el jaque del rival interponiendo una pieza en el camino entre el rey y la pieza que nos ataca .Existen varias casuísticas que son las que implementamos en el vídeo. Se ven mejor con unas imágenes. Recordad que nuestro tablero al fin y al cabo es una matriz de de 8x8.
- En esta entrada aprenderemos a evitar el jaque del rival interponiendo una pieza en el camino entre el rey y la pieza que nos ataca .Existen varias casuísticas que son las que implementamos en el vídeo. Se ven mejor con unas imágenes. Recordad que nuestro tablero al fin y al cabo es una matriz de de 8x8.
- Jaque con una pieza que hace ataque en dirección vertical a nuestro rey
- Jaque con un pieza que ataca en dirección horizontal a nuestro rey
- En el vídeo os muestro el código aplicado para evitar el jaque cuando se produzca alguna de las situaciones mostradas en las imágenes:
- Una vez comprendido el objetivo de este capítulo os dejo el código de las dos funciones que hemos modificado para mejorar la lógica de nuestro agente en situaciones de jaque.
//Obtener todos los posibles movimientos de todas las piezas negras y de momento genero un movimiento aleatorio
#region Nuevo
public void generarMovimientoAleatorio()
{
int posinicial = 0;
int columnaJaque = 0;
ArrayList arrayPiezas = new ArrayList();
ArrayList arrayPosInicialPiezas = new ArrayList();
ArrayList arrayValorMovimiento = new ArrayList();
ArrayList arraypiezasTaponanJaque = new ArrayList();
ArrayList arraypiezasPosInicialTaponanJaque = new ArrayList();
ArrayList arrayPosicionpiezasTaponanJaque = new ArrayList();
int posicionJaque = 0;
int posicionReyJaque = 0;
Boolean SiJaque = false;
Pieza piezaAux = new Pieza();
Pieza reyAux = null;
//Si nos dan jaque buscamos que pieza nos lo esta dando y en que posicion por si al calcular los movimientos de las piezas negras pudieramos comernos la pieza.También seleccionamos la pieza rey.
if (motor.tablero.jaqueNegro)
{
foreach (Cuadrado c in motor.tablero.Escaques)
{
//Guardamos en variable auxiliar la pieza rey negro
if (c.pieza != null && c.pieza.colorPieza == ColorPieza.Negro && c.pieza.tipoPieza == TipoPiezaAjedrez.Rey )
reyAux = c.pieza;
//Buscamos que pieza nos esta dando jaque
if (c.pieza != null && c.pieza.colorPieza == ColorPieza.Blanco && c.pieza.DandoJaque == true)
{
SiJaque = true;
piezaAux = c.pieza;
}
if(!SiJaque)
posicionJaque++;
if(reyAux==null)
posicionReyJaque++;
}
if (!SiJaque)
posicionJaque = -1;
}
//Recorremos el tablero y guardamos la posicion de las piezas negras con algun movimiento valido
foreach (Cuadrado c in motor.tablero.Escaques)
{
if (c.pieza != null && c.pieza.colorPieza == ColorPieza.Negro && c.pieza.movimientosValidos.Count > 0)
{
arrayPiezas.Add(c.pieza);
arrayPosInicialPiezas.Add(posinicial);
arrayValorMovimiento.Add(valorMovimiento(c.pieza, motor.tablero, posicionJaque,posinicial));
//Vemos el tipo de pieza que nos esta dando jaque.Hemos obtenido anteriormente su posición y la del rey.
//Necesitamos obtener todos los movimientos de las piezas negras.Las que coincidan en trayectoria mover la de menor peso
if (SiJaque)
{
for (int i = 0; i < c.pieza.movimientosValidos.Count; i++)
{
//Jaque cuando la posicion del rey en la matriz sea menor que la de la pieza que ataca
if (posicionJaque > posicionReyJaque)
{
columnaJaque = Convert.ToByte(posicionReyJaque % 8);
//Jaque en vertical
for (int j = posicionJaque; j >= posicionReyJaque && Convert.ToByte(posicionJaque % 8)== columnaJaque; j = j - 8)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
//jaque en horizontal.Deben estar en la misma fila de la matriz por lo tanto al diferencia no puede ser mayor a 7
if ((posicionJaque - posicionReyJaque <= 7) && (posicionJaque - posicionReyJaque >= 0))
{
for (int j = posicionReyJaque; j <= posicionJaque; j++)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
}
//jaque en diagonal.Cuando la resta entre la posicion de la pieza que da jaque y el rey da 9 o multiplo de 9 o da 7 o múltiplo de 7
if ((posicionJaque - posicionReyJaque) % 9 ==0 )
{
for (int j = posicionJaque; j >= posicionReyJaque; j = j - 9)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
}
if ((posicionJaque - posicionReyJaque) % 7 == 0)
{
for (int j = posicionJaque; j >= posicionReyJaque; j = j - 7)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
}
} //Jaque cuando la posicion del rey en la matriz sea mayor que la de la pieza que ataca
else
{
columnaJaque = Convert.ToByte(posicionReyJaque % 8);
//Jaque en vertical
for (int j = posicionReyJaque; j <= posicionJaque && Convert.ToByte(posicionReyJaque % 8) == columnaJaque; j = j + 8)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
//jaque en horizontal.Deben estar en la misma fila de la matriz por lo tanto al diferencia no puede ser mayor a 7
if ((posicionReyJaque - posicionJaque <= 7) && (posicionReyJaque - posicionJaque >=0))
{
for (int j = posicionJaque; j <= posicionReyJaque; j++)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
}
//jaque en diagonal.Cuando la resta entre la posicion del rey y la pieza que da jaque da 9 o multiplo de 9 o da 7 o múltiplo de 7
if (( posicionReyJaque- posicionJaque) % 9 == 0)
{
for (int j = posicionReyJaque; j >= posicionJaque; j = j - 9)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
}
if ((posicionReyJaque - posicionJaque) % 7 == 0)
{
for (int j = posicionReyJaque; j >= posicionJaque; j = j - 7)
{
if (c.pieza.movimientosValidos.ElementAt(i) == j)
{
arraypiezasTaponanJaque.Add(c.pieza);
arraypiezasPosInicialTaponanJaque.Add(posinicial);
arrayPosicionpiezasTaponanJaque.Add(j);
}
}
}
}
}
}
}
posinicial++;
}
//Recorremos el array con los valores de los movimientos y elegimos el que mayor valor tenga si no elegimos un movimiento aleatorio
int maxValor = 0;
int posicionArray = 0;
for (int i = 0; i < arrayValorMovimiento.Count; i++)
{
if (((MovimientoSeleccionado)arrayValorMovimiento[i]).ValorMovimiento > maxValor)
{
maxValor = ((MovimientoSeleccionado)arrayValorMovimiento[i]).ValorMovimiento;
posicionArray = i;
}
}
byte columnainicio = 0;
byte filaInicio = 0;
byte columnaDestino = 0;
byte filaDestino = 0;
int posicionInicial = 0;
int posPiezaTapona = 0;
int menorValor = 1000000;
//Si nos estan dando jaque y no nos podemos comer la pieza que nos lo esta dando movemos el rey o ponemos una delante si vale menos que la que da jaque
if (SiJaque && maxValor != 100000)
{
if (arraypiezasTaponanJaque.Count > 0)
{
for (int i = 0; i < arraypiezasTaponanJaque.Count; i++)
{
if ( ((Pieza) arraypiezasTaponanJaque[i]).valorPieza< menorValor)
{
menorValor = ((Pieza)arraypiezasTaponanJaque[i]).valorPieza;
posPiezaTapona = i;
}
}
posicionInicial = Convert.ToInt32(arraypiezasPosInicialTaponanJaque[posPiezaTapona]);
columnainicio = Convert.ToByte(posicionInicial % 8);
filaInicio = Convert.ToByte(posicionInicial / 8);
columnaDestino = Convert.ToByte(Convert.ToInt32(arrayPosicionpiezasTaponanJaque[posPiezaTapona]) % 8);
filaDestino = Convert.ToByte(Convert.ToInt32(arrayPosicionpiezasTaponanJaque[posPiezaTapona]) / 8);
}
else
{
if(reyAux.movimientosValidos.Count>0)
{
Random random = new Random();
columnainicio = Convert.ToByte(posicionReyJaque % 8);
filaInicio = Convert.ToByte(posicionReyJaque / 8);
int posicionAleatoriaRey = random.Next(0, reyAux.movimientosValidos.Count);
columnaDestino = Convert.ToByte((reyAux.movimientosValidos.ElementAt(posicionAleatoriaRey) % 8));
filaDestino = Convert.ToByte((reyAux.movimientosValidos.ElementAt(posicionAleatoriaRey) / 8));
}
}
}
else
{
//Si no nos aporta valor movemos cualquier ficha aleatoriamente
if (maxValor > 0)
{
posicionInicial = Convert.ToInt32(arrayPosInicialPiezas[posicionArray]);
columnainicio = Convert.ToByte(posicionInicial % 8);
filaInicio = Convert.ToByte(posicionInicial / 8);
columnaDestino = Convert.ToByte(((MovimientoSeleccionado)arrayValorMovimiento[posicionArray]).PosicionDestino % 8);
filaDestino = Convert.ToByte(((MovimientoSeleccionado)arrayValorMovimiento[posicionArray]).PosicionDestino / 8);
}
else
{
//Seleccionamos aleatoriamente la pieza a mover y obtenemos columna y fila inicial
Random random = new Random();
int piezaAletoria = random.Next(0, arrayPiezas.Count);
posicionInicial = Convert.ToInt32(arrayPosInicialPiezas[piezaAletoria]);
columnainicio = Convert.ToByte(posicionInicial % 8);
filaInicio = Convert.ToByte(posicionInicial / 8);
////Dentro de los movimientos validos selecionamos aleatoriamente alguno de ellos.Primero hacemos un random de los posible movimientos y
////luego seleccionamos uno de ellos
int posicionAleatoria = random.Next(0, ((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.Count);
columnaDestino = Convert.ToByte(((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.ElementAt(posicionAleatoria) % 8);
filaDestino = Convert.ToByte(((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.ElementAt(posicionAleatoria) / 8);
}
}
motor.moverPieza(columnainicio, filaInicio, columnaDestino, filaDestino);
}
//Funcion para calcular el valor de un movimiento y la posicion detino que la almacenamos en el nuevo objeto MovimientoSeleccionado
private MovimientoSeleccionado valorMovimiento(Pieza piezaMover, Tablero tablero , int PosicionJaque, int posicionInicialPiezaMovemos )
{
MovimientoSeleccionado mov = new MovimientoSeleccionado();
mov.ValorMovimiento = 0;
int posicionpiezaBlanca = 0;
int valorMovimientoAux = 0;
//si en alguno de los posibles movimientos hay una pieza que se pueda comer guardamos su peso y posicion
for (int i = 0; i < piezaMover.movimientosValidos.Count; i++)
{
posicionpiezaBlanca = 0;
foreach (Cuadrado c in motor.tablero.Escaques)
{
if (c.pieza != null && c.pieza.colorPieza == ColorPieza.Blanco && piezaMover.movimientosValidos.ElementAt(i)==posicionpiezaBlanca)
{
//Si nos podemos comer una pieza que nos esta haciendo jaque le damos el máximo valor
if (posicionpiezaBlanca == PosicionJaque)
valorMovimientoAux = 100000;
else
{
if(c.pieza.valorPieza >= tablero.Escaques[posicionInicialPiezaMovemos].pieza.valorPieza)
valorMovimientoAux = c.pieza.valorPieza;
}
if (valorMovimientoAux > mov.ValorMovimiento)
mov.ValorMovimiento = valorMovimientoAux;
mov.PosicionDestino = posicionpiezaBlanca;
}
posicionpiezaBlanca++;
}
}
return mov;
}
No hay comentarios:
Publicar un comentario