Pipe-ManiaK para ZX-81

Foro dedicado a la programación en todo tipo de sistemas clásicos.
dancresp
Amiga 1200
Amiga 1200
Mensajes: 1393
Registrado: 23 Dic 2008, 17:53
Sistema Favorito: MSX
primer_sistema: ZX81
Primera consola: Atari 2600
Gracias dadas: 3 veces
Gracias recibidas: 20 veces

Pipe-ManiaK para ZX-81

Mensajepor dancresp » 23 Ene 2015, 23:37

PipeManiaK_3.gif
PipeManiaK_3.gif (2.67 KiB) Visto 7097 veces


EL JUEGO
Pipe Mania es un videojuego de puzzle desarrollado en 1989 por The Assembly Line para Amiga. Posteriormente LucasFilm Games hizo versiones para otras máquinas bajo el nombre de Pipe Dream.

El título está protagonizado por un fontanero, Alfonzo, cuyo objetivo es encajar piezas de tubería que aparecen aleatoriamente en una matriz en la que hay un grifo del que sale agua.

El objetivo de esta versión consiste en montar una estructura de tuberías que lleve el agua desde la esquina superior izquierda, donde sale la primera pieza, hasta la esquina inferior derecha, donde hay el agua. Hay que tener en cuenta que tanto al inicio como al final el agua avanza hacia la derecha.

Para conseguir nuestro objetivo disponemos de un total de 30 piezas que debemos colocar en una zona de juego de 5 filas y 6 columnas. La puntuación final dependerá de las piezas usadas y la longitud alcanzada. Cada pieza proporciona entre 1 y 7 puntos, en función de su forma.

Si hemos montado la estructura y todavía disponemos de piezas, simplemente hay que situarse en una posición apartada y dejar apretada la tecla “0”. Al colocar la última pieza el ZX-81 calculará si la estructura es correcta y la puntuación. Si la estructura está mal montada o no llega hasta el final aparecerá un ERROR 3 en pantalla, y si es correcta aparecerá un ERROR 2 y los puntos conseguidos.

EL bloque cursor va cambiando entre la pieza que hay en esa posición y la pieza que se debe colocar. Si las dos piezas son iguales no parpadeará. En caso de duda, mover el bloque cursor para ver claramente la pieza a colocar.

Hacer RUN para jugar otra partida.

Controles:
Controla el bloque cursor con “5” – “6” – “7” – “8” y pulsa “0” para colocar un segmento de tuberías.

Descargar el juego en formato ".P":
PipeManiaK.rar
(555 Bytes) Descargado 305 veces


BLOQUES
Se ha dividido el listado en 5 bloques:

- Declaración de las variables.
- Control del cursor.
- Colocar segmento de tuberías.
- Comprobar la estructura.
- Rutina para imprimir un bloque.


COMO FUNCIONA
Todo el programa ocupa 28 líneas.

