Notxor tiene un blog

Defenestrando la vida

El ajedrez y su representación

Notxor
2023-03-12

El ajedrez es un juego milenario que a estas alturas no necesita presentación. Además, desde hace cientos de años se ha intentando sistematizar la representación de las partidas con notaciones de distinto tipo y alcance. Además, se pueden encontrar por internet bases de datos cargadas con, literalmente, millones de partidas anotadas y comentadas que pueden servir no sólo como entrenamiento a las IA, sino también a las inteligencias naturales que pretenden aprender este juego. Como necesitaba algún proyecto que me ayudara a calibrar del todo si el lenguaje Nim del que ya hablé aquí, me hace sentir cómodo. Y en este artículo os cuento en que consistirá dicho proyecto.

Objetivos

Los objetivos no son muy ambiciosos, pero son ampliables. Contado así deprisa, lo que pretendo es hacer un programa que sea capaz de mostrar partidas para analizarlas y aprender de ellas. Para ello tiene que:

  • Mostrar un tablero por pantalla, con las reglas del ajedrez imbuidas en él.
  • Comprender los formatos más habituales de notación de partidas.
  • Posibilidad de hacer búsquedas de partidas.
  • Análisis de partidas.
  • Posibilidad de programar ejercicios de aprendizaje.

Como objetivo secundario y más a largo plazo hacer un pequeño motor de juego para poder jugar contra la máquina o que sirva de asistente para el análisis de las partidas de la base de datos. Sin embargo, existiendo varios motores de juego ya plenamente probados, como gnuchess u otros.

Notación

Es complicado anotar las posiciones o movimientos del ajedrez y a lo largo del tiempo se han ido proponiendo diferentes formas de hacerlo, cada uno a su manera. Algunas de estas maneras conviven en la actualidad y pueden presentarse en diferentes bases de datos. Además contamos con las diferentes variantes idiomáticas para el nombre de las piezas y su notación.

Tabla 1 Los nombres de las piezas y su notación según el idioma
idioma peón caballo alfil torre dama rey
Español P (Peón) C (Caballo) A (Alfil) T (Torre) D (Dama) R (Rey)
Portugués P (Peão) C (Cavalo) B (Bispo) T (Torre) D (Dama) R (Rei)
Esperanto P (Peono) Ĉ (Ĉevalo) K (Kuriero) T (Turo) D (Damo) R (Reĝo)
Francés P (Pion) C (Cavalier) F (Fou) T (Tour) D (Dame) R (Roi)
Italiano P (Pedone) C (Cavallo) A (Alfiere) T (Torre) D (Donna) R (Re)
Alemán B (Bauer) S (Springer) L (Laüfer) T (Turm) D (Dame) K (Köning)
Inglés P (Pawn) N (Knight) B (Bishop) R (Rook) Q (Queen) K (King)

En muchas bases de datos, especialmente las que utilizan el formato PGN (Portable Game Notation) utilizan los nombres en inglés. Las notaciones pueden ser:

  • Notación algebraica: Es la más extendida y está estandarizada por la FIDE, especialmente con su notación inglesa, sin embargo, no es unitaria y hay varios modos de hacer la anotación:
    • Notación algebraica estándar.
    • Notación algebraica larga.
    • Notación algebraica corta.
    • Notación algebraica mínima.
    • Notación algebraica de figuras.
    • Notación algebraica reversible.
    • Notación algebraica concisa de figuras.
  • Notación descriptiva: Más tradicional, está en desuso, pero se sigue encontrando en libros antiguos y la siguen utilizando algunos jugadores, especialmente los de más edad.
  • Notación numérica de la ICCF: La necesidad de notación fue especialmente importante para las partidas a través del correo y la Federación Internacional de Ajedrez por Corresponencia elaboró y estandarizó una notación numérica que es la oficial en sus competiciones.
  • Notación de Smith: es una notación sencilla diseñada para ser reversible que anota la casilla de origen y destino de cada movimiento y la pieza capturada si es necesario.
  • Notación de coordenadas: Es similar a la notación algebraica pero no utiliza código para la pieza movida y en lugar de utilizar letras para las columnas utiliza también números.

Por todo esto, podemos encontrar que las mismas jugadas se pueden expresar de muy diferentes maneras. Según un ejemplo sacado de la wikipedia podríamos utilizar las siguientes maneras:

