Lógica del juego 1: Fundamentos - aigora/twIE_2021-chkr_s-l GitHub Wiki

¿Cómo sabe el programa en que situación se encuentra la partida?

El tablero en nuestro programa está almacenado como un vector de enteros de dimensión 32, guardando en cada uno de los espacios del vector la situación de la casilla correspondiente según la imagen siguiente.

Numeracion-del-tablero

De esta manera podemos controlar que tipo de ficha hay en cada casilla en todo momento.

¿Con qué valor se almacena cada tipo de ficha en el array tablero?

    Peón amarillo: 0
    Peón morado: 1
    Casilla vacía: 2
    Dama amarilla: 3
    Dama morada: 4

Teniendo ya todo esto fijado inicializamos el tablero justo antes de iniciar la partida.

for (k=0;k<32;k++) //Se reinicia el tablero
{
    if(k<=11)
        tablero[k]=1;
    else if(k<=19)
        tablero[k]=2;
    else if(k<=31)
        tablero[k]=0;
}

¿Cómo funciona el juego en sí?

El bucle principal

El juego funciona dentro de un bucle que estará activo hasta que se acabe la partida, es decir, hasta que la función terminar_partida devuelva un numero distinto de 0.

Lo primero que ocurre en el bucle es un if que separa los turnos del bot del de los jugadores.

if (colorBot == turno % 2)
{
    //La IA hace su turno
    turno++;
    nComidas_posibles = puedeComer(tablero, turno, comidasPosibles);
    fin_partida = terminar_partida(tablero, turno_sin_comidos, pieza, turno, nComidas_posibles, comidasPosibles);
//Se comprueba si se ha terminado la partida
}
else
{
    //El jugador hace su turno
}

La variable colorBot toma el valor 0 si el bot juega como amarillas, 1 si juega como moradas y -1 si está desactivado. colorBot se asigna al seleccionar el modo de juego y sirve para anotar si el bot está activo y en caso de que lo esté, con que color está jugando. En caso de estar en modo multijugador la condición del if nunca se verificaría y el juego se da exclusivamente en la cláusula else, que comentaremos a continuación.

El juego en el turno de un jugador

Lo primero que se ejecuta en el turno de un jugador es la función pos_raton, la cual devuelve la casilla que se ha pulsado (su valor de 0 a 31 según el array tablero) o -1 en el caso de que se haya pulsado en un lugar no jugable (fuera del tablero o en las casillas negras, donde no se pueden colocar fichas).
Tras esto comprueba si se ha pulsado un lugar válido. Si no fuese así, el bucle ejecuta de nuevo desde el principio hasta que la posición sea una válida.

posicion = pos_raton(dim_cas,32);
if(posicion != -1)
{
   //Siguiente código
}

Círculos de selección:
En el caso de que la posición seleccionada sea una de las casillas jugables, se borrarían los círculos de selección anteriores si los hubiera, y si en la posición seleccionada hay una pieza del color al que le toca mover en este turno, esta se almacena en la variable pieza, y si esta pudiese hacer algún movimiento, estos se dibujan.