2 – La variable “P” se usa como puntero al buffer de la impresora.
4 – La variable “D” se usa como constante “2” y como indicador de dirección.
6 – La variable “X” contiene la posición horizontal del cursor.
8 – La variable “Y” contiene la posición vertical del cursor.
9 – La variable “N” contiene el número de bloques disponibles y posteriormente como contador de puntos.
10 – Mostramos el punto final donde debe llegar la estructura de tuberías.
18 – Guardamos en la variable “T” la pieza a colocar. Valor aleatorio entre 1 y 7.
20 – Consultamos la posición de memoria donde está el cursor para ver la ficha que hay y lo guardamos en “G”.
22 – Llamamos a la rutina que imprime el bloque correspondiente, indicado por “G”.
24 – Consultamos el teclado para ver si se debe mover el cursor horizontalmente. Controlamos los límites.
26 – Consultamos el teclado para ver si se debe mover el cursor verticalmente. Controlamos los límites.
28 – Ponemos en “G” el código del bloque a colocar, indicado por “T”.
30 – Llamamos a la rutina que imprime el bloque correspondiente, indicado por “G”.
32 – Si no se pulsa “0” volvemos a la línea 20.
34 – Guardamos el bloque colocado en la posición correspondiente del buffer de la impresora.
36 – Restamos el número de bloques pendientes de colocar, indicado por “N”.
38 – Si todavía quedan bloques saltamos a 18 para elegir el nuevo bloque a colocar.
40 – Calculamos la nueva dirección del agua (“D”) en función de la forma del tubo (PEEK P) y la dirección actual.
42 – Sumamos los puntos en función del tubo por el que pasa el agua.
44 – Modificamos el puntero “P” en función de la dirección para consultar el siguiente segmento.
46 – Si “P=16474” el agua ha llegado al destino y muestra la puntuación, y una variable inexistente que detiene el programa.
48 – Como el agua sigue avanzando saltamos a 40.
50 – Calculamos los segmentos del bloque indicado por “G” que imprimiremos en la línea 54.
52 – Inicio de un bucle que se repetirá dos veces.
54 – Imprimimos en la posición “Y, X” una de las dos líneas que forman la pieza indicada por “G”.
56 – Incrementamos “G” en dos para dibujar la segunda línea del bloque.
58 – Final del bucle.
59 – Volvemos a la línea siguiente de la llamada a esta subrutina.


EL LISTADO
Listado.gif
Listado.gif (11.04 KiB) Visto 7097 veces


APUNTES FINALES
Al finalizar mi último proyecto de 1K para el ZX-81 estuve pensando en hacer un juego de acción en el que usara los cursores. No se como me vino a la cabeza el “Pipe-Mania” pero acepte el reto de adaptarlo. En un principio estaba pensado para usar piezas de un único carácter, pero dándole vueltas al tema comprobé que evidentemente según que piezas no encajaban entre si por la forma de los caracteres gráficos del ZX-81. Así que llegué a la conclusión de que debería usar bloques de 2x2, con lo que la zona de juego se reducía y los requisitos de memoria crecían...

Aunque la primera versión debía ser ésta, me decidí a programar primero la del ORIC y de esa forma resolvería las partes más complejas. Queda pendiente una versión MSX más lucida gráficamente ya que no tendré las limitaciones con los colores del ORIC.

En unas 5 horas durante dos días he dejado esta versión lista, no sin bastantes dolores de cabeza, ya que si bien las tuberías se colocaban y el sistema detectaba si la estructura era correcta, no tenía suficiente memoria para darle forma de juego. No sabía si poner tiempo, indicar las siguientes fichas, hacer que al superar un nivel el siguiente fuera más complejo, etc.

Por ello, esta versión es como es, prescindiendo del funcionamiento del juego original pero usando la misma mecánica de encajar tuberías, y limitándolo a un único nivel en el que hay que intentar montar la estructura más compleja y larga con un máximo de 30 piezas.

Para ello, las piezas puntúan distinto según la forma que tienen, ya que los segmentos que “apuntan” hacia la derecha puntúan menos que los que lo hacen hacia la izquierda, por ejemplo.

Y la verdad es que he quedado muy satisfecho ya que todo el conjunto funciona perfectamente, y encima se deja jugar.

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, ya que un ZX-81 básico dispone de 1024 bytes de RAM libres de los que los primeros 125 los usan las variables de sistema y la memoria de video para el tablero de juego ocupa 12x10=120 bytes, más los 25 bytes de final de línea. También necesitaremos 7 variables numéricas que ocupan 7 bytes cada una. Así que antes de hacer nada ya hemos consumido 319 bytes, algo más del 30% de la RAM. Y siempre va bien dejar algo de memoria para los stacks de llamadas y del calculador.

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 un byte extra por cada instrucción o carácter de la línea. El no poder meter varías sentencias en una misma línea no ayuda a ahorrar memoria.

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. Este proyecto tal cual está ocupa 512 bytes, y incorporar alguna línea de código extra provoca el error 4 de memoria llena.

