¿Cómo puedo convertir los movimientos de una posible pieza en un movimiento real en un tablero de bits?

Jan 09 2021

Si tengo un tablero de bits (por ejemplo, para casillas de caballos al que se puede mover) como este:

00000000
00000000
00000000
00000000
00000000
01000000
00100000
N0000000

¿Cómo puedo "convertirlo" en un movimiento o "aplicar" ese movimiento?

Respuestas

2 AryanParekh Jan 09 2021 at 19:28

En realidad, hay dos preguntas en tu publicación.

  • ¿Cómo convertir ataques en Bitboards en una lista de movimientos?

  • ¿Cómo representar esos movimientos?


  • ¿Cómo representar esos movimientos?

Esta cuestión se ha discutido aquí y aquí a fondo. Pero para proporcionar algo de contexto a los lectores de esta publicación, una forma muy simple de hacer esto puede ser usar una clase / estructura para representar un movimiento.

  • De (donde estaba la pieza en movimiento)
  • A (donde estará la pieza en movimiento)
  • Bandera de movimiento especial (si el movimiento fue un movimiento especial, es decir, atravesar, lanzar, ascender)
  • Pieza promocionada (si el movimiento fue un movimiento de promoción, a qué pieza promocionó)

También puede tener atributos adicionales como pieza capturada, tipo de castillo, etc. Pero esa información también se puede deducir usando los cuadrados Fromy To.

Entonces, considerando lo anterior, podemos representar el movimiento de la siguiente manera

struct Move {
    char from; 
    char to;   
    char spMoveFlag;
    char promotedPiece;
};

Sin embargo, muchos motores de ajedrez, incluido el mío, utilizan otro método que puede comprimir el movimiento en solo 16bits. Lea más sobre eso aquí .

Una vez que sabemos qué es un movimiento, podemos responder a la siguiente pregunta.


  • ¿Cómo convertir ataques en Bitboards en una lista de movimientos?

Consideremos que tenemos un caballo en la casilla d4 . También tenemos una función que devuelve los ataques de un caballo dada la casilla.

. . . . . . . . 
. . . . . . . . 
. . 1 . 1 . . . 
. 1 . . . 1 . . 
. . . n . . . .   =  knightattacks(SQ_D4)
. 1 . . . 1 . . 
. . 1 . 1 . . . 
. . . . . . . . 

Así que almacenemos esto dentro de una variable. knightAttacks

uint64_t knightAttacks = getKnightAttacksBB(SQ_D4);

Si observa con atención, ya tenemos 1 de los 4 atributos que necesitamos para representar el movimiento, que es el From cuadrado - D4. Ahora todo lo que tenemos que hacer es conseguir el Tocuadrado para completar esto, ya que un caballo no puede realizar ningún tipo de movimientos especiales.

Un método muy común es hacer estallar la parte menos significativa hasta que suknightAttacks se quede sin nada, es decir 0.

0000011100001000 
            ^
            Least significant bit (lsb)

Puede seguir el enlace que proporcioné para saber cómo puede realizar esto, o existe la posibilidad de que su compilador ya se lo proporcione.

Simplemente necesita crear una función que borre el lsb de un tablero de bits y devuelva su índice. Vamos a llamarlo poplsb().

En total, su código puede verse así

int from = SQ_D4;
uint16_t knightAttacks = getknightAttacks(from);

while (knightAttacks)  {
     int to = poplsb(knightAttacks);
     MyMoveList.Add( NewMove(from, to, 0, 0) ); // The last two 0's denote that there is no special move
}

Esto funciona porque cada vez que abre el lsb, se borra un poco hasta que el número es == 0. Ahí es cuando el bucle se detiene y tiene una lista perfectamente buena de movimientos. La misma idea se aplica a cualquier tipo de movimientos que haya creado utilizando Bitboards.