Cap. 5 - Pseudo-legal hasta que el rey respira

cap. 5 Legalidad · Motor 2012

Pseudo-legal hasta que el rey respira

esAtacadoPor y el filtro de jaque
José Andrés Morales Linares
Madrid, España

El generador de bitboards no pregunta si el rey queda a salvo. Anota todos los pasos que una pieza podría dar: capturas, silencios, enroques a primera vista. Eso se llama pseudo-legal. Lo legal se decide después: se hace la jugada y se pregunta si el propio rey está atacado. Si sí, se deshace y se tacha.

Esa pregunta es esAtacadoPor() en ataque.c. Lo escribí en 2012 y no lo he reescrito. Este artículo empieza por por qué no se genera solo lo legal, no por cada máscara mágica.

Por qué generar de más

Generar solo jugadas legales obliga a detectar clavadas, rayos-X y jaques descubiertos antes de anotar cada candidata. Es caro y fácil de romper. Analogía: se anotan todos los pasos posibles en el papel y se tachan los que dejan al rey al descubierto. El lápiz es barato (AND de bitboards). La goma es un test de ataque sobre una casilla.

El mismo filtro sirve en la búsqueda, en Perft, en UCI al aplicar moves, en el libro. Un solo portero. Si esAtacadoPor miente, todo miente.

hacerMovimiento(mov);
if (juego.colorTurno)  /* ya cambió el turno */
    esJaque = esAtacadoPor(juego.tablero[BLANCO][REY], NEGRO);
else
    esJaque = esAtacadoPor(juego.tablero[NEGRO][REY], BLANCO);
if (esJaque) { desHacerMovimiento(mov); continue; }

Tras hacer, el turno ya es del rival: se pregunta si el rey del que acabó de mover está atacado por quien le toca. Si el blanco movió, colorTurno es negro y se mira el rey blanco contra ataques negros.

Cómo se mira una casilla

esAtacadoPor(bitmapDestino, lado) recorre las casillas del bitmap (casi siempre un solo bit: el rey) y pregunta, en este orden: peones (máscara de captura), caballos, rey, y luego los deslizantes. Los deslizantes reutilizan las magic bitboards de la entrada de representación: occupancy de fila, columna o diagonal por la constante mágica, desplazamiento 57, tabla precalculada.

if (peones & mascaraCapturarPeon[to][otro]) return VERDADERO;
if (caballos & mascaraCaballo[to])          return VERDADERO;
if (rey     & mascaraRey[to])               return VERDADERO;
/* torres/damas: RANK_ATTACKS, FILE_ATTACKS * FILEMAGIC >> 57 */
/* alfiles/damas: DIAGA8H1 / DIAGA1H8 * MAGIC >> 57 */

Analogía: no se recorre el tablero casilla a casilla preguntando «¿hay una torre aquí que llegue?». Se pregunta «de las torres negras, ¿alguna cae en el mapa de ataques de esta casilla dado el bloqueo actual?». Un AND. Si hay bit, hay jaque.

Hay una hermana, esAtacadoPorSR: igual, pero sin contar al rey atacante. Sirve cuando el rey no debe ser el que «protege» o amenaza en ese cálculo. obtAtacantesDeEscaque no responde sí o no: devuelve el bitboard de quién mira esa casilla. Lo usa SEE para armar la cola de la pelea. obtPiezasClavadasPor busca la pieza amiga única entre el rey y un deslizante.

Mate y ahogado

Si tras generar y filtrar no queda ninguna legal, hay que distinguir. Si el rey del lado que toca está atacado, es mate: se devuelve -VALOR_JAQUE_MATE + capa. Si no, es ahogado: empate. El mismo portero cierra el árbol.

El enroque se genera con condiciones extra (casillas vacías, derechos). La legalidad fina, no enrocar a través de jaque, cae otra vez en este filtro: si el rey pasó o quedó en una casilla atacada, la jugada se tacha al hacer.

if (!existeUnMovValido) {
    if (esAtacadoPor(juego.tablero[colorTurno][REY], !colorTurno))
        return -VALOR_JAQUE_MATE + capa - 2;  /* mate */
    return PUNTAJE_EMPATE;                    /* ahogado */
}

El orden dentro de esAtacadoPor no es capricho: peones y caballos se miran primero (un AND con un mapa fijo) y los deslizantes después (occupancy × magic). En un jaque de peón se sale en la primera línea. Analogía: el portero mira primero si hay alguien pegado a la puerta, luego si hay un francotirador al fondo del pasillo.

Qué archivos leer

Archivo Qué hay
ataque.c esAtacadoPor, esAtacadoPorSR, obtAtacantesDeEscaque
busquedad.c / perft.c / uci.c El mismo filtro post-hacerMovimiento
macros.h Tablas mágicas de deslizantes (entrada de bitboards)

El repositorio del motor: GitHub.

Cierre

Generar es barato y sucio. Legal es un sí o un no sobre el rey. esAtacadoPor usa las mismas magics que el generador: peón, caballo, rey, luego la cruz y la equis. Encaja con los bitboards (mapas), con hacer/deshacer (el peaje) y con Perft (el número seco). Para poner una posición en el tablero sin jugarla, hace falta texto. Eso es FEN. La siguiente entrada.

Correo de contacto: comprasmangocomputer@gmail.com

Comentarios

Entradas populares de este blog

Mango AC Ajedrez

Cap. 18 - Hacer lo que hay que hacer

Cap. 2 - Seis campos y el tablero entero