Pop

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



No hay comentarios:

Publicar un comentario

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...