RYG: tableros más compactos – cambios en el código

Los cambios en el diseño del tablero tienen su impacto en el código del juego. Además de una reducción obvia en el tamaño de la estructura de datos (de 88 a 29 bytes) hay un cambio en el enfoque de los datos: antes teníamos una matriz de 8×8 casillas que podían estar vacías, ocupadas por un ratón o por gatos; ahora tenemos directamente la posición de los cinco protagonistas y todo lo demás se presupone vacío.

Lógicamente tienen que cambiar cosas en el código como la forma de generar las jugadas o la forma de evaluar los tableros. Sin embargo, como veremos más adelante, y sorprendentemente, los cambios son mucho más acotados de lo que podría parecer en un principio.

Nuevo tablero actual:

Si la estructura de datos del tablero cambia, lo primero que cambia es el tablero actual, el que controla la situación actual de la partida (ver fichero “Arbol.asm”). En vez de tener 88 bytes, tendrá 29.

Nuevas rutinas para el manejo de tableros:

Más importante que lo anterior, también cambian las rutinas que permiten manejar tableros, es decir, las rutinas del fichero “Tableros.asm”. Sorprendentemente, muchas rutinas no cambian porque sólo manejan los datos de los tableros que no hemos tocado (nivel, turno, valor, padre o hijos).

