Chessy - Parte 1
“Voy a crear una app para reproducir partidas de ajedrez” fué lo que dije en el post anterior, y aquí están las primeras notas de lo que arbitrariamente decidí llamar chessy.
En este post explico cómo se graban los partidos de ajedrez, escribo algunas líneas del proceso que voy a seguir, detallo los primeros componentes que trabajé (UI y UI-Data) y finalmente agrego algunos detalles de la implementación.
Asumo que el lector medianamente sabe qué es ajedrez y cómo se juega. Si, por el contrario, estás más perdido que yo mirando cricket, acá te dejo mi buena acción del día: el ajedrez se juega de a 2, con piezas Blancas y Negras, sobre un tablero de 8x8, por turnos, y en cada turno algo cambia en el tablero: se mueven, quitan, o transforman piezas. De nada (?).
La parte interesante (para mí) es que la forma de grabarlas es en formato texto, simplemente escribiendo todos los movimientos que ocurrieron (además de otra info como la fecha, lugar, nombre de jugadores, etc). El formato estándard es PGN y podés mirar algunos ejemplos en su artículo de wikipedia. Las webs de los torneos, o incluso el de la federación, publican los partidos en éste formato. Por ejemplo: Norway Chess y FIDE World Championship 2018. Partidos como éstos son los que intento reproducir.
Proceso
Una vez leí sobre un principio llamado Tracer Bullet 1 (guía de bala, o algo así) que sugiere que uno comience creando un sistema incompleto, con detalles faltantes, con cosas mockeadas y simples, pero que funcione de punta a punta. Este serviría de guía (trace) para la bala (bullet) que viene después - el sistema completo. Se diferencia de ‘prototipado’ porque ahí uno prueba algo y después lo tira. Aunque hoy tenga algunas cosas claras en mi cabeza, hay varias otras que todavía no: cómo sería la versión final de la UI y qué información necesito usar en y entre cada componente. Por eso creo primero una algo simple (pero que funcione y esté testeado) que pueda ser completado en futuras iteraciones.
Los componentes con los que arranco son la UI (interfaz de usuario), y la información que ésta usa (UI Data).
La UI
La interfaz consiste en un tablero de ajedrez, las piezas correspondientes, y dos botones para que el usuario pueda avanzar o retroceder en el partido.
La interfaz debe ser extremadamente sencilla, limitada a mostrar cómo es el partido en un determinado momento del tiempo - nada más. No quiero agregar “lógica de negocios” acá (por ejemplo: calcular cuál es el estado del tablero dado un movimiento, marcar si hay jaque o si alguna pieza fue tomada, etc) por dos razones: planeo hacer más de una app - cuanto más sencillas mejor - y porque toda esa lógica no es tan sencilla como parece - mejor tener un sólo lugar que mantener.
La UI-Data
Para que esa super-simple UI sea posible, la información que usa tiene que estar lista para ser usada. En el contexto de reproducción de partidos de ajedrez eso significa que la información debe ser una sequencia de posiciones del tablero. Como, en lugar de eso, los partidos (formato PGN) tiene una lista de movimientos, éstos deberían ser pre-procesados a mi conveniencia y convertir: lista de movimientos a lista de posiciones del tablero.
La posición del tablero va a estar escrita en formato FEN (por suerte existe un estándar para eso) que consiste en una string de letras, números y barras. Por ejemplo, la posición en FEN rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
2 significa: comenzando desde arriba y a la izquierda del tablero, hay una torre (‘r’, por su inicial en inglés), caballo (n), alfil (b), reina (q), rey (k), alfil, caballo y una torre, en ese órden. En la fila siguiente (eso significa la barra /
) hay sólamente peones. En la tercera fila hay 8 casilleros vacíos (eso significa el número 8), y así sucesivamente. Las piezas Negras se escriben en minúsculas y las Blancas en mayúsculas.
Implementación
La primera UI es web sólo porque me resulta fácil modificarla. La hice usando Svelte porque es un framework que hace rato me venía intrigando. Sigue la onda de componentes y reactividad (como React, Vue, Angular) pero con un gran énfasis en performance. Usé Typescript donde pude 😎, y Javascript en lo demás 3 😢.
La web baja y reproduce el juego indicado por gameId
(el ?gameId=1
en la URL) que hoy por hoy pueden ser 1, 2, o 3. Más adelante habrán más partidos, y la elección va a ser a travez de algún menú o lista.
La primera versión está hosteada en vercel (unos genios estos muchachos) y el código de fuente en github. Podés usarla y ver cualquiera de los 3 juegos cambiando el número al final de la URL (los partidos son del Campeonato Mundial 2013 entre Anand y Carlsen).
La UI Data (lista de posiciones en FEN) se guarda en archivos en formato JSON. Por qué JSON? Simplemente porque es un formato muy conocido y todo lenguaje o framework tiene librerías para parsearlos. Además es flexible como para añadirle más información luego. Guardo los archivos en S3 solo por una cuestión de simplicidad; seguramente voy a usar una basa de datos después. Se puede ver un ejemplo de my UI Data abriendo un partido.
Y eso es todo por hoy! Quizás te quedó la pregunta “cómo hiciste para generar la lista de posiciones partiendo de un archivo en PGN?”. Buena pregunta! Gran tema para el siguiente post.◆
-
Lo leí en “The Pragmatic Programmer”. El principio en sí está mejor definido y es un poco más específico que mi libre interpretación. ↩
-
Estoy salteando la última parte de una posición escrita en FEN que indica quién juega luego, si está disponible el enroque, y demás. ↩
-
Svelte añade un par de elementos a la sintaxis de Javascript (por ejemplo
$:
) que se usa en los archivos.svelte
para los cuales no encontré aún soporte en Typescript. ↩