75. Inteligencia Artificial (4). Generando movimientos
- 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 empezamos a generar movimientos con las piezas negras que serán las que controle nuestro agente de inteligencia artificial.
- Por el momento nos conformaremos con generar un movimiento aleatorio de todos los posibles movimientos válidos, que se puedan realizar. En siguientes entradas empezaremos a calcular cual es el mejor movimiento dentro de los posibles movimientos válidos.Os dejo el vídeo con el código:
-Como hemos visto en el vídeo implementamos una función que nos genere los movimientos aleatorios utilizando las clases vistas en anteriores entradas.
int posinicial = 0;
ArrayList arrayPiezas = new ArrayList();
ArrayList arrayPosInicialPiezas = new ArrayList();
if (motor.tablero.jaqueNegro)
{
//Ver que hacemos en caso de jaque al rey
}
else
{
//Recorremos el tablero y guardamos la posicion de las piezas negras con algun movimiento valido en el caso que no sea jaque
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);
}
posinicial++;
}
}
-Como hemos visto en el vídeo implementamos una función que nos genere los movimientos aleatorios utilizando las clases vistas en anteriores entradas.
- En primer lugar obtenemos los posibles movimientos válidos de las pieza negras con este código:
int posinicial = 0;
ArrayList arrayPiezas = new ArrayList();
ArrayList arrayPosInicialPiezas = new ArrayList();
if (motor.tablero.jaqueNegro)
{
//Ver que hacemos en caso de jaque al rey
}
else
{
//Recorremos el tablero y guardamos la posicion de las piezas negras con algun movimiento valido en el caso que no sea jaque
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);
}
posinicial++;
}
}
- En segundo lugar en esta misma función hacemos un movimiento aleatorio:
//Seleccionamos aleatoriamente la pieza a mover y obtenemos columna y fila inicial
Random random = new Random();
int piezaAletoria = random.Next(0, arrayPiezas.Count);
int posicionInicial = Convert.ToInt32(arrayPosInicialPiezas[piezaAletoria]);
byte columnainicio = Convert.ToByte(posicionInicial % 8);
byte 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);
byte columnaDestino = Convert.ToByte(((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.ElementAt(posicionAleatoria) % 8);
byte filaDestino = Convert.ToByte(((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.ElementAt(posicionAleatoria) / 8);
motor.moverPieza(columnainicio, filaInicio, columnaDestino, filaDestino);
- Os dejo el código completo de este clase. El resto del código esta en entradas anteriores del blog:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AjedrezIA.Properties;
using AjedrezIA.Motor;
using System.Drawing.Drawing2D;
using System.Collections;
namespace AjedrezIA.Controles
{
public partial class TableroAjedrez : UserControl
{
#region Internal
internal class Seleccion
{
public byte Columna;
public byte Fila;
public bool Seleccionado;
}
#endregion
#region enumerados
#region Column enum
public enum Column
{
A,
B,
C,
D,
E,
F,
G,
H,
Desconocida
}
#endregion
#region Mostrartipospiezas enum
public enum Mostrartipospiezas
{
ClassicHiRes,
Classic,
EnchancedClassic
}
#endregion
#endregion
#region Delegados
public delegate void CambioTurnoHandler(ColorPieza quienMueve);
#endregion
#region Private
private Seleccion actualDestino;
private Seleccion actualOrigen;
private Engine motor;
private int boxAltura;
private int maxAltura;
#endregion
#region Public
public event CambioTurnoHandler cambioTurno;
#endregion
#region Constructores
public TableroAjedrez()
{
InitializeComponent();
NuevaPartida();
}
public void NuevaPartida()
{
motor = new Engine();
actualOrigen = new Seleccion();
actualDestino = new Seleccion();
if (motor.Humano != motor.quienMovio)
{
MotorMovimiento();
}
Refresh();
}
#endregion
#region Publica
private void MotorMovimiento()
{
if (motor.dameTipoPieza(actualOrigen.Columna, actualOrigen.Fila) == TipoPiezaAjedrez.Ninguna)
{
actualDestino.Seleccionado = false;
actualOrigen.Seleccionado = false;
return;
}
bool valid = motor.EsMovimientoValido(actualOrigen.Columna, actualOrigen.Fila, actualDestino.Columna, actualDestino.Fila);
if (valid == false)
{
actualDestino.Seleccionado = false;
actualOrigen.Seleccionado = false;
return;
}
motor.moverPieza(actualOrigen.Columna, actualOrigen.Fila, actualDestino.Columna, actualDestino.Fila);
if (cambioTurno != null)
{
cambioTurno(motor.quienMovio);
}
//Limpiar solucion
actualOrigen.Seleccionado = false;
//Generar movimiento
generarMovimientoAleatorio();
Refresh();
}
public static Column dameNumeroColumna(int columna)
{
Column retColumna;
switch (columna)
{
case 1:
retColumna = Column.A;
break;
case 2:
retColumna = Column.B;
break;
case 3:
retColumna = Column.C;
break;
case 4:
retColumna = Column.D;
break;
case 5:
retColumna = Column.E;
break;
case 6:
retColumna = Column.F;
break;
case 7:
retColumna = Column.G;
break;
case 8:
retColumna = Column.H;
break;
default:
retColumna = Column.Desconocida;
break;
}
return retColumna;
}
#endregion
#region Eventos
private void tablero_Pintar(object sender, PaintEventArgs e)
{
GraphicsBuffer gBuffer = new GraphicsBuffer();
gBuffer.CreateGraphicsBuffer(e.Graphics, Width, Height);
Graphics g = gBuffer.Graphics;
SolidBrush solidWhiteBrush = new SolidBrush(Color.White);
SolidBrush solidBlackBrush = new SolidBrush(Color.Black);
Pen penBlack = new Pen(Color.Black, 1);
Pen penHightlight = new Pen(Color.Black, 2);
Pen penDestination = new Pen(Color.Yellow, 2);
Pen penValidMove = new Pen(Color.Black, 2);
Pen penEnPassant = new Pen(Color.DeepPink, 1);
const int buffer = 10;
if (Width < Height)
{
maxAltura = Width - 5 - buffer;
boxAltura = maxAltura / 8;
}
else
{
maxAltura = Height - 5 - buffer;
boxAltura = maxAltura / 8;
}
g.Clear(BackColor);
try
{
int seleccionX;
int seleccionY;
//Draw Chess Board
for (byte y = 0; y < 8; y++)
{
for (byte x = 0; x < 8; x++)
{
if ((x + y) % 2 == 0)
{
g.FillRectangle(solidWhiteBrush, (x * boxAltura) + buffer, (y * boxAltura), boxAltura, boxAltura);
}
else
{
Rectangle dibujarArea1 = new Rectangle((x * boxAltura) + buffer, (y * boxAltura), boxAltura, boxAltura);
LinearGradientBrush linearBrush = new LinearGradientBrush(dibujarArea1, Color.Gainsboro, Color.Silver, LinearGradientMode.ForwardDiagonal);
g.FillRectangle(linearBrush, (x * boxAltura) + buffer, (y * boxAltura), boxAltura, boxAltura);
}
g.DrawRectangle(penBlack, (x * boxAltura) + buffer, (y * boxAltura), boxAltura, boxAltura);
}
}
for (byte i = 0; i < 8; i++)
{
g.DrawString((8 - i).ToString(), new Font("Verdana", 8), solidBlackBrush, 0, (i * boxAltura) + buffer);
g.DrawString(dameNumeroColumna(i + 1).ToString(), new Font("Verdana", 8), solidBlackBrush, (i * boxAltura) + (boxAltura / 2) + 3, maxAltura - 1);
}
//dibujar piezas
for (byte columna = 0; columna < 8; columna++)
{
for (byte fila = 0; fila < 8; fila++)
{
TipoPiezaAjedrez tipoPiezaAjedrez = motor.dameTipoPieza(columna, fila);
if (tipoPiezaAjedrez != TipoPiezaAjedrez.Ninguna)
{
ColorPieza colorPieza = motor.dameColorPieza(columna, fila);
bool seleccionado = motor.damePiezaSeleccionada(columna, fila);
int x = (columna) * boxAltura;
int y = (fila) * boxAltura;
if (colorPieza == ColorPieza.Blanco)
{
if (tipoPiezaAjedrez == TipoPiezaAjedrez.Peon)
{
g.DrawImage(Resources.WPawn, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Torre)
{
g.DrawImage(Resources.WRook, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Caballo)
{
g.DrawImage(Resources.WKnight, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Alfil)
{
g.DrawImage(Resources.WBishop, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Reina)
{
g.DrawImage(Resources.WQueen, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Rey)
{
g.DrawImage(Resources.WKing, x + buffer, y, boxAltura, boxAltura);
}
}
else
{
if (tipoPiezaAjedrez == TipoPiezaAjedrez.Peon)
{
g.DrawImage(Resources.BPawn, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Torre)
{
g.DrawImage(Resources.BRook, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Caballo)
{
g.DrawImage(Resources.BKnight, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Alfil)
{
g.DrawImage(Resources.BBishop, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Reina)
{
g.DrawImage(Resources.BQueen, x + buffer, y, boxAltura, boxAltura);
}
else if (tipoPiezaAjedrez == TipoPiezaAjedrez.Rey)
{
g.DrawImage(Resources.BKing, x + buffer, y, boxAltura, boxAltura);
}
}
if (seleccionado)
{
seleccionX = ((columna) * boxAltura) + buffer;
seleccionY = (fila) * boxAltura;
g.DrawRectangle(penHightlight, seleccionX, seleccionY, boxAltura - 1, boxAltura - 1);
//Pintar movimientos validos
if (motor.dameMovimientosValidos(columna, fila) != null)
{
foreach (byte[] sqr in motor.dameMovimientosValidos(columna, fila))
{
int moverY = (sqr[1]) * boxAltura;
int moverX = (sqr[0] * boxAltura) + buffer;
g.DrawRectangle(penValidMove, moverX, moverY, boxAltura - 1, boxAltura - 1);
}
}
}
if (motor.ObtenerMovimientosAnteriores()[0] > 0)
{
int moverY = (motor.ObtenerMovimientosAnteriores()[1]) * boxAltura;
int moverX = (motor.ObtenerMovimientosAnteriores()[0] * boxAltura) + buffer;
g.DrawRectangle(penEnPassant, moverX, moverY, boxAltura - 1, boxAltura - 1);
}
}
}
}
if (actualDestino.Seleccionado)
{
seleccionY = (actualDestino.Fila) * boxAltura;
seleccionX = ((actualDestino.Columna) * boxAltura) + buffer;
g.DrawRectangle(penDestination, seleccionX, seleccionY, boxAltura - 1, boxAltura - 1);
}
gBuffer.Render(CreateGraphics());
g.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error al dibujar tablero", MessageBoxButtons.OK);
}
}
private void tablero_MouseClick(object sender, MouseEventArgs e)
{
byte columna = 0;
byte fila = 0;
try
{
//dame Columna
for (int i = 0; i < 8; i++)
{
if (((i * boxAltura) + 10) < e.Location.X)
{
columna++;
}
else
{
break;
}
}
//dame fila
for (int i = 0; i < 8; i++)
{
if (i * boxAltura < e.Location.Y)
{
fila++;
}
else
{
break;
}
}
columna--;
fila--;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error calculando fila y columna seleccionada", MessageBoxButtons.OK);
}
//Comprobar si filas y columna están en los limites
if (columna > 7 || columna < 0)
{
return;
}
if (fila > 7 || fila < 0)
{
return;
}
try
{
if (actualOrigen.Columna == columna && actualOrigen.Fila == fila && actualOrigen.Seleccionado)
{
actualOrigen.Seleccionado = false;
actualDestino.Seleccionado = false;
if (motor.dameTipoPieza(columna, fila) != TipoPiezaAjedrez.Ninguna)
{
motor.asignarPosicionAPieza(columna, fila, false);
}
}
else if ((actualOrigen.Columna != columna || actualOrigen.Fila != fila) && actualOrigen.Seleccionado)
{
actualDestino.Seleccionado = true;
actualDestino.Columna = columna;
actualDestino.Fila = fila;
MotorMovimiento();
}
else
{
if (motor.dameTipoPieza(columna, fila) != TipoPiezaAjedrez.Ninguna)
{
if (motor.dameColorPieza(columna, fila) != motor.quienMovio)
{
motor.asignarPosicionAPieza(actualDestino.Columna, actualDestino.Fila, false);
actualOrigen.Seleccionado = false;
actualDestino.Seleccionado = false;
return;
}
motor.asignarPosicionAPieza(columna, fila, true);
}
else
{
motor.asignarPosicionAPieza(actualDestino.Columna, actualDestino.Fila, false);
actualOrigen.Seleccionado = false;
actualDestino.Seleccionado = false;
return;
}
//Seleccionar origen
actualDestino.Seleccionado = false;
actualOrigen.Columna = columna;
actualOrigen.Fila = fila;
actualOrigen.Seleccionado = true;
}
Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error seleccionando pieza", MessageBoxButtons.OK);
}
}
private void ChessBoard_Load(object sender, EventArgs e)
{
if (cambioTurno != null)
{
cambioTurno(motor.quienMovio);
}
}
private void ChessBoard_Resize(object sender, EventArgs e)
{
Refresh();
}
#endregion
//Obtener todos los posibles movimientos de todas las piezas negras y de momento generao un movimiento aleatorio
#region Nuevo
public void generarMovimientoAleatorio()
{
int posinicial = 0;
ArrayList arrayPiezas = new ArrayList();
ArrayList arrayPosInicialPiezas = new ArrayList();
if (motor.tablero.jaqueNegro)
{
//Ver que hacemos en caso de jaque al rey
}
else
{
//Recorremos el tablero y guardamos la posicion de las piezas negras con algun movimiento valido en el caso que no sea jaque
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);
valorMovimiento(c.pieza,motor.tablero);
}
posinicial++;
}
}
//Seleccionamos aleatoriamente la pieza a mover y obtenemos columna y fila inicial
Random random = new Random();
int piezaAletoria = random.Next(0, arrayPiezas.Count);
int posicionInicial = Convert.ToInt32(arrayPosInicialPiezas[piezaAletoria]);
byte columnainicio = Convert.ToByte(posicionInicial % 8);
byte 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);
byte columnaDestino = Convert.ToByte(((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.ElementAt(posicionAleatoria) % 8);
byte filaDestino = Convert.ToByte(((Pieza)arrayPiezas[piezaAletoria]).movimientosValidos.ElementAt(posicionAleatoria) / 8);
motor.moverPieza(columnainicio, filaInicio, columnaDestino, filaDestino);
}
}
No hay comentarios:
Publicar un comentario