Otro libro interesante

Hace un par de meses me compré el libro “Commodore 64 Exposed”. Por lo visto, es un libro de 1983 que se ha reeditado ahora con la fiebre de la programación retro.

C64 Exposed

El libro está bien. Son algo menos de 200 páginas en las que se tratan:

  • La programación en BASIC.
  • Los comandos de BASIC.
  • Técnicas avanzadas en BASIC.
  • Sonido.
  • Gráficos.
  • Código máquina.
  • Dispositivos externos.
  • Apéndices.

Como os imagináis, con esa extensión y variedad de temas, los asuntos tampoco los puede tratar en mucha profundidad. Casi todo lo ahí mencionado (código máquina, sonido, gráficos, etc.), quitando la parte inicial de BASIC, lo encontraréis tratado con mucho más detalle en este blog y sus libros asociados (volumen I y volumen II).

Lo que sí me ha llamado la atención, porque no lo conocía, es el formato en que se almacenan en memoria los programas en BASIC. Aparece descrito en la página 45. El formato es así (para cada línea del programa):

  • Dos bytes para la dirección en memoria de la siguiente línea. Si valen $0000 es el final del programa.
  • Dos bytes para el número de línea BASIC.
  • El texto de la línea BASIC. Los comandos están tokenizados, es decir, se convierten a unos códigos (ej. $9e para SYS). Lo demás, se almacena tal cual en codificación PETSCII.
  • Un byte $00 para marcar el fin de línea.

Todo esto es fácil de comprobar arrancando VICE, introduciendo un programa BASIC, arrancando el monitor con ALT + M, y revisando las posiciones de memoria $0801 y siguientes.

BASIC

Que lo disfrutéis si os animáis a leerlo.

RYG: inicios y finales de partida

Los aficionados al ajedrez sabrán que es muy habitual estudiar aperturas y finales de partida, porque son situaciones especiales en las que conviene saber cómo actuar. Pues bien, una funcionalidad interesante para el juego consiste en añadir una “base de datos” de inicios y/o finales de partida.

Los inicios de partida son fáciles de añadir, porque es fácil identificar cuándo una partida se encuentra al inicio. Por ejemplo, si el número de movimientos aplicados es menor que X está claro que estamos ante un inicio de partida.

Por el contrario, los finales de partida son mucho más difíciles de identificar y, por tanto, de aplicar. No hay un umbral de movimientos a partir del cual podemos suponer que estamos ante un final de partida. Por tanto, se trata más bien de reconocer situaciones o patrones (ej. número de piezas, posiciones, etc.). En consecuencia, es algo bastante más complejo de implementar.

En el caso que nos ocupa, siempre que el número de movimientos esté por debajo de 8, el ratón no habrá podido alcanzar la formación de los gatos y, por tanto, no podrá condicionar ni limitar los movimientos de estos. Por tanto, por debajo de 8 movimientos podremos aplicar una secuencia de movimientos fija (o varias) que sea de interés para los gatos. A partir del movimiento 9, en cambio, el ratón ya habrá podido alcanzar a los gatos y, por tanto, los movimientos posibles para los gatos ya dependerán de cómo se haya movido el ratón.

Inicios de partida

Como a los gatos les interesa mantener una formación cerrada, una posible “base de datos” de movimientos al inicio de la partida consiste hacer los movimientos 1, 3, 5 y 7 como se muestra en la imagen anterior.

Implementar lo anterior es fácil. En vez de construir un árbol de jugadas, evaluarlo, aplicar minimax y elegir la jugada que minimiza la evaluación en todo caso, haremos lo siguiente:

  • Por debajo de la jugada 8, aplicaremos la “base de datos” de movimientos. Da igual lo que haya movido el ratón.
  • Por encima de la jugada 8, actuaremos como hasta ahora, es decir, construiremos el árbol de jugadas, lo evaluaremos, aplicaremos minimax, y optaremos por la jugada que minimiza el valor (porque el C64 mueve a los gatos).

Para ello, en el fichero principal “RYG.asm” dotamos la nueva rutina “decideBDvsArbol” que lo primero que hace es mirar en qué número de movimiento estamos (nivel):

Rutina decideBDvsArbol

Por debajo de 8 (bcc), saltamos a la etiqueta “dbdaBaseDatos”, que se encarga de aplicar la “base de datos” de jugadas de inicio. Por encima de 8, continuamos con la etiqueta “dbdaArbol”, es decir, continuamos con la operativa normal hasta ahora:

Arbol

En cambio, cuando se trata de aplicar la “base de datos” de jugadas la novedad es como sigue:

Base de datos inicio

Es decir, movemos el nivel o número de jugada (que en ese momento está en el acumulador) al registro X y, usando X como índice, accedemos a una tabla doble de gatos y offsets:

Base datos gatos y offsets

Esta tabla doble es propiamente la “base de datos de jugadas” ya que, para un número de jugada (valor del índice X), nos dice qué gato hay que mover (tabla “tablaNumGatos”) y a qué offset hay que moverlo (tabla “tablaOffsets”).

A los gatos les corresponden los movimientos 1, 3, 5 y 7. En el movimiento 1 hay que mover el gato 0 al offset 9, en el movimiento 3 hay que mover el gato 1 al offset 11, en el movimiento 5 hay que mover el gato 2 al offset 13 y, por último, en el movimiento 7 hay que mover el gato 3 al offset 15. Todo lo demás son ceros de relleno que corresponden a los movimientos del ratón.

De este modo, al arrancar la partida veremos que el C64, es decir, los gatos, mueve siempre la secuencia anterior. Ni siquiera veremos que aparece “PENSANDO: XXXX”, ya que el C64 no está pensando nada, no está generando un árbol de jugadas, sino que juega “a tiro hecho”.

Todo esto da lugar a la versión 19 del proyecto.


Código del proyecto: RYG19