El juego es así porque...
Con todo lo visto anteriormente, decidí desde un principio usar el buffer de la impresora para almacenar el tipo de tubería que hay en cada posición. El buffer de la impresora empieza en la dirección 16444 y tiene un tamaño de 33 bytes. Haciendo una zona de juego de 5 filas y 6 columnas ocuparán 30 bytes y quedan 3 libres que no se usarán. Otra cosa buena de usar este buffer es que los bytes se inicializan a 0 cada vez que se hace RUN o se sale del programa, con lo que me ahorro ponerla a 0. Esto ha sido básico para haber conseguido encajar el juego en un ZX-81 básico.

Así, cada una de estas 30 posiciones puede tener un valor entre 0 y 7. El 0 corresponde a una casilla vacía y el resto al tipo de tubería que se ha colocado. Para saber donde estamos alterno la impresión de la pieza de la posición con la de la a colocar. De esta forma, si la casilla está vacía la pieza a colocar aparece y desaparece, pero si ya hay una pieza la forma alterna entre ellas siendo confuso a veces. Para salir de dudas lo mejor es colocar el bloque cursor en una posición vacía.

Visto que no era posible usar tiempo, ya que el juego no es especialmente rápido, he optado por un estilo más estratégico en el que a parte de intentar llegar al destino, se intente hacer alguna estructura compleja para obtener más puntos.

Una de las formas de añadir complejidad al juego ha consistido en poner un máximo de 30 piezas a colocar, pudiéndose terminar antes de haber completado la estructura. El resto del reto consiste en intentar obtener el máximo de puntos, ordenando los tipos de pieza en función de su complejidad para ser encajado con otras y hacer avanzar el agua hacia la derecha.

Se ha decidido iniciar el juego desde la esquina superior izquierda y terminar en la esquina inferior derecha porque de esta forma la inicialización de las variables “X” e “Y” ocupa menos memoria, se obliga a hacer una estructura de un mínimo de 10 piezas y sobretodo porque es más sencillo detectar si se ha llegado a la posición final, ya que la dirección resultante de multiplicar “Y*5” y sumar “X” queda fuera del rango de la posición final.

Y el agua fluye...
La principal y casi única dificultad del proyecto, a parte de encajarlo en poco más de 500 bytes, ha consistido en hacer circular el agua por la tubería, y aunque en un principio parecía un tema bastante complejo, encontré una solución bastante sencilla y rápida que ya apliqué en la versión ORIC. Aquí se ha tenido que simplificar y en lugar de tratar la pieza en función de los segmentos de tubería que contiene (3 en ORIC) aquí se a aplicado a la pieza entera, ya que a diferencia de la versión ORIC, aquí no se va viendo como el agua circula.

De esta forma, al colocar la última pieza de las 30 disponibles, el programa empieza a calcular el recorrido automáticamente mediante el bloque comprendido entre las líneas 40 y 48, de la siguiente forma:

1. Disponemos de 7 tipos de bloques distintos para montar nuestro circuito.

PipeManiaK_Piezas.gif
PipeManiaK_Piezas.gif (1.13 KiB) Visto 7097 veces


2. El agua puede tener 4 posibles direcciones, numeradas siguiendo el sentido de las agujas del reloj:
1 – Subir, 2 – Derecha, 3 – Bajar y 4 – Izquierda.

3. En la posición de memoria apuntada por “P” tenemos la forma de la pieza a analizar. Toda la tira de números de la línea 40 lo forman 8 bloques de 4 cifras cada uno, según el código de la pieza. El 0 corresponde a una posición vacía. En el bloque de 4 cifras, la posición indica la dirección por la que entra el agua y el valor de esa posición indica la nueva dirección que ha de tomar el agua. En esta línea calculamos la nueva dirección por donde debe seguir avanzando el agua. Si el valor es 0 quiere decir que ha entrado por una dirección incorrecta.

