Maze-K para ZX-81
Publicado: 28 Dic 2013, 17:24
EL JUEGO
El objetivo del juego consiste en conseguir salir de un laberinto que tiene un tamaño de 9x9=81 cuadrículas.
Cada cuadrícula puede mostrar entre 1 y 4 caminos, y nos moveremos con las teclas de los cursores 5, 6, 7 y 8.
El signo “+” que aparece a la derecha del laberinto nos indica la profundidad en la que nos encontramos.
La posición inicial es aleatoria, y al salir se muestra el número de movimientos realizados.
Descargar el juego en formato ".Z81" (Snapshot del EightyOne):
BLOQUES
He dividido el listado en 6 bloques:
- Datos del laberinto.
- Declaración de variables.
- Impresión de la cuadrícula del laberinto en la que estamos.
- Control del movimiento.
- Comprobar si se ha salido.
- Mostrar los movimientos realizados y fin del juego.
COMO FUNCIONA
A continuación detallo, línea por línea, el funcionamiento del programa.
Se utilizan las siguientes variables:
P – Puntero a la línea 1, que contiene el REM con los datos del laberinto.
T - Constante con valor 3, usado en distintas partes del programa.
S - Contador de movimientos realizados.
J - Usada para controlar si es una celda fija (1, 3, 5, 7, 9) o una celda variable (2, 4, 6, 8).
N - Valor numérico de la posición del laberinto en la que está el personaje.
B - Usada para obtener un bit de la variable “N”.
G – Tipo de gráfico a mostrar: 1 – Bloque, 10 – Personaje.
Y – Posición vertical del gráfico.
X – Posición horizontal del gráfico.
F – Variable para el bucle de impresión del gráfico.
K$ - Tecla que se ha pulsado.
1 - Línea REM que contiene los datos de las 81 casillas del laberinto.
10 - Guardamos el valor 16514 en la variable “P”. Apunta al primer carácter después del REM de la línea 10.
12 - Asignar a “T” el valor 3.
14 - Asignar a “S” el valor 0.
16 – Borrar la pantalla
18 – Asignar a “J” el valor de “T”, que es tres.
20 – Asignar a “B” el valor 16.
22 – Asignar a “N” el valor de la posición de memoria apuntado por “P” y restar 28 para obtener un valor entre 0 y 15.
24 – Inicio del bucle para imprimir los bloques verticales.
26 - Inicio del bucle para imprimir los bloques horizontales.
28 – Asignar a “G” el valor 1, correspondiente a un bloque.
29 – Si va a imprimir el bloque central asignar a “G” el valor 10, correspondiente al personaje.
30 – Si “J<>0” (bloques fijos) saltar a 38 para imprimir el gráfico del valor de “G”.
32 – Dividir el valor de “B” entre 2, para poder explorar el siguiente bit de “N”. Va de izquierda a derecha.
34 – Si el valor de “N” es inferior a “B” es que el bit explorado es igual a 0 y no imprime el bloque de camino.
36 – Restar a “N” el valor de “B”.
38 - Inicio del bucle que imprime el bloque gráfico.
40 – Imprimir en la posición correspondiente la parte del gráfico que toca.
42 – Incrementar el número del gráfico en 3.
44 – Final del bucle que imprime el bloque gráfico.
46 – Cambiar el valor de la variable “J” de “1 a 0” ó de “0 a 1”.
48 – Final del bucle horizontal.
50 – Final del bucle vertical.
51 – Mostrar el signo “+” para indicar a la profundidad a la que se encuentra el personaje.
52 – Esperar a que se pulse una tecla mediante un PAUSE con el valor de “P”, ya que no admite el PAUSE 0.
54 – Almacenar en “K$” el valor de la tecla pulsada.
56 – Movimiento horizontal si se pulsa “8” ó “5”
58 - Movimiento vertical si se pulsa “6” ó “7”
60 – Incrementar el contador de movimientos en 1.
62 - Si el puntero “P” es mayor o igual a 16514 es que esta dentro del laberinto y saltar a la línea 16.
64 – Mostrar el número de movimientos y finalizar el juego.
EL PROGRAMA
APUNTES FINALES
Después de las versiones 1K de los juegos “Minefield”, “Sudoku” y “Lights Out” tenía ganas de adaptar un juego tipo laberinto.
Para el desarrollo he vuelto a usar el emulador “EightyOne” con unos resultados muy satisfactorios.
Mi primera intención ha sido programar una mini-versión del clásico “MAZOGS”, pero al poco rato ya he visto que sería imposible meterlo en 1K.
Sumando bytes…
Como todo buen proyecto de ZX-81 con 1K lo primera es hacer una estimación de lo que debería ocupar cada parte del programa.
Un ZX-81 básico dispone de 1024 bytes de RAM libres.
Las variables de sistema ocupan 125 bytes y la memoria de video para el tablero de juego ocupa 9x9=81 bytes, más los 25 bytes de final de línea, ocupan unos 106 bytes.
Necesito 10 variables numéricas, que ocupan 7 bytes cada una y una alfanumérica que ocupa 2 bytes. Así que, en principio, las variables consumen unos 72 bytes más aprox. Los datos del laberinto ocupan 81 bytes más, y simplificando la complejidad de los cálculos se consigue que las rutinas del calculador no necesiten más que unos cuantos bytes.
Con todo esto, el programa no debería ocupar más de 600 bytes, aunque en la práctica la cosa quede sobre los 550 bytes.
Hay que tener en cuenta que cuenta que cualquier línea de código ocupa un mínimo de 6 bytes: 2 del número de línea, 2 del tamaño de la línea, 1 del final de línea y el resto según el contenido de la línea. El no poder meter varías sentencias en una misma línea no ayuda a ahorrar memoria.
Empieza el desarrollo
Lo más importante ha sido codificar los datos del laberinto en el mínimo espacio. Para ello he creado una codificación igual a la del juego “Light Out”. En cada posición puede haber entre 1 y 4 salidas. La combinación se hace usando los 4 bits de la derecha de un valor entre 0 y 15 (00h y 0Fh). Si hay muro en una dirección se pone su bit a 1 y se suman los valores: 8 – Superior, 1 – Inferior, 4 – Izquierda y 2 – Derecha. Esta codificación se introduce en el REM de la línea 1. Así, con solo 81 bytes he codificado el laberinto entero.
Como el almacenamiento de números no es muy eficiente y ocupa espacio tanto en el listado como en el área de variables, he declarado la variable “T=3” y se usa en distintos sitios del programa.
Con el bucle contenido entre las líneas 38 y 44 puedo imprimir el bloque que desee (G) en la posición correspondiente (X, Y).
El programa no controla que el movimiento que se realiza sea correcto, con lo que podemos atravesar paredes. En un principio esto no era así y almacenaba si había bloques en el camino guardando una serie de valores 1 y 0 en la zona del buffer de la impresora, y con otro puntero apuntaba allí. En la parte de los INKEY$ controlaba si el valor era 1 o 0 para aceptar el movimiento. Desgraciadamente esta parte se ha tenido que eliminar porque no quedaba espacio para poner el contador de movimientos ni el “+” que nos sirve como pista para saber a que profundidad nos encontramos.
La posición inicial se calcula aleatoreamente, modificando el valor del puntero “P”. Siempre empezamos a partir de la mitad inferior del laberinto. Y como curiosidad, hay una celda que permite pasar de la parte izquierda (fila 3 columna 1) a la derecha (fila 2 columna 9). Así se consigue que el laberinto sea “cilíndrico”.
Para saber si hemos salido del laberinto simplemente miro que el puntero apunte antes que el primer carácter de la línea REM. Si no es así vuelvo a imprimir el laberinto, y sino muestro los puntos y finaliza el juego.
¿Que se ha quedado en el tintero?
- Me gustaría poder validar que el movimiento que se realiza es correcto, pero no ha cabido.
- Encontrar un tesoro antes de salir, pero tampoco cabe.
Como curiosidad, si vamos pulsando la tecla “7” el puntero deja de apuntar en la línea REM y lo hace sobre el programa directamente. En este caso el resultado del laberinto puede ser ilógico.
Sea como sea, prueba superada ¡!!
Os invito a probarlo.