#. Algebraica Al. figuras Al. larga Al. reversible Al. corta Smith Descriptiva Coordenadas ICCF
1. e4 e5 e4 e5 e2e4 e7e5 e2-e4 e7-e5 e24 e75 e2e4 e7e5 P4R P4R E2-E4 E7-E5 5254 5755
2. Cf3 Cc6 ♘f3 ♞c6 Cg1f3 Cb8c6 Cg1-f3 Cb8-c6 Cg1f3 Cb8c6 g1f3 b8c6 C3AR C3Ad G1-F3 B8-C6 7163 2836
3. Ab5 a6 ♗b5 a6 Af1b5 a7a6 Af1-b5 a7-a6 Af1b5 a76 f1b5 a7a6 A5C P3TD F1-B5 A7-A6 6125 1716
4. Axc6 dxc6 ♗xc6 dxc6 Ab5xc6 d7xc6 Ab5xNc6 d7xBc6 Ab5:Cc6 d7:Ac6 b5c6n d7c6b AxC PDxA B5-C6 D7-C6 2536 4736
5. d3 Ab4+ d3 ♝b4+ d2d3 Af8b4+ d2-d3 Af8-b4+ d23 Af8b4+ d2d3 f8b4 P3D A5C+ D2-D3 F8-B4 4243 6824
6. Cc3 Cf6 ♘c3 ♞f6 Cb1c3 Cg8f6 Cb1-c3 Cg8-f6 Cb1c3 Cg8f6 b1c3 g8f6 C3A C3A B1-C3 G8-F6 2133 7866
7. O-O Axc3 O-O ♝xc3 O-O Ab4xc3 O-O Ab4xNc3 O-O Ab4:Cc3 e1g1c b4c3n O-O AxC E1-G1 B4-C3 5171 2433

Como se puede observar, hay muchas maneras de indicar los movimientos, siendo algunos más comprensibles que otros a ojos humanos. Los símbolos que se suelen utilizar son varios:

  • +: indica jaque.
  • ++, #, ≠, ‡: indica jaque mate.
  • O-O, O-O-O: enroque corto y largo, respectivamente.
  • 1-0: ganan blancas.
  • 0-1: ganan negras.
  • ½-½: tablas.
  • !: jugada excepcionalmente buena. Se pueden utilizar varios !! para dar aún más énfasis.
  • ?: jugada excepcionalmente mala. Se pueden utilizar varios ?? para dar aún más énfasis.

Dado que el tablero de ajedrez está dividido en casillas colocadas en filas y en columnas, se han utilizado varios sistemas de coordenadas para referirse a ellas. Por ejemplo, en la notación descriptiva las columnas se denominan como:

  • TR: columna de la torre de rey.
  • CR: columna del caballo de rey.
  • AR: columna del alfil de rey.
  • R: columna del rey.
  • D: columna de la dama.
  • AD: columna del alfil de dama.
  • CD: columna del caballo de dama.
  • TD: columna de la torre de dama.

En este mismo sistema, las filas se numeran desde el punto de vista de cada jugador, es decir, la fila 1 del jugador de blancas es la fila 8 del jugador de negras y viceversa.

tablero.svg

En la esquina superior derecha está el sistema de coordenadas más utilizado por los distintos sistemas de notación. Abajo a la izquierda está el sistema de coordenadas del sistema descriptivo. Como se puede apreciar, este sistema tiene en cuenta la perspectiva del jugador para la anotación haciendo que las casillas tengan dos coordenadas distintas dependiendo del jugador. El tercer sistema, abajo a la derecha, es el sistema de coordenadas utilizado por la ICCF en partidas por correspondencia.

En las partidas por correspondencia además se anota el día de recepción de la respuesta del contrincante y el día de respuesta.

Notación de partidas y descripción del tablero

Hay dos tipos de notaciones, la notación de partidas y la descripción de las posiciones en el tablero. Empecemos por la descripción de las posiciones en el tablero:

  • FEN (Notación de Forsyth-Edwars): Consta de seis campos
    • Cadena representando las 8 filas del tablero:
      • El tablero se lee de izquierda a derecha comenzando por la casilla a8.
      • Cada fila se separa de la siguiente con el signo /.
      • Se utiliza la notación de piezas en mayúscula para blancas y en minúscula para negras.
      • Las casillas vacías se muestran agrupándolas con un número.
    • Indicador de color activo, o a quién le toca mover, b y n si la notación está en español o w y b si está en inglés (por poner sólo dos ejemplos).
    • Indicador de posibilidad de enroques: aparecerá una combinación de letras, en español serían RDrd o en inglés QKqk que actuarían como flags de que blancas (en mayúscula) y negras (en minúscula) tienen capacidad de enrocar aún por alguno de los lados o un - si no.
    • Casilla de destino al paso. Si no hay casilla de destino aparecerá un -. La casilla destino aparecerá después de un doble avance de salida de un peón. Un peón contrario que se encuentre en la fila 3 (para negros) o en la fila 6 (para blancos) puede ejercer la acción de comer al paso.
    • Reloj medio de movimiento: Este número es el recuento de medios movimientos desde el avance de peones o movimientos de captura y se utiliza para la regla de conteo de 50 movimientos.
    • Número de jugadas completas: Comienza puesto a 1 y se incrementa tras cada movimiento de las negras.