4. Por ejemplo, el segmento de tubería 6 (codo inferior/izquierda) es “4300”. Así, si entra agua sube y entra por debajo (dirección 1) se cambia a izquierda (dirección 4). Si entra avanza hacia la derecha (dirección 2) se cambia a bajar (dirección 3). Pero si el agua viene desde la arriba o desde la izquierda el valor es “0” y finaliza la partida.

5. La línea 44 calcula la nueva posición de memoria a la que debe apuntar la variable “P”, en función de la nueva dirección. Esto significa que se puede sumar o restar 1 si el avance es horizontal, y sumar o restar 6 si el avance es vertical. Si la nueva dirección es 0, provoca un error 3 ya que el valor debe estar entre 1 y 4. Es una forma sencilla y “económica” en memoria de detener el programa si se ha montado mal la estructura.

6. Si la variable “P” vale 16474, dirección fuera del buffer de la impresora, significa que el agua ha llegado bien a su destino, mostrando la puntuación y finalizando el programa provocando un error 2 al intentar mostrar el valor de la variable inexistente “A”.

PipeManiaK_Bloque.gif
PipeManiaK_Bloque.gif (4 KiB) Visto 7087 veces


Pues nada más, solo me queda esperar que os guste.


Os invito a probarlo.

PipeManiaK_4.gif
PipeManiaK_4.gif (2.84 KiB) Visto 7097 veces

PipeManiaK_5.gif
PipeManiaK_5.gif (3.07 KiB) Visto 7097 veces

PipeManiaK_3.gif
PipeManiaK_3.gif (2.67 KiB) Visto 7097 veces

PipeManiaK_Listado.gif
PipeManiaK_Listado.gif (9.43 KiB) Visto 7097 veces
Buscando la IP de la W.O.P.R.

Avatar de Usuario
6128
Amiga 2500
Amiga 2500
Mensajes: 2823
Registrado: 27 Ene 2010, 18:06
Sistema Favorito: Amstrad CPC
primer_sistema: Amstrad CPC
consola_favorita: Sega Genesis/Megadrive
Primera consola: Sega Genesis/Megadrive
Ubicación: León
Gracias dadas: 133 veces
Gracias recibidas: 33 veces

Re: Pipe-ManiaK para ZX-81

Mensajepor 6128 » 24 Ene 2015, 00:43

Macho, le das a todo. Bravo. =D>

dancresp
Amiga 1200
Amiga 1200
Mensajes: 1393
Registrado: 23 Dic 2008, 17:53
Sistema Favorito: MSX
primer_sistema: ZX81
Primera consola: Atari 2600
Gracias dadas: 3 veces
Gracias recibidas: 20 veces

Re: Pipe-ManiaK para ZX-81

Mensajepor dancresp » 26 Ene 2015, 10:04

6128 escribió:Macho, le das a todo. Bravo. =D>

Gracias.

Pero...¿Alguien sabe algo de antoniovillena? :-ss

Hace unos aportes de lo más interesantes a mis programas de ZX-81 1K, y creo que esta vez se lo he puesto muy difícil... :twisted:
Buscando la IP de la W.O.P.R.

Avatar de Usuario
antoniovillena
Amiga 1200
Amiga 1200
Mensajes: 2013
Registrado: 16 Abr 2012, 21:22
Gracias recibidas: 8 veces

Re: Pipe-ManiaK para ZX-81

Mensajepor antoniovillena » 26 Ene 2015, 22:15

Estoy un poco perdido. Pero mañana volveré y le echaré un vistazo.

Challenge accepted!!!

-- Actualizado 27 Ene 2015, 17:30 --

Empiezo pasando a ASCII tu programa:

Código: Seleccionar todo

    2 LET P= 0|16444
    4 LET D= VAL "2"
    6 LET X= NOT PI
    8 LET Y= X
    9 LET N= CODE "2"
   10 PRINT AT VAL "9", CODE "\\";"\!'"
   18 LET T= INT (RND*VAL"7") + SGN PI
   20 LET G= PEEK (P+Y*VAL"6"+X)
   22 GOSUB CODE "M"
   24 LET X= X-(INKEY$="5" AND X)+(INKEY$="8" AND X<VAL "5")
   26 LET Y= Y-(INKEY$="7" AND Y)+(INKEY$="6" AND Y<VAL "4")
   28 LET G= T
   30 GOSUB CODE "M"
   32 IF INKEY$<>"0" THEN GOTO CODE "="
   34 POKE P+Y*VAL "6"+X, T
   36 LET N= N-SGN PI
   38 IF N THEN GOTO CODE ">"
   40 LET D= VAL"\
0000\
1234\
0204\
1030\
0021\
2003\
4300\
0140\
"(PEEK P*VAL "4"+D)
   42 LET N= N+PEEK P
   44 LET P= P+CODE "0"-CODE "6.-1"(D)
   46 IF P=0|16474 THEN PRINT N, A
   48 GOTO CODE "C"
   50 LET G= G*VAL "4"+SGN PI
   52 FOR F= NOT PI TO SGN PI
   54   PRINT AT Y*D+F, X*D; "    \
\.:\:.\':\:'\
\..\..\''\''\
\ :\: \ :\: \
\ :\:.\ '\''\
\ .\..\ :\:'\
\..\. \':\: \
\.:\: \''\' \
"(G TO G+SGN PI)
   56 LET G= G+D
   58 NEXT F
   59 RETURN


A ver lo que consigo optimizar

-- Actualizado 27 Ene 2015, 18:11 --

Esta vez me lo has puesto muy difícil. De momento sólo he recortado 8 bytes, y no creo que optimice mucho más.

Código: Seleccionar todo

    2 LET P= 0|16444
    4 LET D= VAL "2"
    6 LET X= NOT PI
    8 LET Y= X
    9 LET N= CODE "2"
   10 PRINT AT VAL "9", CODE "\\";"\!'"

   18 LET T= INT (RND*VAL"7") + SGN PI

   20 LET G= PEEK (P+Y*VAL"6"+X)
   22 GOSUB CODE "M"
   24 LET X= X-(INKEY$="5" AND X)+(INKEY$="8" AND X<VAL "5")
   26 LET Y= Y-(INKEY$="7" AND Y)+(INKEY$="6" AND Y<VAL "4")
   28 LET G= T
   30 GOSUB CODE "M"
   32 IF INKEY$<>"0" THEN GOTO CODE "="
   34 POKE P+Y*VAL "6"+X, T
   36 LET N= N-SGN PI
   38 IF N THEN GOTO CODE ">"

   40 LET D= VAL"\
0000\
1234\
0204\
1030\
0021\
2003\
4300\
0140\
"(PEEK P*VAL "4"+D)
   42 LET N= N+PEEK P
   44 LET P= P+CODE "0"-CODE "6.-1"(D)
   46 IF P=0|16474 THEN PRINT N, A
   48 GOTO CODE "C"

   50 FOR F= NOT PI TO SGN PI
   52   PRINT AT Y*D+F, X*D; "    \
\.:\:.\':\:'\
\..\..\''\''\
\ :\: \ :\: \
\ :\:.\ '\''\
\ .\..\ :\:'\
\..\. \':\: \
\.:\: \''\' \
"(G*VAL "4"+F*D+SGN PI TO G*VAL "4"+F*D+D)
   54 NEXT F
   56 RETURN

Avatar de Usuario
Ivanzx
Amiga 1200
Amiga 1200
Mensajes: 1618
Registrado: 05 Abr 2007, 19:39
Gracias recibidas: 21 veces
Contactar:

Re: Pipe-ManiaK para ZX-81

Mensajepor Ivanzx » 24 Sep 2016, 21:03

Hola también por aquí :)

Dancresp, me ocurre lo mismo que con el Jumping Jack, al intentar descomprimir para cargar el fichero me da un error raro, raro :)
Si pudieras volver a subir el juego, te lo agradecería.

Saludos!


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 10 invitados