if(tablero[posicion] % 3 == turno % 2) //Si la pieza selecciona corresponde al color que juega este turno
{
    if(pieza != -1) //Si había una pieza seleccionada previamente
    {
        if(nComidas_posibles == -1) //Si ninguna pieza puede comer en este turno
        {
            for(i=0; i<=nMovimientos_posibles; i++) //Para cada movimiento que puede hacer la pieza que estaba
//seleccionada
            {
                Pintar(tablero, movimientosPosibles[i], false, Render, dim_cas); //Borra la selección de esa casilla
            }
        }
        else
        {
            for(i=0; i<=nComidas_posibles; i++) //Para cada comida que puede hacer cada pieza en este turno
            {
                if(comidasPosibles[i][0] == pieza) //Si la pieza que estaba seleccionada es la pieza que puede comer
                {
                    Pintar(tablero, comidasPosibles[i][2], false, Render, dim_cas); //Borra la selección de esa
//casilla
                }
            }
        }
        Pintar(tablero, pieza, false, Render, dim_cas); //Borra la selección de esa pieza
    }
    pieza = posicion; //Se selecciona una pieza y se dibuja en modo seleccionado
    nMovimientos_posibles = puedeMover(tablero, pieza, movimientosPosibles);
    if(nComidas_posibles == -1) //Si ninguna pieza puede comer en este turno
    {
        for(i=0; i<=nMovimientos_posibles; i++) //Para cada movimiento que puede hacer la pieza que estaba
//seleccionada
        {
            Pintar(tablero, movimientosPosibles[i], true, Render, dim_cas); //Pinta la selección de esa casilla
        }
    }
    else
    {
        for(i=0; i<=nComidas_posibles; i++) //Para cada comida que puede hacer cada pieza en este turno
        {
            if(comidasPosibles[i][0] == pieza) //Si la pieza seleccionada es la pieza que puede comer
            {
                Pintar(tablero, comidasPosibles[i][2], true, Render, dim_cas); //Pinta la selección de esa casilla
            }
        }
    }
    Pintar(tablero, pieza, true, Render, dim_cas); //Pinta la selección de la pieza
}

Esto se realiza a partir de las variable movimientosPosibles, que contiene las posiciones a donde puede mover una pieza dada, y comidasPosibles, que contiene, entre otras cosas, las piezas que pueden comer en un turno dado y la posición a la que llegan tras comer. Estas variables están explicadas a fondo en las funciones puedeMover y puedeComer respectivamente.

Comprobar si la pieza seleccionada puede comer:
En el caso de que ya haya una ficha seleccionada y no se pulse en otra del mismo color, se busca en el array comidasPosibles la pieza como posición inicial y la posición como posición final, y en caso de encontrarse, se guarda el índice del array (n) en el que esto ocurre porque este es el movimiento que se da, siendo este una comida de ficha. En caso contrario el índice (n) quedará a -1, simbolizando que no se da una comida.