Toda la información se codifica en una sola línea, pero un fichero acabado en .fen puede contener varias de estas líneas para mostrar diferentes posiciones de la partida.

La notación para la posición inicial de una partida sería:

tcadract/pppppppp/8/8/8/8/PPPPPPPP/TCADRACT b RDrd - 0 1

El formato EPD (Extended Position Description) Es muy similar a FEN, pero añade una serie de campos de acciones que complementan la información del tablero.

La notación de partidas como vimos antes se puede hacer de variadas maneras imponiéndose la notación algebraica de un tiempo a esta parte. La mayoría de las bases de datos que se pueden encontrar en un formato que se denomina PGN (Portable Game Notation). Por ejemplo, una partida podría tener la siguiente forma:

[Event "Informal Game"]
[Site "London, England ENG"]
[Date "1851.07.??"]
[Round "-"]
[White "Anderssen, Adolf"]
[Black "Kieseritzky, Lionel"]
[Result "1-0"]

1.e4 e5 2.f4 exf4 3.Bc4 Qh4+ 4.Kf1 b5 5.Bxb5 Nf6 6.Nf3 Qh6 7.d3 Nh5 8.Nh4 Qg5
9.Nf5 c6 10.g4 Nf6 11.Rg1 cxb5 12.h4 Qg6 13.h5 Qg5 14.Qf3 Ng8 15.Bxf4 Qf6
16.Nc3 Bc5 17.Nd5 Qxb2 18.Bd6 Bxg1 19.e5 Qxa1+ 20.Ke2 Na6 21.Nxg7+ Kd8
22.Qf6+ Nxf6 23.Be7# 1-0

Se puede observar dos partes perfectamente diferenciadas: una cabecera con etiquetas encerradas en [...] con una estructura de [etiqueta "valor"], seguida de un bloque con las jugadas que componen la partida. Cada jugada completa va precedida de su número de orden, con un punto, y todo está separado por espacios o saltos de línea. Un fichero .pgn es básicamente un fichero de texto plano con una o varias partidas. Hay algunos que son un compendio de miles de ellas y las búsquedas y manejo se hacen tediosos con un editor de texto.

Implementación

¿Por dónde empezar? En principio, se podría pensar que no hace falta que el tablero sepa las reglas del ajedrez para implementar uno que sea capaz de cargar esas partidas y estudiarlas o incluso que sirva para jugar alguna partida. Sería como jugar con un tablero físico con sus fichas, la madera pintada no tiene consciencia de regla o norma alguna más allá de quedarse donde la mano la suelte. Sin embargo, al encontrarse algo como "Ng8" debe saber que es un caballo, pero además debe saber cuál de los dos que puede tener el jugador puede mover a la coordenada g8. Por tanto, se hace necesario que el programa conozca toda la reglamentación del ajedrez.

De momento, el proyecto se llama ŝako, ajedrez en Esperanto, aunque lo escribo shako por si alguna herramienta (no lo he comprobado) tiene algún problema con caracteres unicode que estén más allá del ASCII.

La forma más sencilla de implementar un tablero es utilizar un array de 64 caracteres:

type
  Tablero* = ref object
    tablero: array[64, char]

Podemos convertir de manera sencilla una cadena de dos caracteres alfanuméricos en una posición en ese array. Se podría implementar un diccionario que buscará la cadena y devolviera un entero con la posición de la casilla buscada en el array. En mi caso me he decantado por tener un array con las coordenadas:

 const
  coordenadas = [
    "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8",
    "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
    "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
    "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
    "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
    "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
    "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
    "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1"]

proc posicion*(t: Tablero, pos: string): char =
  var casilla: uint8 = coordenadas.find(pos).uint8()
  return t.tablero[casilla]

Así, con poco esfuerzo podemos mostrar el tablero por pantalla escribiendo el array hacia adelante:

const
  tableroInicial = [
    't', 'c', 'a', 'd', 'r', 'a', 'c', 't',
    'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p',
    '.', '.', '.', '.', '.', '.', '.', '.',
    '.', '.', '.', '.', '.', '.', '.', '.',
    '.', '.', '.', '.', '.', '.', '.', '.',
    '.', '.', '.', '.', '.', '.', '.', '.',
    'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P',
    'T', 'C', 'A', 'D', 'R', 'A', 'C', 'T']