Sin embargo, otras rutinas sí tienen que cambiar:

  • La rutina “inicializaTablero” ya no tiene que rellenar un tablero con 64 casillas vacías. Ahora sólo tiene que fijar las posiciones iniciales del ratón (offset = 59) y los gatos (offsets = 0, 2, 4 y 6), ya que todo lo demás se presupone vacío.
  • Las rutinas “dameContenido” y “fijaContenido” dejan de tener sentido. Ya no tenemos 64 casillas que rellenar con un contenido (#Raton, #Gato o #Vacio). Ahora tenemos cinco bytes con las posiciones (offsets) de ratón y gatos. Estas posiciones se especifican con las nuevas rutinas “fijaPosicionRaton” y “fijaPosicionGato”.
  • Las rutinas “dameOffset” y “dameFilaCol” antes empezaban a contar los offsets desde el comienzo de la estructura de datos. Por tanto, la casilla (0, 0) del tablero recibía el offset 24. Ahora cambiamos el criterio y a la casilla (0, 0) le asignamos el offset 0.
  • Las rutinas “dameRaton” y “dameGato” antes recorrían la matriz de 8×8 casillas para buscar y localizar el ratón o el gato enésimo (su offset). Ahora no hace falta buscar nada; tenemos la información a tiro hecho en los cinco bytes que sustituyen a la matriz de 8×8. Por tanto, esas rutinas se sustituyen por las nuevas rutinas “damePosicionRaton” y “damePosicionGato”.

Y poco más hasta aquí.

Nueva generación de jugadas:

La generación de jugadas del ratón está en el fichero “GenJugadasRaton.asm”. La pieza clave anteriormente eran las tablas con los movimientos permitidos:

Movimientos ratón

Es decir, los cambios en la posición (fila, columna) podían ser:

  • ($ff, $ff) = (-1, -1).
  • ($ff, $01) = (-1, 1).
  • ($01, $01) = (1, 1).
  • ($01, $ff) = (1, -1).

Como ahora no tenemos una matriz de 8×8 posiciones, ni tampoco gestionamos las posiciones en formato (fila, columna), sino en formato offset, esa pieza clave se convierte en esta otra:

Movimientos ratón - offsets

Es decir, el offset del ratón puede variar en:

  • $f7 = -9.
  • $f9 = -7.
  • $09 = +9.
  • $07 = +7.

Estas variaciones corresponden a estos cuatro movimientos (suponiendo que el ratón estuviera en el offset 43):

Movimientos offsets

De este modo, generar los movimientos posibles consiste en tomar el offset actual (43), recorrer las cuatro posiciones de la tabla, e ir sumando:

  • 43-9=34.
  • 43-7=36.
  • 43+9=52.
  • 43+7=50.

En el fondo, muy parecido a lo que ya hacíamos antes, pero manejando variaciones en el offset (-9, -7, +9, +7) en vez de variaciones en filas y columnas.

Otra pieza importante es la validación de las jugadas. Para que éstas sean válidas las reglas son (antes y ahora):

  • Tienen que generarse conforme a las reglas de movimiento de las piezas.
  • El destino tiene que estar vacío.
  • El destino tiene que caer dentro de los márgenes del tablero.

La primera condición se garantiza por la forma de generar las jugadas, partiendo de una tabla (antes tablas) que recogen los movimientos válidos.

La segunda es igual de fácil de comprobar ahora que antes. Antes teníamos la (fila, columna) destino; ahora tenemos el offset destino. Si el offset destino está ocupado por el ratón o algún gato, no será un destino válido. En caso contrario, sí lo será.

Y la tercera condición cambia un poco. Antes comprobábamos si la fila o la columna eran menores que cero o mayores que siete. Ahora tenemos un offset entre 0 y 63, y sumar o restar 7 o 9 puede hacer que se traspasen los bordes del tablero sin detectarlo, si no hacemos nada especial. Por ejemplo, 47-7=40 o 47+9=56:

Movimientos offsets - bordes

Una forma inteligente de impedir estos traspasos es dándose cuenta de que ratón y gatos siempre se mueven por las casillas blancas (offsets en blanco) y, cuando tiene lugar un traspaso ilegal de este tipo, acaban en una casilla negra (ver 40 o 56). Por tanto, llega con validar que el offset de destino es blanco (0, 2, 4, 6, 9, 11, 13, 15, …, 61, 63). Esto se puede hacer con una tabla de offsets válidos:

Offsets válidos

Por lo demás, todas las rutinas de “GenJugadasRaton.asm” (generar jugadas, validar jugadas, generar jugadas válidas, etc.) son esencialmente iguales a las que ya había antes, con la salvedad de que las posiciones de origen y destino se especifican mediante offsets, y no mediante parejas (fila, columna).

Y lo mismo se puede decir de “GenJugadasGatos.asm”.

Otros cambios:

Los cambios principales son los ya comentados: rutinas para manejar tableros y generación de jugadas. En el código surgen más cambios (evaluación de tableros, etc.) pero son cambios derivados de los anteriores.

En particular, el hecho de cambiar las rutinas “dameRaton” y “dameGato”, que buscaban en la matriz 8×8, por las nuevas rutinas “damePosicionRaton” y “damePosicionGato”, que devuelven las posiciones a tiro hecho, implica bastantes cambios en la evaluación de tableros (“EvalTableros.asm”), pero son más estéticos (por el cambio de nombre en las rutinas) que otra cosa.

También hay cambios menores en “PintaTableros.asm”. Antes los tableros tenían una matriz 8×8 que pintar (con “G”, “R” o un “.”). Ahora gráficamente hay que pintar la misma matriz 8×8, porque la representación gráfica del tablero no ha cambiado, pero la información de partida es muy distinta (cinco offsets).

Los cambios en el programa principal “RYG.asm” también se limitan a manejar las posiciones mediante offsets, en vez de mediante filas y columnas, o bien cambios en los nombres de algunas rutinas llamadas. Además, está el cambio obvio de pasar de tres a cuatro niveles de profundidad que, no olvidemos, es el motivo por el que hemos montado todo este lío 🙂 .

Cuatro niveles

Por último, un cambio de presentación. Como ahora podemos analizar hasta cuatro niveles de profundidad, es decir, hasta 1024 tableros, pintar “PENSANDO:” y un punto por cada tablero son muchos puntos. Por ello, se prefiere pintar la dirección del tablero que se está generando. De este modo, consumimos menos pantalla, hacemos menos scroll, tenemos igual idea del avance, y encima sabemos si el árbol consume más o menos memoria:

Nuevo pensando

Todos estos cambios pueden verse en la versión 18 del proyecto. Lo bueno de esta versión es que ya permite hasta cuatro niveles de profundidad.

Ah, y una lección que ganamos: lo más intuitivo para el programador (ej. tener un tablero de 8×8) no es siempre lo más intuitivo ni lo mejor para la máquina.


Código del proyecto: RYG18

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s