74. Inteligencia Artificial (3). Analizando el motor del juego de Ajedrez
- 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 este capítulo del curso continuamos con el análisis del motor del juego. Desgranaremos el funcionamiento de algunas de las clases que controlan los movimientos de nuestro ajedrez.
- En concreto en esta entrada vemos el funcionamiento de las últimas clases del motor interno que nos quedaban por analizar : MovimientoValidoPieza.cs , Tablero.cs y Engine.cs. También os muestro brevemente la clases que utilizamos para pintar en pantalla el tablero y como inicializamos la posición de las piezas en el tablero.En el vídeo lo podemos ver:
Os dejo el código de las clases mencionadas en el vídeo:
- MovimientoValidoPieza.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AjedrezIA.Motor
{
internal static class MovimientosValidosPiezas
{
internal static bool[] tableroAtacanNegras;
private static byte poscionReynegro;
internal static bool[] tableroAtacanBlancas;
private static byte posicionReyBlanco;
private static void analizarMovimientoPeon(Tablero tablero, byte posicionDestino, Pieza piezaMovimiento)
{
//Como el peón sólo mata en diagonal.La captura al paso es un escenario especial
if (tablero.anteriorPosicion > 0)
{
if (piezaMovimiento.colorPieza != tablero.capturaAlPasoColor)
{
if (tablero.anteriorPosicion == posicionDestino)
{
//Posible captura al paso
piezaMovimiento.movimientosValidos.Push(posicionDestino);
if (piezaMovimiento.colorPieza == ColorPieza.Blanco)
tableroAtacanBlancas[posicionDestino] = true;
else
tableroAtacanNegras[posicionDestino] = true;
}
}
}
Pieza piezaAtacada = tablero.Escaques[posicionDestino].pieza;
if (piezaAtacada == null)
return;
//Se ataca este cuadrado
if (piezaMovimiento.colorPieza == ColorPieza.Blanco)
{
tableroAtacanBlancas[posicionDestino] = true;
//Si la pieza es del mismo color
if (piezaAtacada.colorPieza == piezaMovimiento.colorPieza)
{
piezaAtacada.valorDefensa += piezaMovimiento.valorAccionPieza;
return;
}
piezaAtacada.valorAtaque += piezaMovimiento.valorAccionPieza;
//Si es un rey se hace jaque
if (piezaAtacada.tipoPieza == TipoPiezaAjedrez.Rey)
tablero.jaqueNegro = true;
else
piezaMovimiento.movimientosValidos.Push(posicionDestino);
}
else
{
tableroAtacanNegras[posicionDestino] = true;
//Si la pieza es del mismo color
if (piezaAtacada.colorPieza == piezaMovimiento.colorPieza)
{
piezaAtacada.valorDefensa += piezaMovimiento.valorAccionPieza;
return;
}
piezaAtacada.valorAtaque += piezaMovimiento.valorAccionPieza;
//Si es un rey se hace jaque
if (piezaAtacada.tipoPieza == TipoPiezaAjedrez.Rey)
tablero.jaqueBlanco = true;
else
piezaMovimiento.movimientosValidos.Push(posicionDestino);
}
return;
}
private static bool analizarMovimiento(Tablero tablero, byte posicionDestino, Pieza piezaMovimiento)
{
//Si no soy un peón muevo y puedo atacar
if (piezaMovimiento.colorPieza == ColorPieza.Blanco)
tableroAtacanBlancas[posicionDestino] = true;
else
tableroAtacanNegras[posicionDestino] = true;
//Si no hay ninguna pieza allí, puedo matar potencialmente
if (tablero.Escaques[posicionDestino].pieza == null)
{
piezaMovimiento.movimientosValidos.Push(posicionDestino);
return true;
}
Pieza piezaAtacada = tablero.Escaques[posicionDestino].pieza;
//Si la pieza es de diferente color
if (piezaAtacada.colorPieza != piezaMovimiento.colorPieza)
{
piezaAtacada.valorAtaque += piezaMovimiento.valorAccionPieza;
//Si hay un rey hacemos jaque
if (piezaAtacada.tipoPieza == TipoPiezaAjedrez.Rey)
{
if (piezaAtacada.colorPieza == ColorPieza.Negro)
{
tablero.jaqueNegro = true;
}
else
{
tablero.jaqueBlanco = true;
}
}
else
{
//añadir como movimiento válido
piezaMovimiento.movimientosValidos.Push(posicionDestino);
}
//No podemos seguir moviendonos
return false;
}
piezaAtacada.valorDefensa += piezaMovimiento.valorAccionPieza;
return false;
}
private static void chequearMovimientosValidosPeon(List<byte> movimientos, Pieza piezaMoviendose, byte posicionOrigen,Tablero tablero, byte cont)
{
for (byte i = 0; i < cont; i++)
{
byte posDestino = movimientos[i];
if (posDestino % 8 != posicionOrigen % 8)
{
//Si no hay ninguna pieza es una muerte potencial
analizarMovimientoPeon(tablero, posDestino, piezaMoviendose);
if (piezaMoviendose.colorPieza == ColorPieza.Blanco)
{
tableroAtacanBlancas[posDestino] = true;
}
else
{
tableroAtacanNegras[posDestino] = true;
}
}
// si tenemos algo enfrente peón no podemos mover
else if (tablero.Escaques[posDestino].pieza != null)
return;
//si tenemos algo enfrente peón podemos mover
else
piezaMoviendose.movimientosValidos.Push(posDestino);
}
}
private static void generarMovimientosValidosRey(Pieza pieza, Tablero tablero, byte posicionOrigen)
{
if (pieza == null)
{
return;
}
for (byte i = 0; i < MovimientoArrays.ReytotalMovimientos[posicionOrigen]; i++)
{
byte posicionDestino = MovimientoArrays.ReyMovimientos[posicionOrigen].Movimientos[i];
if (pieza.colorPieza == ColorPieza.Blanco)
{
//No puedo moverme porque estoy siendo atacado
if (tableroAtacanNegras[posicionDestino])
{
tableroAtacanBlancas[posicionDestino] = true;
continue;
}
}
else
{
if (tableroAtacanBlancas[posicionDestino])
{
tableroAtacanNegras[posicionDestino] = true;
continue;
}
}
analizarMovimiento(tablero, posicionDestino, pieza);
}
}
private static void generarMovimientosValidosEnroque(Tablero tablero, Pieza rey)
{
if (rey == null)
return;
if (rey.Movida)
return;
if (rey.colorPieza == ColorPieza.Blanco && tablero.enroqueBlanco)
return;
if (rey.colorPieza == ColorPieza.Negro && tablero.enroqueNegro)
return;
if (rey.colorPieza == ColorPieza.Negro && tablero.jaqueNegro)
return;
if (rey.colorPieza == ColorPieza.Blanco && tablero.jaqueBlanco)
return;
//Chequeo los posibles enroques
if (rey.colorPieza == ColorPieza.Blanco)
{
if (tablero.jaqueBlanco)
return;
if (tablero.Escaques[63].pieza != null)
{
//Comprobar que la torre sigue en poscion correcta
if (tablero.Escaques[63].pieza.tipoPieza == TipoPiezaAjedrez.Torre)
{
if (tablero.Escaques[63].pieza.colorPieza == rey.colorPieza)
{
if (tablero.Escaques[62].pieza == null)
{
if (tablero.Escaques[61].pieza == null)
{
if (tableroAtacanNegras[61] == false &&
tableroAtacanNegras[62] == false)
{
rey.movimientosValidos.Push(62);
tableroAtacanBlancas[62] = true;
}
}
}
}
}
}
if (tablero.Escaques[56].pieza != null)
{
//Comprobar que la torre sigue en poscion correcta
if (tablero.Escaques[56].pieza.tipoPieza == TipoPiezaAjedrez.Torre)
{
if (tablero.Escaques[56].pieza.colorPieza == rey.colorPieza)
{
if (tablero.Escaques[57].pieza == null)
{
if (tablero.Escaques[58].pieza == null)
{
if (tablero.Escaques[59].pieza == null)
{
if (tableroAtacanNegras[58] == false &&
tableroAtacanNegras[59] == false)
{
rey.movimientosValidos.Push(58);
tableroAtacanBlancas[58] = true;
}
}
}
}
}
}
}
}
else if (rey.colorPieza == ColorPieza.Negro)
{
if (tablero.jaqueNegro)
{
return;
}
//scenario 1:
if (tablero.Escaques[7].pieza != null)
{
//Comprobar que la torre sigue en poscion correcta
if (tablero.Escaques[7].pieza.tipoPieza == TipoPiezaAjedrez.Torre
&& !tablero.Escaques[7].pieza.Movida)
{
if (tablero.Escaques[7].pieza.colorPieza == rey.colorPieza)
{
if (tablero.Escaques[6].pieza == null)
{
if (tablero.Escaques[5].pieza == null)
{
if (tableroAtacanBlancas[5] == false && tableroAtacanBlancas[6] == false)
{
rey.movimientosValidos.Push(6);
tableroAtacanNegras[6] = true;
}
}
}
}
}
}
//scenario 2:
if (tablero.Escaques[0].pieza != null)
{
//Comprobar que la torre sigue en poscion correcta
if (tablero.Escaques[0].pieza.tipoPieza == TipoPiezaAjedrez.Torre && !tablero.Escaques[0].pieza.Movida)
{
if (tablero.Escaques[0].pieza.colorPieza == rey.colorPieza)
{
if (tablero.Escaques[1].pieza == null)
{
if (tablero.Escaques[2].pieza == null)
{
if (tablero.Escaques[3].pieza == null)
{
if (tableroAtacanBlancas[2] == false &&
tableroAtacanBlancas[3] == false)
{
//Ok looks like move is valid lets add it
rey.movimientosValidos.Push(2);
tableroAtacanNegras[2] = true;
}
}
}
}
}
}
}
}
}
internal static void generarMovimientosValidos(Tablero tablero)
{
// Reset tablero
tablero.jaqueNegro = false;
tablero.jaqueBlanco = false;
tableroAtacanBlancas = new bool[64];
tableroAtacanNegras = new bool[64];
//Generate Moves
for (byte x = 0; x < 64; x++)
{
Cuadrado escaque = tablero.Escaques[x];
if (escaque.pieza == null)
continue;
escaque.pieza.movimientosValidos = new Stack<byte>(escaque.pieza.ultimoMovimiento);
switch (escaque.pieza.tipoPieza)
{
case TipoPiezaAjedrez.Peon:
{
if (escaque.pieza.colorPieza == ColorPieza.Blanco)
{
chequearMovimientosValidosPeon(MovimientoArrays.peonBlancoMovimientos[x].Movimientos, escaque.pieza, x,tablero,MovimientoArrays.peonBlancoTotalMovimientos[x]);
break;
}
if (escaque.pieza.colorPieza == ColorPieza.Negro)
{
chequearMovimientosValidosPeon(MovimientoArrays.peonNegroMovimientos[x].Movimientos, escaque.pieza, x,tablero,MovimientoArrays.peonNegroTotalMovimientos[x]);
break;
}
break;
}
case TipoPiezaAjedrez.Caballo:
{
for (byte i = 0; i < MovimientoArrays.caballoTotalMovimientos[x]; i++)
{
analizarMovimiento(tablero, MovimientoArrays.caballoMovimientos[x].Movimientos[i], escaque.pieza);
}
break;
}
case TipoPiezaAjedrez.Alfil:
{
for (byte i = 0; i < MovimientoArrays.AlfilTotalMovimientos1[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.AlfilMovimientos1[x].Movimientos[i],escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.AlfilTotalMovimientos2[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.AlfilMovimientos2[x].Movimientos[i],escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.AlfilTotalMovimientos3[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.AlfilMovimientos3[x].Movimientos[i], escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.AlfilTotalMovimientos4[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.AlfilMovimientos4[x].Movimientos[i],escaque.pieza) ==false)
{
break;
}
}
break;
}
case TipoPiezaAjedrez.Torre:
{
for (byte i = 0; i < MovimientoArrays.TorreTotalMovimientos1[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.TorreMovimientos1[x].Movimientos[i], escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.TorreTotalMovimientos2[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.TorreMovimientos2[x].Movimientos[i], escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.TorreTotalMovimientos3[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.TorreMovimientos3[x].Movimientos[i], escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.TorreTotalMovimientos4[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.TorreMovimientos4[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
break;
}
case TipoPiezaAjedrez.Reina:
{
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos1[x]; i++)
{
if ( analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos1[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos2[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos2[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos3[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos3[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos4[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos4[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos5[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos5[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos6[x]; i++)
{
if ( analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos6[x].Movimientos[i], escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos7[x]; i++)
{
if ( analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos7[x].Movimientos[i], escaque.pieza) ==false)
{
break;
}
}
for (byte i = 0; i < MovimientoArrays.ReinaTotalMovimientos8[x]; i++)
{
if (analizarMovimiento(tablero, MovimientoArrays.ReinaMovimientos8[x].Movimientos[i], escaque.pieza) == false)
{
break;
}
}
break;
}
case TipoPiezaAjedrez.Rey:
{
if (escaque.pieza.colorPieza == ColorPieza.Blanco)
{
posicionReyBlanco = x;
}
else
{
poscionReynegro = x;
}
break;
}
}
}
if (tablero.quienMovio == ColorPieza.Blanco)
{
generarMovimientosValidosRey(tablero.Escaques[poscionReynegro].pieza, tablero,poscionReynegro);
generarMovimientosValidosRey(tablero.Escaques[posicionReyBlanco].pieza, tablero,posicionReyBlanco);
}
else
{
generarMovimientosValidosRey(tablero.Escaques[posicionReyBlanco].pieza, tablero,posicionReyBlanco);
generarMovimientosValidosRey(tablero.Escaques[poscionReynegro].pieza, tablero,poscionReynegro);
}
//Chquemaos todos para ver si es posible el enroque
generarMovimientosValidosEnroque(tablero, tablero.Escaques[posicionReyBlanco].pieza);
generarMovimientosValidosEnroque(tablero, tablero.Escaques[poscionReynegro].pieza);
}
}
}
- Tablero.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AjedrezIA.Motor
{
class Tablero
{
internal Cuadrado[] Escaques;
internal int Puntuacion;
internal ulong ZobristHash;
internal bool jaqueNegro;
internal bool mateNegro;
internal bool jaqueBlanco;
internal bool mateBlanco;
internal bool TAblas;
internal byte cincuentaMovimientos;
internal byte movimientoRepetido;
internal bool enroqueNegro;
internal bool enroqueBlanco;
internal bool faseFinaljuego;
internal Movimiento ultimoMovimiento;
internal ColorPieza capturaAlPasoColor;
internal byte anteriorPosicion;
internal ColorPieza quienMovio;
internal int contadorMovimientos;
#region Constructores
internal Tablero(string fen) : this()
{
byte posicion = 0;
byte cont = 0;
enroqueBlanco = true;
enroqueNegro = true;
byte espaciadores = 0;
quienMovio = ColorPieza.Blanco;
if (fen.Contains("a3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 40;
}
else if (fen.Contains("b3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 41;
}
else if (fen.Contains("c3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 42;
}
else if (fen.Contains("d3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 43;
}
else if (fen.Contains("e3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 44;
}
else if (fen.Contains("f3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 45;
}
else if (fen.Contains("g3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 46;
}
else if (fen.Contains("h3"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 47;
}
if (fen.Contains("a6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 16;
}
else if (fen.Contains("b6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 17;
}
else if (fen.Contains("c6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 18;
}
else if (fen.Contains("d6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 19;
}
else if (fen.Contains("e6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 20;
}
else if (fen.Contains("f6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 21;
}
else if (fen.Contains("g6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 22;
}
else if (fen.Contains("h6"))
{
capturaAlPasoColor = ColorPieza.Blanco;
anteriorPosicion = 23;
}
foreach (char c in fen)
{
if (posicion < 64 && cont == 0)
{
if (c == '1' && posicion < 63)
posicion++;
else if (c == '2' && posicion < 62)
posicion += 2;
else if (c == '3' && posicion < 61)
posicion += 3;
else if (c == '4' && posicion < 60)
posicion += 4;
else if (c == '5' && posicion < 59)
posicion += 5;
else if (c == '6' && posicion < 58)
posicion += 6;
else if (c == '7' && posicion < 57)
posicion += 7;
else if (c == '8' && posicion < 56)
posicion += 8;
else if (c == 'P')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Peon, ColorPieza.Blanco);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'N')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Caballo, ColorPieza.Blanco);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'B')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Alfil, ColorPieza.Blanco);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'R')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Torre, ColorPieza.Blanco);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'Q')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Reina, ColorPieza.Blanco);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'K')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Rey, ColorPieza.Blanco);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'p')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Peon, ColorPieza.Negro);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'n')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Caballo, ColorPieza.Negro);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'b')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Alfil, ColorPieza.Negro);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'r')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Torre, ColorPieza.Negro);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'q')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Reina, ColorPieza.Negro);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == 'k')
{
Escaques[posicion].pieza = new Pieza(TipoPiezaAjedrez.Rey, ColorPieza.Negro);
Escaques[posicion].pieza.Movida = true;
posicion++;
}
else if (c == '/')
continue;
else if (c == ' ')
cont++;
}
else
{
if (c == 'w')
{
quienMovio = ColorPieza.Blanco;
}
else if (c == 'b')
{
quienMovio = ColorPieza.Negro;
}
else if (c == 'K')
{
if (Escaques[60].pieza != null)
{
if (Escaques[60].pieza.tipoPieza == TipoPiezaAjedrez.Rey)
Escaques[60].pieza.Movida = false;
}
if (Escaques[63].pieza != null)
{
if (Escaques[63].pieza.tipoPieza == TipoPiezaAjedrez.Torre)
Escaques[63].pieza.Movida = false;
}
enroqueBlanco = false;
}
else if (c == 'Q')
{
if (Escaques[60].pieza != null)
{
if (Escaques[60].pieza.tipoPieza == TipoPiezaAjedrez.Rey)
Escaques[60].pieza.Movida = false;
}
if (Escaques[56].pieza != null)
{
if (Escaques[56].pieza.tipoPieza == TipoPiezaAjedrez.Torre)
Escaques[56].pieza.Movida = false;
}
enroqueBlanco = false;
}
else if (c == 'k')
{
if (Escaques[4].pieza != null)
{
if (Escaques[4].pieza.tipoPieza == TipoPiezaAjedrez.Rey)
Escaques[4].pieza.Movida = false;
}
if (Escaques[7].pieza != null)
{
if (Escaques[7].pieza.tipoPieza == TipoPiezaAjedrez.Torre)
Escaques[7].pieza.Movida = false;
}
enroqueNegro = false;
}
else if (c == 'q')
{
if (Escaques[4].pieza != null)
{
if (Escaques[4].pieza.tipoPieza == TipoPiezaAjedrez.Rey)
Escaques[4].pieza.Movida = false;
}
if (Escaques[0].pieza != null)
{
if (Escaques[0].pieza.tipoPieza == TipoPiezaAjedrez.Torre)
Escaques[0].pieza.Movida = false;
}
enroqueNegro = false;
}
else if (c == ' ')
espaciadores++;
else if (c == '1' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 1);
else if (c == '2' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 2);
else if (c == '3' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 3);
else if (c == '4' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 4);
else if (c == '5' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 5);
else if (c == '6' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 6);
else if (c == '7' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 7);
else if (c == '8' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 8);
else if (c == '9' && espaciadores == 4)
cincuentaMovimientos = (byte)((cincuentaMovimientos * 10) + 9);
else if (c == '0' && espaciadores == 4)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 0);
else if (c == '1' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 1);
else if (c == '2' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 2);
else if (c == '3' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 3);
else if (c == '4' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 4);
else if (c == '5' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 5);
else if (c == '6' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 6);
else if (c == '7' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 7);
else if (c == '8' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 8);
else if (c == '9' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 9);
else if (c == '0' && espaciadores == 5)
contadorMovimientos = (byte)((contadorMovimientos * 10) + 0);
}
}
}
internal Tablero()
{
Escaques = new Cuadrado[64];
for (byte i = 0; i < 64; i++)
{
Escaques[i] = new Cuadrado();
}
ultimoMovimiento = new Movimiento();
}
private Tablero(Cuadrado[] escaques)
{
Escaques = new Cuadrado[64];
for (byte x = 0; x < 64; x++)
if (escaques[x].pieza != null)
Escaques[x].pieza = new Pieza(escaques[x].pieza);
}
internal Tablero(int punt) : this()
{
Puntuacion = punt;
}
internal Tablero(Tablero tablero)
{
Escaques = new Cuadrado[64];
for (byte x = 0; x < 64; x++)
{
if (tablero.Escaques[x].pieza != null)
{
Escaques[x] = new Cuadrado(tablero.Escaques[x].pieza);
}
}
faseFinaljuego = tablero.faseFinaljuego;
cincuentaMovimientos = tablero.cincuentaMovimientos;
movimientoRepetido = tablero.movimientoRepetido;
enroqueBlanco = tablero.enroqueBlanco;
enroqueNegro = tablero.enroqueNegro;
jaqueNegro = tablero.jaqueNegro;
jaqueBlanco = tablero.jaqueBlanco;
TAblas = tablero.TAblas;
mateBlanco = tablero.mateBlanco;
mateNegro = tablero.mateNegro;
quienMovio = tablero.quienMovio;
anteriorPosicion = tablero.anteriorPosicion;
capturaAlPasoColor = tablero.capturaAlPasoColor;
ZobristHash = tablero.ZobristHash;
Puntuacion = tablero.Puntuacion;
ultimoMovimiento = new Movimiento(tablero.ultimoMovimiento);
contadorMovimientos = tablero.contadorMovimientos;
}
#endregion
#region Metodos Privados
private static bool PromocionarPeones(Tablero tablero, Pieza pieza, byte posDestino, TipoPiezaAjedrez promocionarAPieza)
{
if (pieza.tipoPieza == TipoPiezaAjedrez.Peon)
{
if (posDestino < 8)
{
tablero.Escaques[posDestino].pieza.tipoPieza = promocionarAPieza;
return true;
}
if (posDestino > 55)
{
tablero.Escaques[posDestino].pieza.tipoPieza = promocionarAPieza;
return true;
}
}
return false;
}
private static void RegistrarCambioPaso(ColorPieza coloPieza, TipoPiezaAjedrez tipoPieza, Tablero tablero, byte posicionOrigen, byte posicionDestino)
{
//Gaurdar cambio de paso si el peon fue movido
if (tipoPieza == TipoPiezaAjedrez.Peon)
{
//resetear cincuenta movimientos mueves el peon
tablero.cincuentaMovimientos = 0;
int diferencia = posicionOrigen - posicionDestino;
if (diferencia == 16 || diferencia == -16)
{
tablero.anteriorPosicion = (byte)(posicionDestino + (diferencia / 2));
tablero.capturaAlPasoColor = coloPieza;
}
}
}
private static bool asignarMovimientoCambioPaso(Tablero tablero, byte posicionDestino, ColorPieza colorPieza)
{
if (tablero.anteriorPosicion == posicionDestino)
{
//posibilidad cambio de paso
if (colorPieza != tablero.capturaAlPasoColor)
{
int pieceLocationOffset = 8;
if (tablero.capturaAlPasoColor == ColorPieza.Blanco)
pieceLocationOffset = -8;
posicionDestino = (byte)(posicionDestino + pieceLocationOffset);
Cuadrado escaque = tablero.Escaques[posicionDestino];
tablero.ultimoMovimiento.piezaComida = new PiezaComida(escaque.pieza.colorPieza, escaque.pieza.tipoPieza, escaque.pieza.Movida, posicionDestino);
tablero.Escaques[posicionDestino].pieza = null;
//Resetear a 50 movimientos si capturamos
tablero.cincuentaMovimientos = 0;
return true;
}
}
return false;
}
private static void Enroque(Tablero tablero, Pieza pieza, byte posicionOrigen, byte posicionDestino)
{
if (pieza.tipoPieza != TipoPiezaAjedrez.Rey)
return;
//Comprobamos si es enroque
if (pieza.colorPieza == ColorPieza.Blanco && posicionOrigen == 60)
{
if (posicionDestino == 62)
{
if (tablero.Escaques[63].pieza != null)
{
tablero.Escaques[61].pieza = tablero.Escaques[63].pieza;
tablero.Escaques[63].pieza = null;
tablero.enroqueBlanco = true;
tablero.ultimoMovimiento.moviendoPiezaSecundaria = new MovimientoPieza(tablero.Escaques[61].pieza.colorPieza, tablero.Escaques[61].pieza.tipoPieza, tablero.Escaques[61].pieza.Movida, 63, 61);
tablero.Escaques[61].pieza.Movida = true;
return;
}
}
//enroque izquierda
else if (posicionDestino == 58)
{
//Movemos torre
if (tablero.Escaques[56].pieza != null)
{
tablero.Escaques[59].pieza = tablero.Escaques[56].pieza;
tablero.Escaques[56].pieza = null;
tablero.enroqueBlanco = true;
tablero.ultimoMovimiento.moviendoPiezaSecundaria = new MovimientoPieza(tablero.Escaques[59].pieza.colorPieza, tablero.Escaques[59].pieza.tipoPieza, tablero.Escaques[59].pieza.Movida, 56, 59);
tablero.Escaques[59].pieza.Movida = true;
return;
}
}
}
else if (pieza.colorPieza == ColorPieza.Negro && posicionOrigen == 4)
{
if (posicionDestino == 6)
{
if (tablero.Escaques[7].pieza != null)
{
tablero.Escaques[5].pieza = tablero.Escaques[7].pieza;
tablero.Escaques[7].pieza = null;
tablero.enroqueNegro = true;
tablero.ultimoMovimiento.moviendoPiezaSecundaria = new MovimientoPieza(tablero.Escaques[5].pieza.colorPieza, tablero.Escaques[5].pieza.tipoPieza, tablero.Escaques[5].pieza.Movida, 7, 5);
tablero.Escaques[5].pieza.Movida = true;
return;
}
}
//enroqe izquierda
else if (posicionDestino == 2)
{
//Ok we are casteling we need to move the Rook
if (tablero.Escaques[0].pieza != null)
{
tablero.Escaques[3].pieza = tablero.Escaques[0].pieza;
tablero.Escaques[0].pieza = null;
tablero.enroqueNegro = true;
tablero.ultimoMovimiento.moviendoPiezaSecundaria = new MovimientoPieza(tablero.Escaques[3].pieza.colorPieza, tablero.Escaques[3].pieza.tipoPieza, tablero.Escaques[3].pieza.Movida, 0, 3);
tablero.Escaques[3].pieza.Movida = true;
return;
}
}
}
return;
}
#endregion
#region Metodos internos
internal Tablero Clonar()
{
Tablero clonarTablero = new Tablero(Escaques);
clonarTablero.faseFinaljuego = faseFinaljuego;
clonarTablero.quienMovio = quienMovio;
clonarTablero.contadorMovimientos = contadorMovimientos;
clonarTablero.cincuentaMovimientos = cincuentaMovimientos;
clonarTablero.ZobristHash = ZobristHash;
clonarTablero.enroqueNegro = enroqueNegro;
clonarTablero.enroqueBlanco = enroqueBlanco;
return clonarTablero;
}
internal static Movimiento MoverPieza(Tablero tablero, byte posicionOrigen, byte posicionDestino, TipoPiezaAjedrez promocionarAPieza)
{
Pieza pieza = tablero.Escaques[posicionOrigen].pieza;
//almacenamos ultimo movimiento
tablero.ultimoMovimiento = new Movimiento();
tablero.cincuentaMovimientos++;
if (pieza.colorPieza == ColorPieza.Negro)
tablero.contadorMovimientos++;
if (tablero.anteriorPosicion > 0)
{
tablero.ultimoMovimiento.capturaAlPasoOcurrio = asignarMovimientoCambioPaso(tablero, posicionDestino, pieza.colorPieza);
}
if (!tablero.ultimoMovimiento.capturaAlPasoOcurrio)
{
Cuadrado escaque = tablero.Escaques[posicionDestino];
if (escaque.pieza != null)
{
tablero.ultimoMovimiento.piezaComida = new PiezaComida(escaque.pieza.colorPieza, escaque.pieza.tipoPieza,escaque.pieza.Movida, posicionDestino);
tablero.cincuentaMovimientos = 0;
}
else
tablero.ultimoMovimiento.piezaComida = new PiezaComida(ColorPieza.Blanco, TipoPiezaAjedrez.Ninguna, false,posicionDestino);
}
tablero.ultimoMovimiento.moviendoPiezaPrincipal = new MovimientoPieza(pieza.colorPieza, pieza.tipoPieza, pieza.Movida, posicionOrigen, posicionDestino);
//eliminamos posción origen
tablero.Escaques[posicionOrigen].pieza = null;
//movemos pieza a la nueva posición
pieza.Movida = true;
pieza.Seleccionada = false;
tablero.Escaques[posicionDestino].pieza = pieza;
tablero.anteriorPosicion = 0;
if (pieza.tipoPieza == TipoPiezaAjedrez.Peon)
{
tablero.cincuentaMovimientos = 0;
RegistrarCambioPaso(pieza.colorPieza, pieza.tipoPieza, tablero, posicionOrigen, posicionDestino);
}
tablero.quienMovio = tablero.quienMovio == ColorPieza.Blanco ? ColorPieza.Negro : ColorPieza.Blanco;
Enroque(tablero, pieza, posicionOrigen, posicionDestino);
if (PromocionarPeones(tablero, pieza, posicionDestino, promocionarAPieza))
tablero.ultimoMovimiento.peonPromocionado = true;
else
tablero.ultimoMovimiento.peonPromocionado = false;
if (tablero.cincuentaMovimientos >= 50)
tablero.TAblas = true;
return tablero.ultimoMovimiento;
}
private static string dameLetraColumna(byte columna)
{
switch (columna)
{
case 0:
return "a";
case 1:
return "b";
case 2:
return "c";
case 3:
return "d";
case 4:
return "e";
case 5:
return "f";
case 6:
return "g";
case 7:
return "h";
default:
return "a";
}
}
internal static string Fen(bool tableroSolo, Tablero tablero)
{
string respuesta = String.Empty;
byte escaquesBlancos = 0;
for (byte x = 0; x < 64; x++)
{
byte posicion = x;
if (tablero.Escaques[posicion].pieza != null)
{
if (escaquesBlancos > 0)
{
respuesta += escaquesBlancos.ToString();
escaquesBlancos = 0;
}
if (tablero.Escaques[posicion].pieza.colorPieza == ColorPieza.Negro)
{
respuesta += Pieza.dameLetraPieza(tablero.Escaques[posicion].pieza.tipoPieza).ToLower();
}
else
{
respuesta += Pieza.dameLetraPieza(tablero.Escaques[posicion].pieza.tipoPieza);
}
}
else
{
escaquesBlancos++;
}
if (x % 8 == 7)
{
if (escaquesBlancos > 0)
{
respuesta += escaquesBlancos.ToString();
respuesta += "/";
escaquesBlancos = 0;
}
else
{
if (x > 0 && x != 63)
{
respuesta += "/";
}
}
}
}
if (tablero.quienMovio == ColorPieza.Blanco)
{
respuesta += " w ";
}
else
{
respuesta += " b ";
}
string espacios = "";
if (tablero.enroqueBlanco == false)
{
if (tablero.Escaques[60].pieza != null)
{
if (tablero.Escaques[60].pieza.Movida == false)
{
if (tablero.Escaques[63].pieza != null)
{
if (tablero.Escaques[63].pieza.Movida == false)
{
respuesta += "K";
espacios = " ";
}
}
if (tablero.Escaques[56].pieza != null)
{
if (tablero.Escaques[56].pieza.Movida == false)
{
respuesta += "Q";
espacios = " ";
}
}
}
}
}
if (tablero.enroqueNegro == false)
{
if (tablero.Escaques[4].pieza != null)
{
if (tablero.Escaques[4].pieza.Movida == false)
{
if (tablero.Escaques[7].pieza != null)
{
if (tablero.Escaques[7].pieza.Movida == false)
{
respuesta += "k";
espacios = " ";
}
}
if (tablero.Escaques[0].pieza != null)
{
if (tablero.Escaques[0].pieza.Movida == false)
{
respuesta += "q";
espacios = " ";
}
}
}
}
}
if (respuesta.EndsWith("/"))
{
respuesta.TrimEnd('/');
}
if (tablero.anteriorPosicion != 0)
{
respuesta += espacios + dameLetraColumna((byte)(tablero.anteriorPosicion % 8)) + "" + (byte)(8 - (byte)(tablero.anteriorPosicion / 8)) + " ";
}
else
{
respuesta += espacios + "- ";
}
if (!tableroSolo)
{
respuesta += tablero.cincuentaMovimientos + " ";
respuesta += tablero.contadorMovimientos + 1;
}
return respuesta.Trim();
}
#endregion
}
}
- Engine.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AjedrezIA.Motor
{
class Engine
{
internal Tablero tablero;
internal Tablero anteriorTablero;
public ColorPieza Humano;
public ColorPieza quienMovio
{
get { return tablero.quienMovio; }
set { tablero.quienMovio = value; }
}
public Engine()
{
InicializaTablero("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
}
public Engine(string fen)
{
InicializaTablero(fen);
}
private void InicializaTablero(string fen)
{
Humano = ColorPieza.Blanco;
tablero = new Tablero(fen);
tablero.quienMovio = ColorPieza.Blanco;
MovimientoPiezas.IniciarMovimientoPieza();
GenerarMovimientosValidos();
}
public byte[] ObtenerMovimientosAnteriores()
{
if (tablero == null)
return null;
byte[] arrayRespuesta = new byte[2];
arrayRespuesta[0] = (byte)(tablero.anteriorPosicion % 8);
arrayRespuesta[1] = (byte)(tablero.anteriorPosicion / 8);
return arrayRespuesta;
}
public bool EsMovimientoValido(byte columnaInicial, byte filaInicial, byte columnaDestino, byte filaDestino)
{
if (tablero == null)
return false;
if (tablero.Escaques == null)
return false;
byte indice = DamePosicionTablero(columnaInicial, filaInicial);
if (tablero.Escaques[indice].pieza == null)
return false;
foreach (byte bs in tablero.Escaques[indice].pieza.movimientosValidos)
if (bs % 8 == columnaDestino)
if ((byte)(bs / 8) == filaDestino)
return true;
indice = DamePosicionTablero(columnaDestino, filaDestino);
if (indice == tablero.anteriorPosicion)
return true;
return false;
}
public TipoPiezaAjedrez dameTipoPieza(byte columnaTablero, byte filaTablero)
{
byte indice = DamePosicionTablero(columnaTablero, filaTablero);
if (tablero.Escaques[indice].pieza == null)
return TipoPiezaAjedrez.Ninguna;
return tablero.Escaques[indice].pieza.tipoPieza;
}
public TipoPiezaAjedrez dameTipoPieza(byte indice)
{
if (tablero.Escaques[indice].pieza == null)
return TipoPiezaAjedrez.Ninguna;
return tablero.Escaques[indice].pieza.tipoPieza;
}
public ColorPieza dameColorPieza(byte columnaTablero, byte filaTablero)
{
byte indice = DamePosicionTablero(columnaTablero, filaTablero);
if (tablero.Escaques[indice].pieza == null)
return ColorPieza.Blanco;
return tablero.Escaques[indice].pieza.colorPieza;
}
public ColorPieza dameColorPieza(byte indice)
{
if (tablero.Escaques[indice].pieza == null)
return ColorPieza.Blanco;
return tablero.Escaques[indice].pieza.colorPieza;
}
public bool damePiezaSeleccionada(byte columnaTablero, byte filaTablero)
{
byte indice = DamePosicionTablero(columnaTablero, filaTablero);
if (tablero.Escaques[indice].pieza == null)
return false;
return tablero.Escaques[indice].pieza.Seleccionada;
}
public byte[][] dameMovimientosValidos(byte columnaTablero, byte filaTablero)
{
byte indice = DamePosicionTablero(columnaTablero, filaTablero);
if (tablero.Escaques[indice].pieza ==null)
return null;
byte[][] arrayRespuesta = new byte[tablero.Escaques[indice].pieza.movimientosValidos.Count][];
int cont = 0;
foreach (byte escaque in tablero.Escaques[indice].pieza.movimientosValidos)
{
arrayRespuesta[cont] = new byte[2];
arrayRespuesta[cont][0] = (byte)(escaque % 8);
arrayRespuesta[cont][1] = (byte)(escaque / 8);
cont++;
}
return arrayRespuesta;
}
public void asignarPosicionAPieza (byte columnaTablero, byte filaTablero, bool seleccion)
{
byte posicion = DamePosicionTablero(columnaTablero, filaTablero);
if (tablero.Escaques[posicion].pieza == null)
return;
if (tablero.Escaques[posicion].pieza.colorPieza != quienMovio)
return;
tablero.Escaques[posicion].pieza.Seleccionada = seleccion;
}
public bool moverPieza(byte columnaOrigen, byte filaOrigen, byte columnaDestino, byte filaDestino)
{
byte posicionOrigen = (byte)(columnaOrigen + (filaOrigen * 8));
byte posicionDestino = (byte)(columnaDestino + (filaDestino * 8));
Pieza pieza = tablero.Escaques[posicionOrigen].pieza;
anteriorTablero = new Tablero(tablero);
Tablero.MoverPieza(tablero, posicionOrigen, posicionDestino, TipoPiezaAjedrez.Reina);
MovimientosValidosPiezas.generarMovimientosValidos(tablero);
if (pieza.colorPieza == ColorPieza.Blanco)
{
if (tablero.jaqueBlanco)
{
//Movimiento no válido
tablero = new Tablero(anteriorTablero);
MovimientosValidosPiezas.generarMovimientosValidos(tablero);
return false;
}
}
else if (pieza.colorPieza == ColorPieza.Negro)
{
if (tablero.jaqueNegro)
{
//Movimiento no válido
tablero = new Tablero(anteriorTablero);
MovimientosValidosPiezas.generarMovimientosValidos(tablero);
return false;
}
}
return true;
}
private void GenerarMovimientosValidos()
{
MovimientosValidosPiezas.generarMovimientosValidos(tablero);
}
private static byte DamePosicionTablero(byte columnaTablero, byte filaTablero)
{
return (byte)(columnaTablero + (filaTablero * 8));
}
}
}
- GraphicsBuffer.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AjedrezIA
{
public sealed class GraphicsBuffer
{
private Graphics graphics;
private int height;
private Bitmap memoryBitmap;
private int width;
public Graphics Graphics
{
get { return graphics; }
}
public void CreateGraphicsBuffer(Graphics g, int W, int H)
{
if (memoryBitmap != null)
{
memoryBitmap.Dispose();
memoryBitmap = null;
}
if (graphics != null)
{
graphics.Dispose();
graphics = null;
}
if (W == 0 || H == 0)
return;
if ((W != width) || (H != height))
{
width = W;
height = H;
memoryBitmap = new Bitmap(width, height);
graphics = Graphics.FromImage(memoryBitmap);
}
}
public void Render(Graphics g)
{
if (memoryBitmap != null)
{
g.DrawImage(memoryBitmap, new Rectangle(0, 0, width, height), 0, 0, width, height, GraphicsUnit.Pixel);
}
}
}
}
- FormAjedrez
using AjedrezIA.Motor;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AjedrezIA
{
public partial class FormAjedrez : Form
{
public ColorPieza WhosMove;
public FormAjedrez()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
Opacity = 1;
}
private void MainForm_ResizeEnd(object sender, EventArgs e)
{
tableroAjedrez.Refresh();
}
private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
WindowState = FormWindowState.Normal;
}
else if (WindowState == FormWindowState.Normal)
{
WindowState = FormWindowState.Minimized;
}
}
}
}
No hay comentarios:
Publicar un comentario