proc mostrarTablero*(t: Tablero): string =
  for i in 0 .. 63:
    if (i mod 8) == 0:
      result.add('\n')
    result.add(t.tablero[i])
    result.add(' ')
  return result

El procedimiento mostrarTablero lo que hace es recorrer el array que representa el tablero, carácter a carácter y lo va añadiendo a una cadena dejando un espacio en blanco entre los caracteres y añadiendo un salto de línea cuando la posición del array sea múltiplo de 8.

Para mostrar el tablero desde la posición del jugador de negras se invierte el proceso:

proc mostrarTableroNegras*(t: Tablero): string =
  for i in countdown(63, 0):
    if (i mod 8) == 0:
      result.add(t.tablero[i])
      result.add('\n')
    else:
      result.add(t.tablero[i])
      result.add(' ')
  return result

Hasta ahora no es mucho, lo que llevo hecho, apenas un par de tests y cuatro funciones básicas para limpiar el tablero, iniciar uno con el procedimiento partidaNueva, la posibilidad de obtener la ficha de una determinada casilla, bien de manera numérica o por coordenada y algunos tests para comprobar que todo va funcionando. De momento no enseño mucho el código. Por ejemplo, me he hecho un script en bash para manejar nimble de manera más sencilla:

#!/bin/bash

function crear_docs () {
    nimble doc -o:doc/shako.html src/shako.nim
    nimble doc -o:doc/tablero.html src/tablero.nim
}

if [ $1 = 'run' ] ; then
    nimble c -r -o:bin/shako src/shako.nim
fi
if [ $1 = 'doc' ] ; then
    crear_docs
fi
if [ $1 = 'all' ] ; then
    nimble test
    nimble c -r -o:bin/shako src/shako.nim
    crear_docs
fi
if [ $1 = 'tests' ] ; then
   nimble test
fi
if [ $1 = 'clean' ] ; then
   rm -rf ./bin
   rm -rf ./doc
fi

La salida de todo el proceso, de momento queda así:

> ./make.sh all
  Verifying dependencies for shako@0.0.1
  Compiling /home/notxor/proyectos/shako/tests/test_tablero (from package shako) using c backend

[Suite] Prueba del módulo «tablero»
  [OK] Un tablero vacío
  [OK] Iniciar tablero a partida nueva
  [OK] Posiciones por cadena de coordenada
   Success: Execution finished
   Success: All tests passed
  Verifying dependencies for shako@0.0.1
  Compiling src/shako (from package shako) using c backend
Tablero en memoria:

t c a d r a c t 
p p p p p p p p 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
P P P P P P P P 
T C A D R A C T 
Tablero desde negras:
T C A R D A C T
P P P P P P P P
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
p p p p p p p p
t c a r d a c t

   Success: Execution finished
  Verifying dependencies for shako@0.0.1
 Generating documentation for src/shako (from package shako) using doc backend
   Success: Execution finished
  Verifying dependencies for shako@0.0.1
 Generating documentation for src/tablero (from package shako) using doc backend
   Success: Execution finished

Conclusiones

De momento, el programa está en mantillas. Si alguien espera poder analizar partidas con él tendrá que esperar mucho tiempo, por lo que es recomendable que espere sentado o en posiciones aún más cómodas y que no olvide hidratarse y alimentarse para poder sobrellevar mucho mejor la espera. Pero si no puedes esperar, te recomiendo SCID. Que es más o menos similar a lo que pretendo hacer.

Como me he puesto con este proyecto, amenazo con una serie de artículos sobre su implementación. Avisados estáis. Lo siguiente será la posibilidad de que entienda mínimamente la notación FEN para poder iniciar el tablero de una manera más o menos directa. Sería el primer modo de pasarle partidas e implementar algunas de las reglas básicas como la de los 50 movimientos que dice que la partida se acaba si se alcanzan 50 movimientos sin que se mueva un peón o sin que una pieza capture otra, o también las que gobiernan los enroques.

Categoría: Ajedrez nim

Comentarios

Debido a algunos ataques mailintencionados a través de la herramienta de comentarios, he decidido no proporcionar dicha opción en el Blog. Si alguien quiere comentar algo, me puede encontrar en esta cuenta de Mastodon, también en esta otra cuenta de Mastodon y en Diaspora con el nick de Notxor.

Si usas habitualmente XMPP (si no, te recomiendo que lo hagas), puedes encontrar también un pequeño grupo en el siguiente enlace: notxor-tiene-un-blog@salas.suchat.org

Disculpen las molestias.