else if(pieza != -1) //Si hay una pieza seleccionada
{
    n = -1;
    for(i=0; i<=nComidas_posibles; i++) //Para cada comida que puede realizar una pieza este turno
    {
        if(pieza == comidasPosibles[i][0] && posicion == comidasPosibles[i][2]) //Si que la pieza seleccionada coma
//y acabe en la posición seleccionada
        {
            n = i;
        }
    }
if (n != -1)
{
    //Comer
}
else
{
    //Mover si es posible
}

Comer:
Si se puede comer entonces se actualiza el tablero cambiando la pieza seleccionada a la posición seleccionada, borrando tanto la pieza de su posición anterior como la pieza comida y comprobando si la pieza movida se corona. Tras esto se actualiza visualmente el tablero y se comprueba si la pieza que ha comido puede comer de nuevo. En caso negativo se pasa turno, se mira las piezas que puede comer el siguiente jugador en su turno y se comprueba si se ha acabado la partida (Función terminar_partida), y en caso negativo, no se hace nada, dejando que al dar la vuelta el bucle el mismo jugador juegue como si fuese un turno nuevo. Después de comprobar esto, y en ambos casos, se inicializa pieza a -1 para indicar que no hay ninguna pieza seleccionada y se fija turnos_sin_comidos (variable utilizada en terminar_partida) a 0 porque se ha comido en este turno.

tablero[comidasPosibles[n][2]] = tablero[comidasPosibles[n][0]]; //Devuelve el valor en la posición querida
tablero[comidasPosibles[n][0]] = 2; //Quita la ficha movida
tablero[comidasPosibles[n][1]] = 2; //Quita la ficha comida
coronar(tablero); //Se comprueba si se corona la pieza que ha comido
for(j=0; j<=2; j++)
{
     Pintar(tablero, comidasPosibles[n][j], false, Render, dim_cas); //Borrar la pieza la posición en la que estaba
//la pieza movida y la comida
}
for(j=0; j<=nComidas_posibles; j++)
{
    if (pieza == comidasPosibles[j][0])
    {
        Pintar(tablero, comidasPosibles[j][2], false, Render, dim_cas); //Deseleccionar el resto de casillas a donde
//podía mover tras comer la pieza seleccionada
    }
}

nComidas_posibles = puedeComer(tablero,turno,comidasPosibles); //Se mira que piezas pueden comer este turno después
//de haber comido la seleccionada

pasar_turno=true;
for(j=0; j<=nComidas_posibles; j++) //Para cada pieza que puede mover en este turno después de haber comido la otra
//seleccionada
{
    if(posicion == comidasPosibles[j][0]) //Si la pieza que ha movido puede volver a mover
    {
        pasar_turno = false;
    }
}

pieza = -1;
turno_sin_comidos = 0;

if(pasar_turno)
{
    turno++; //Se pasa turno
    nComidas_posibles = puedeComer(tablero,turno,comidasPosibles); //Se miran las comidas que se pueden hacer en el
//tuno siguiente
    fin_partida = terminar_partida(tablero, turno_sin_comidos, pieza, turno, nComidas_posibles, comidasPosibles);
//Se comprueba si se ha terminado la partida
}

Comprobar si es posible mover y hacerlo en caso afirmativo:
En el caso de que la pieza seleccionada no se encuentre entre las piezas que pueden comer, se comprueba si hay piezas que puedan comer, y en caso negativo, se mueve si la pieza puede realizar algún movimiento (Función puedeMover). Para mover se actualiza la función tablero con la nueva posición de la ficha y quitándola de la casilla en la que se encontraba antes. Tras esto se pintan las casillas que se han alterado, se deselecciona la ficha, se pasa turno y se comprueba si hay piezas que pueden comer en este (Función puedeComer) y se lanza la función terminar_partida para ver si esta se ha acabado.

if(nComidas_posibles == -1) //Si no se puede comer con ninguna pieza este turno
{
    for (i=0; i<=nMovimientos_posibles; i++) //Para cada movimiento que puede hacer la pieza seleccionada
    {
        if (posicion == movimientosPosibles[i]) //Si la pieza seleccionada se puede mover a la posición seleccionada
        {
            tablero[posicion] = tablero[pieza]; //Se pone la ficha en la nueva posición
            tablero[pieza] = 2; //Se borra la pieza de la posición anterior
            coronar(tablero); //Se comprueba si se corona la pieza movida
            Pintar(tablero, pieza, false, Render, dim_cas); //Se quita la ficha de la posición anterior

            for(j=0; j<=nMovimientos_posibles; j++) //Se corrige la parte gráfica
            {
                Pintar(tablero, movimientosPosibles[j], false, Render,dim_cas);//Se borran los circulos de selección
            }


            pieza = -1;
            turno_sin_comidos++;

            turno++; //Se pasa turno
            nComidas_posibles = puedeComer(tablero, turno, comidasPosibles); //Se comprueban las piezas que pueden
//comer en el turno siguiente
            fin_partida=terminar_partida(tablero,turno_sin_comidos, pieza,turno, nComidas_posibles,comidasPosibles);
//Se comprueba si se ha terminado la partida
        }
    }
}

El juego en el turno del bot:

En el turno del bot se invoca la función IA, que hace el movimiento del bot. Tras esto se pasa de turno, se miran las piezas que pueden comer en el siguiente turno (Función puedeComer) y se comprueba si la partida ha terminado (Función terminar_partida).

IA(tablero, dificil, turno, comidasPosibles, nComidas_posibles, Render, dim_cas); //El bot hace su movimiento
turno++; //Se pasa turno
nComidas_posibles = puedeComer(tablero, turno, comidasPosibles); //Se comprueban que piezas se pueden comer en el
//siguiente turno
fin_partida = terminar_partida(tablero, turno_sin_comidos, pieza, turno, nComidas_posibles, comidasPosibles); //Se
//comprueba si ha terminado la partida
⚠️ **GitHub.com Fallback** ⚠️