Pop

Curso programación C# - 80. Inteligencia Artificial con C# (9)- Visual Studio 2017


80. Inteligencia Artificial (9). Minimax aplicado al juego 3 en raya

 -  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 vimos una introducción al algoritmo minimax.

- En esta entrada nos centraremos en explicar al detalle el funcionamiento de este algortimo. Como ya comentamos en la entrada anterior este  algoritmo se resume en cómo elegir el mejor movimiento suponiendo que tu oponente escogerá el peor para ti. Una vez supuesto esto recorremos todo el árbol de soluciones del juego a partir de un estado dado, es decir, según las casillas que ya han sido rellenadas. Minimax se ejecutará cada vez que le toque mover a la IA.

- Podemos implementar el algoritmo minimax en diferentes pasos y de diferentes maneras pero hay que tener  una idea clara de su funcionamiento.


  • Partimos de un estado inicial, que es el estado en que se encuentra el juego. Para el caso que nos ocupa puede ser por ejemplo:

  • Buscamos las posibles jugadas legales a partir del estado inicial.En el caso que nos ocupa todas las posibles jugadas son las siguientes:

  •  Asignamos un determinado valor para el caso de empate,victoria o derrota
  • Lo que  hará el algoritmo Minimax cuando vaya regresando hacia atrás, será comunicarle a la llamada recursiva superior cuál es el mejor nodo hoja alcanzado hasta el momento. 
  • Cada llamada recursiva tiene que saber a quién le toca jugar, para analizar si el movimiento realizado pertenece a la inteligencia artificial o al otro jugador, ya que cuando sea el turno de la IA nos interesa MAXIMIZAR el resultado, y cuando sea el turno del rival MINIMIZAR su resultado.
  • El algoritmo nos devolverá la jugada que debe realizar la máquina para maximizar sus posibilidades y bloquear las posibilidades del rival.

- En la siguiente entrada del blog veremos el código necesario para implementar esta lógica.De momento os dejo el vídeo con lo explicado en este capítulo:







Curso programación C# - 79. Inteligencia Artificial con C# (8)- Visual Studio 2017

79. Inteligencia Artificial (8).Algoritmo minimax

 -  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 entradas anterior enseñamos a nuestro agente mecanismos para evitar el jaque de nuestro adversario.

- En esta ocasión finalizamos nuestro ajedrez validando en que situaciones finaliza el juego por producirse jaque mate . Además os dejo las nociones teóricas para la implementación del algoritmo minimax.

-  Minimax lo que hace informalmente es considerar todos los casos que se pueden dar desde donde estás y en base a esto,  elegir el movimiento que te lleve a un resultado mejor asumiendo que el contrario hará el movimiento que más te perjudique.El algoritmo Minimax es el algoritmo más conocido (y utilizado) para juegos de 2 adversarios, movimientos alternos (“ahora tú, ahora yo”). No se puede utilizar en juegos donde hay “azar”, sino perfectamente definido como las tres en raya y el ajedrez.  El problema de Minimax es que el árbol de estados que crea es muy grande para juegos como el ajedrez. Os dejo la imagen del posible  de movimientos de una posible jugada y el vídeo donde lo explico:



Explicación:




-Minimax es un algoritmo recursivo (https://es.wikipedia.org/wiki/Minimax). El funcionamiento de minimax puede resumirse como elegir el mejor movimiento para ti mismo suponiendo que tu contrincante escogerá el peor para ti.

-  Pasos del algoritmo minimax:

  • Generación del árbol de juego. Se generarán todos los nodos hasta llegar a un estado terminal.
  • Cálculo de los valores de la función de utilidad para cada nodo terminal. 
  • Calcular el valor de los nodos superiores a partir del valor de los inferiores. Según nivel si es MAX o MIN se elegirán los valores mínimos y máximos representando los movimientos del jugador y del oponente, de ahí el nombre de minimax. 
  • Elegir la jugada valorando los valores que han llegado al nivel superior. El algoritmo explorará los nodos del árbol asignándoles un valor numérico mediante una función de evaluación, empezando por los nodos terminales y subiendo hacia la raíz. La función de utilidad definirá lo buena que es la posición para un jugador cuando la alcanza. 
  • En el caso del ajedrez los posibles valores son (+1, 0 ,-1) que se corresponden con ganar, empatar y perder respectivamente. 

* Finalmente os dejo el código  del proyecto completo  en visual studio en este archivo rar:




Curso programación C# - 78. Inteligencia Artificial con C# (7)- Visual Studio 2017

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.


  • 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

  • Jaque con una pieza que ataca en dirección diagonal 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;
        }



Curso programación C# - 77. Inteligencia Artificial con C# (6)- Visual Studio 2017

77. Inteligencia Artificial (6).Lógica para evitar un jaque(1)

 -  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  a comer piezas.En este capítulo trataremos de evitar el jaque que nos hagan las piezas blancas.

- En esta entrada aprenderemos a evitar el jaque del rival mediante dos mecanismos: comiendo la pieza del rival  que no está atacando o moviendo el rey a alguna casilla libre.En la siguiente entrada del blog trataremos de evitar el jaque de nuestro adversario bloqueando la trayectoria de la pieza que nos este atacando. De momento os dejo el vídeo con el código de los dos mecanismos anteriormente mencionados:



- Os pongo el código de los métodos modificado en este vídeo:

  //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();
            ArrayList arrayValorMovimiento = 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++;
            }



            //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;

            //Si nos estan dando jaque y no nos podemos comer la pieza que nos lo esta dando movemos el rey
            if (SiJaque && maxValor != 100000)
            {
                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));

                //Meter logica para bloquear la trayectoria de la pieza que nos esta atacando

            }
            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 )
        {
            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
                        valorMovimientoAux = c.pieza.valorPieza;

                        if (valorMovimientoAux > mov.ValorMovimiento)
                            mov.ValorMovimiento = valorMovimientoAux;

                        mov.PosicionDestino = posicionpiezaBlanca;
                    }
                    posicionpiezaBlanca++;
                }
            }
            return mov;
        }





Curso programación C# - 76. Inteligencia Artificial con C# (5)- Visual Studio 2017

76. Inteligencia Artificial (5).Comiendo piezas

 -  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 aprendimos a generar movimientos aleatorios en nuestro tablero, que en realidad es una matriz.En esta ocasión nuestro agente tiene como objetivo comer fichas del rival en función del peso que tengan asignado.

- Para ello hemos asignado a cada pieza del rival  un valor:


  • Peón: 100 puntos
  • Caballo:320 puntos
  • Alfil:325 puntos
  • Torre:500 puntos
  • Reina: 975 puntos
  • Rey: 32767 puntos

- En función de los valores que tengan asignadas las piezas nuestro agente tratara de comer una pieza u otra en función del valor que tenga asignada.En el vídeo lo podemos ver más claro:


- En siguientes entradas iremos mejorando nuestro jugador para que además de intentar comer piezas del rival tenga en cuenta las posibles consecuencias de hacerlo.Por el momento os dejo el código de lo visto en el vídeo:


  • Nueva clase MovimientoSeleccionado.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AjedrezIA
{
    public class MovimientoSeleccionado
    {
        int valorMovimiento;
        int posicionDestino;

        public int ValorMovimiento { get => valorMovimiento; set => valorMovimiento = value; }
        public int PosicionDestino { get => posicionDestino; set => posicionDestino = value; }

        public MovimientoSeleccionado()
        {
            valorMovimiento = 0;
            posicionDestino = 0;
            }
    }
}

  • Métodos utilizados en este capítulo:
  //Obtener todos los posibles movimientos de todas las piezas negras y de momento generao un movimiento aleatorio
       
        public void generarMovimientoAleatorio()
        {

            int posinicial = 0;
            ArrayList arrayPiezas = new ArrayList();
            ArrayList arrayPosInicialPiezas = new ArrayList();
            ArrayList arrayValorMovimiento = 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);
                        arrayValorMovimiento.Add(valorMovimiento(c.pieza, motor.tablero));
                    }
                    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;
            //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 )
        {
            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)
                    {
                        valorMovimientoAux = c.pieza.valorPieza;
                        if (valorMovimientoAux > mov.ValorMovimiento)
                            mov.ValorMovimiento = valorMovimientoAux;

                        mov.PosicionDestino = posicionpiezaBlanca;
                    }
                    posicionpiezaBlanca++;
                }
            }
            return mov;
        }


        

Curso programación C# - 75. Inteligencia Artificial con C# (4)- Visual Studio 2017

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.


  •  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);


        }
}

Curso .NET Core en C# - 34.Creamos nuestro propio log

34.Creamos nuestro propio log Hola a todos. En este curso, analizaremos todos los conceptos básicos, intermedios y avanzados de  ASP.NET...