BattleShips-1K para ZX-81

dancresp
Mensajes: 5017
Registrado: 13 Nov 2010 02:08
Agradecido : 17 veces
Agradecimiento recibido: 89 veces

BattleShips-1K para ZX-81

Mensajepor dancresp » 29 May 2014 20:24

bship_1.gif
bship_1.gif (48.42 KiB) Visto 1795 veces


EL PROGRAMA
Este programa es una sencilla versión del clásico juego de los barquitos para jugar contra el ZX-81.

Cada contrincante dispone de una flota de 5 barcos de dos posiciones cada uno.

En el tablero de 10x10 casillas se muestra la posición de los barcos del jugador y las tiradas que va realizando el ZX-81. El jugador deberá llevar el control de sus jugadas en una hoja de papel o jugando de memoria.

Inicia la partida el ZX-81 y de forma alternativa se van realizando las tiradas. En caso de que el ZX-81 toque un barco del jugador, vuelve a realizar una nueva tirada. A continuación tira el jugador introduciendo un valor formado por una letra y un número, correspondientes al formato "fila/columna”.

El primer jugador que hunde los cinco barcos del adversario gana la partida. Para iniciar una nueva partida se debe detener el programa con “BREAK” y hacer “RUN”.

Descargar el juego en formato ".z81" (Snapshot de EightOne):
BattleShips.rar
(1.06 KiB) Descargado 104 veces


BLOQUES
He dividido el listado en 6 bloques:

- Inicializar variables principales.
- Mostrar el tablero.
- Introducir la posición de los barcos de los dos jugadores.
- Tirada del ZX-81.
- Tirada del jugador.
- Rutina de entrada de datos del jugador y cálculo de la posición.


COMO FUNCIONA
El programa ocupa 30 líneas. A continuación detallo el funcionamiento de cada una.

Se utilizan las siguientes variables:
D – Variable que contiene el valor “10”.
M – Variable usada como puntero a la memoria del buffer de impresora.
F – Variable para bucles, o auxiliar en varios puntos.
X – Posición horizontal de la tirada.
Y – Posición vertical de la tirada.
A$ - Casilla donde se tira.

2 – Guardamos el valor 10 en la variable “D”. Se usará a lo largo del programa y permite ahorrar memoria.
4 – Guardamos el valor 16444 en la variable “M”. Se usa como puntero para guardar la posición de los barcos del ZX-81.
10 – Muestra el valor de las columnas.
12 – Inicio del bucle que dibuja el tablero.
14 – Muestra el valor de las filas.
16 – Final del bucle que dibuja el tablero.
20 – Inicio del bucle para introducir la posición de los barcos del jugador y del ZX-81.
22 – Saltamos a la línea 62 que pide la posición de la tirada del jugador.
24 – Mostrar el barco en la posición indicada.
26 – Posicionamiento de un barco por parte del ZX-81.
28 – Final del bucle de posicionamiento.
30 – Tirada aleatoria vertical del ZX-81.
32 – Tirada aleatoria horizontal del ZX-81.
34 – Posicionar el cursor en la posición de la tirada del ZX-81.
36 – Guarda en F el carácter que hay en esa posición de la pantalla.
38 – Si ya hay una “X” vuelve a la línea 30 para hacer una nueva tirada.
40 – Pone una “X” en la posición de la tirada y posiciona el cursor en la posición 20,0 para el mensaje del jugador.
42 – Si la tirada del ZX-81 no ha tocado un barco del jugador salta a la línea 50.
44 – Modifica la tirada horizontal del ZX-81, eligiendo la posición siguiente o anterior si se sale del tablero.
48 – EL ZX-81 vuelve a tirar.
50 - Saltamos a la línea 62 que pide la posición de la tirada del jugador.
52 – Inicio del bucle que revisa si se ha tocado alguno de los cinco barcos del ZX-81.
54 – Si la tirada coincide con la posición o posición contigua de un barco del ZX-81 pone “HIT” en pantalla.
56 – Final del bucle de revisión.
58 – Imprime tres espacios que pueden borrar el mensaje “HIT” de la tirada anterior.
60 – Salta a la línea 30 para una nueva tirada del ZX-81.
62 – Introducir la tirada del jugador.
64 – Calcular la posición vertical de la tirada.
66 – Calcular la posición horizontal de la tirada.
68 – Final y retorno de la subrutina.


EL PROGRAMA
listado.gif
listado.gif (75.39 KiB) Visto 36 veces


APUNTES FINALES
Después de varios juegos de un solo jugador y un par de proyectos más serios (FORTH y ASSEMBLER) para el ZX-81 tenía ganas de programar un juego en el que pudieras jugar contra el ordenador.

Mi primer intento ha sido este, y uno de los objetivos era hacer que el ordenador jugara con “cierta” inteligencia. Esto es que no tire dos veces en la misma casilla y que al tocar un barco del adversario intente hundirlo. Lo he conseguido “casi” todo, con matices.


La primera en la frente
Mi primer intento consistió en una versión en la que aparecían los dos tableros. El tema funcionaba bastante bien hasta que tuve que implementar las partes más complejas. Al poco apareció el fatídico error 4 de “No hay memoria”.

bship_5.gif


La memoria de pantalla se llevaba una cuarta parte de la RAM y no cabía el resto del programa. Pero bueno, durante un ratito a medio funcionado...

A partir de ese punto me he visto obligado a realizar los recortes oportunos para conseguir encajarlo en el mísero K de RAM.
El resultado es más que satisfactorio.


Metiendo un juego de los barquitos en 550 bytes y 30 líneas de código BASIC
Una vez me las he pasado canutas para conseguir hacer que funcione con las limitadas capacidades del ZX-81 básico. Y una vez más aquí ha estado la gracia del proyecto.

Como siempre, lo primero ha sido introducir una línea con la que voy controlando la memoria que ocupa el programa:
9999 PRINT (PEEK VAL"16396"+VAL"256"*PEEK VAL"16397")-VAL"16552"
Esta línea ocupa 43 bytes, que ganaré al borrarla al finalizar el desarrollo del programa, o antes si es preciso.

He usado los trucos habituales del ZX-81 para ahorrar memoria en el uso de valores numéricos. Así, “NOT PI” es 0 y "SGN PI" es 1, uso de VAL, y como el valor 10 se usa varias veces he asignado ese valor a la variable "D". Para valores de un dígito o que no puedo asignar con CODE uso VAL para dejar el programa algo más comprensible, y para el resto uso CODE.

Para este proyecto solo utilizo 5 variables numéricas, que voy reutilizando en distintas partes, y una alfanumérica donde almaceno la entrada del jugador. Con todo, esto ocupa unos 50 bytes.

Vamos por partes:

Dibujando el tablero
Esta parte se ha llevado 4 líneas simples de código. Eso si, la memoria de video puede llegar a ocupar un total de 156 bytes entre el tablero (11x11), el mensaje HIT y 3 espacios (6 bytes) y la zona del INPUT (4 bytes si no nos pasamos en la entrada), A más de las 25 marcas de final de línea típicas del ZX-81 cuando tiene menos de 4KB de RAM.

Colocando los barcos
Esta parte ocupa solo 5 líneas, y me siento especialmente orgulloso. Explico el motivo.

Cada jugador debe introducir 5 barcos que ocupan dos posiciones. En el caso del jugador, salvo que haya mala intención, la colocación debe ser correcta. Pero en el caso del ZX-81 hay que evitar que dos barcos puedan ocupar la misma posición, y con una simple línea y algo de ingenio lo he conseguido.

Vamos a repetir las siguientes líneas un total de cinco veces. Una por barco y usando el valor del bucle “F” como contador.

Para que el jugador coloque un barco se llama a la subrutina que hay en la línea 62. Nos pide introducir una posición con el formato “fila/columna” y a continuación se convierte el valor de la letra en un valor entre 0 y 9 que se guarda en “Y” (fila) , y el valor numérico entre 0 y 9 se guarda en “X” (columna). Con estos dos valores ponemos el gráfico del barco en la posición correspondiente del tablero. Bastante simple.

Para las posiciones de los barcos del ZX-81 la cosa se complica.

Primero hay que pensar donde se van a guardar. Imposible crear una matriz de dos dimensiones con tan poca memoria.
¿Solución? Uso el buffer de la impresora (33 bytes sin uso durante la ejecución del programa) para guardar la primera posición absoluta de cada barco. El tablero ocupa un total de 100 casillas que internamente van numeradas con un valor entre 0 y 99. Así la fila A va de la casilla 0 a la 9, B de la 10 a la 19, y así hasta el final. De esta forma, la casilla “B5” se guarda como 15 y la casilla “J9” como 99, por ejemplo.

Y para evitar que la posición de dos barcos coincida, he dividido el tablero en 5 zonas de dos líneas cada una, así el primer barco debe estar entre la casilla 0 y la 19, el segundo entre la 20 y la 39, etc. De esta forma no hay que hacer ninguna comprobación, aunque si se sabe el “truco” cuando hundes un barco en una fila no hace falta seguir buscando en esa zona.

De esta forma, con el POKE de la línea 26 y una simple fórmula coloco la posición absoluta de un barco en un byte del buffer de la impresora con la seguridad que ningún más se coloque encima. Eso si, puede darse el caso que dos barcos estén colocados en casillas adjuntas, aunque las probabilidades son bajas. Es lo que hay.

Tira el ZX-81
Para evitar que el ordenador no tire dos veces en la misma casilla y no tengo espacio para guardar las posiciones donde ya he tirado, voy a usar la memoria de pantalla para este efecto. Así, genero dos números aleatorios, posiciono el cursor en la posición de la pantalla correspondiente con el PRINT AT de la línea 34 y consulto en la memoria de pantalla si hay una “X”. En caso afirmativo vuelvo a generar dos nuevos números, hasta que la tirada es correcta.

A continuación pongo una “X” en esa posición y consulto el carácter que había en esa posición de la pantalla, y que está guardado en “F”. Si no he tocado un barco salto a la línea 50 para que tire el jugador.

Si he tocado una parte de un barco, se activa una sencilla rutina de “inteligencia artificial” que lo que hace es incrementar en 1 la posición horizontal de la tirada realizada (a la derecha), y en caso de salir del margen del tablero restar 2 para tirar a la izquierda. Salto a la línea 34 y vuelvo a comprobar que hay en esa posición.

Como las variables “X” e “Y” están compartidas por los dos jugadores, he tenido que hacer que el ordenador pueda realizar una nueva tirada en caso de tocar un barco del jugador para no perder la posición. Y en caso de no dar con la otra mitad del barco, entra en un proceso de “amnesia” hasta que un nuevo número aleatorio le haga dar con él.

Tira el jugador
En este caso vamos a volver a ir a la subrutina de la línea 62, la cual a partir de unas coordenadas nos devuelve una posición horizontal (X) y una vertical (Y).

A continuación se inicia un bucle que se repite 5 veces y que sirve para comprobar si el valor absoluto de las coordenadas indicadas coinciden con la posición de uno de los barcos del ZX-81 o con la posición contigua, ya que el barco ocupa dos posiciones. El valor absoluto se calcula multiplicando la coordenada vertical por diez y sumándole la horizontal.

Si hemos tocado un barco aparece el texto “HIT” , en una posición que hemos colocado al hacer el PRINT “X” de la tirada del ZX-81.

Al acabar la comprobación se imprimen 3 espacios. Si no se ha tocado ningún barco, borrará el mensaje “HIT” (si estaba) y sino se pondrán en la línea siguiente lo que no afecta en nada (pero ocupan 3 bytes).

Final de partida
Como en ningún momento se controla el número de impactos de ninguno de los contendientes, la partida puede entrar en un bucle sin fin cuando el ZX-81 ha llenado todas las casillas. Así que cuando uno de los contendientes haya localizado las 10 partes de los barcos, se deberá hacer un “BREAK” y un “RUN” para iniciar otra partida.

Y si ya has tenido bastante, siempre nos quedará “NEW”.


Para terminar
Me he quedado con las ganas de mostrar los dos tableros, controlar las posiciones de los barcos, las coordenadas y alguna otra cosilla, pero la verdad es que no había memoria para más.


Pues nada más. Con sus limitaciones el programa funciona más que bien y es hasta entretenido, así que…

Os invito a probarlo.

bship_2.gif
bship_2.gif (52.89 KiB) Visto 1795 veces

bship_3.gif
bship_3.gif (58.12 KiB) Visto 1795 veces

Avatar de Usuario
ron
Mensajes: 17360
Registrado: 28 Oct 2010 14:20
Ubicación: retrocrypta
Agradecido : 571 veces
Agradecimiento recibido: 589 veces

Re: BattleShips-1K para ZX-81

Mensajepor ron » 29 May 2014 22:33

Guapísimo. Gran trabajo dancresp.

Mola mucho ver como "rascas" memoria de donde no hay y tiras de la propia memoria de video. Como te he dicho, guapísimo. Y además que tiras de RND, lo tiene casi todo, ¿ he dicho ya que me gustaba ? xD

Tira el ZX-81
Para evitar que el ordenador no tire dos veces en la misma casilla y no tengo espacio para guardar las posiciones donde ya he tirado, voy a usar la memoria de pantalla para este efecto. Así, genero dos números aleatorios, posiciono el cursor en la posición de la pantalla correspondiente con el PRINT AT de la línea 34 y consulto en la memoria de pantalla si hay una “X”. En caso afirmativo vuelvo a generar dos nuevos números, hasta que la tirada es correcta.

A continuación pongo una “X” en esa posición y consulto el carácter que había en esa posición de la pantalla, y que está guardado en “F”. Si no he tocado un barco salto a la línea 50 para que tire el jugador.

Si he tocado una parte de un barco, se activa una sencilla rutina de “inteligencia artificial” que lo que hace es incrementar en 1 la posición horizontal de la tirada realizada (a la derecha), y en caso de salir del margen del tablero restar 2 para tirar a la izquierda. Salto a la línea 34 y vuelvo a comprobar que hay en esa posición.

Como las variables “X” e “Y” están compartidas por los dos jugadores, he tenido que hacer que el ordenador pueda realizar una nueva tirada en caso de tocar un barco del jugador para no perder la posición. Y en caso de no dar con la otra mitad del barco, entra en un proceso de “amnesia” hasta que un nuevo número aleatorio le haga dar con él.

Avatar de Usuario
ron
Mensajes: 17360
Registrado: 28 Oct 2010 14:20
Ubicación: retrocrypta
Agradecido : 571 veces
Agradecimiento recibido: 589 veces

Re: BattleShips-1K para ZX-81

Mensajepor ron » 29 May 2014 23:10

0001.png
0001.png (12.65 KiB) Visto 1777 veces


bship.rar
(550 Bytes) Descargado 97 veces


Dentro del rar está el bship.p

Avatar de Usuario
Chema
Mensajes: 1605
Registrado: 21 Jun 2012 20:13
Ubicación: Gijón
Agradecido : 510 veces
Agradecimiento recibido: 205 veces
Contactar:

Re: BattleShips-1K para ZX-81

Mensajepor Chema » 29 May 2014 23:17

Flipo con las cosas que llegas a hacer... Una pasada, dancresp. ¡¡Felicidades!!

Tolvatar
Mensajes: 433
Registrado: 30 Jun 2012 17:56
Agradecido : 1 vez
Agradecimiento recibido: 1 vez

Re: BattleShips-1K para ZX-81

Mensajepor Tolvatar » 30 May 2014 16:33

Y que me decis de las explicaciones?
Una pasada.

Dancresp. En que trabajas? Tus capacidades didacticas me asombran. Y los programas que haces tambien.

jltursan
Mensajes: 1933
Registrado: 20 Sep 2011 13:59
Agradecido : 57 veces
Agradecimiento recibido: 149 veces

Re: BattleShips-1K para ZX-81

Mensajepor jltursan » 30 May 2014 17:32

Chico, te tienes que pasar al ensamblador. En un ZX-81 de 1KB empiezo a pensar que podrías hacer auténticas barrabasadas ;-)

Avatar de Usuario
ron
Mensajes: 17360
Registrado: 28 Oct 2010 14:20
Ubicación: retrocrypta
Agradecido : 571 veces
Agradecimiento recibido: 589 veces

Re: BattleShips-1K para ZX-81

Mensajepor ron » 30 May 2014 19:46

Estaría pero que muy bien ver un día una dancrespada en el ZX81 hecha enteramente en assembler. Yo esperaré porque viendo que todo lo que dijo que iba a hacer lo ha hecho con creces ya me espero cualquier sorpresa de las buenas, al tiempo.

Dirá que no y que tal y que cual, ( es broma ) pero yo no tengo prisa y algún día seguro que lo vemos, al tiempo x2.

Avatar de Usuario
web8bits
Mensajes: 944
Registrado: 31 Oct 2010 10:34
Agradecido : 76 veces
Agradecimiento recibido: 46 veces

Re: BattleShips-1K para ZX-81

Mensajepor web8bits » 31 May 2014 12:47

IMPRESIONANTE

Una vez más me quito el sombrero ante dancresp, fantástico trabajo.

Un saludo

dancresp
Mensajes: 5017
Registrado: 13 Nov 2010 02:08
Agradecido : 17 veces
Agradecimiento recibido: 89 veces

Re: BattleShips-1K para ZX-81

Mensajepor dancresp » 31 May 2014 20:52

A ver, que ayer me fui de casa y no he vuelto hasta hace un rato.

1) ron, gracias por el ".p" del juego. Triste, pero no se como generarlos...

2) Trabajo como responsable de informática en una empresa, y me toca programar. Eso ayuda.

Respecto al tema del assembler, es algo que tengo en cuenta porque es una asignatura pendiente.

En su día alguna rutinilla hice, pero nada serio. Me lancé con el Spectrum y el GENS-3.

Así que tengo intención de acabar haciendo cosillas en ensamblador, pero para la máquina con 1K ya que no estoy por liarme con grandes proyectos, y porque lo que haga lo quiero ensamblar "a mano", y algo muy grande es de chinos.

De todas formas, todos estos proyectos en BASIC son un "rompecocos" brutal, y aquí está la gracia. -banghead

El haber conseguido programar en 1K un "Sudoku" con 20 líneas de BASIC (¿récord Guinness?), un "Light Out" con 10 niveles predefinidos, el del laberinto con un mapa de 9x9 posiciones, el buscaminas y ahora el de los barquitos, te da una sensación al acabarlos de "lo conseguí" muy gratificante, y difícil de explicar.

Y no os cuento el ensamblador y, muy especialmente, cuando hice mi primer bucle "DO LOOP" con el "FORTH-1K".

Mi primer sistema fue éste y aunque tengo la ampliación de 16KB, el programarlo con 1K le da un "algo" único, y para cosas más "profesionales" tengo mis queridos MSX, que también tienen "su que". Solo he de ver el "Nuclear Invaders", el "Star Wars" o el "Jawbreaker" para asumir de lo que son capaces...

Fin del ladrillo, pero habrá más... -drinks

Avatar de Usuario
jojo073
Mensajes: 3147
Registrado: 14 Nov 2010 20:41
Agradecido : 41 veces
Agradecimiento recibido: 97 veces

Re: BattleShips-1K para ZX-81

Mensajepor jojo073 » 01 Jun 2014 23:26

Buen trabajo, tengo que mirarle el teclado a mi zx81... a ver si es capaz de ejecutar algo...

Avatar de Usuario
ron
Mensajes: 17360
Registrado: 28 Oct 2010 14:20
Ubicación: retrocrypta
Agradecido : 571 veces
Agradecimiento recibido: 589 veces

Re: BattleShips-1K para ZX-81

Mensajepor ron » 02 Jun 2014 19:58

EL mismo eightyone genera los .p, abres la ventana del tape, una vez tengas en programa haces un SAVE "PROG" y te mostrará el programa. Lo pinchas y le das al icono del diskette, el cual te permitirá salvarlo en el formato que tu elijas.

81progp.png
81progp.png (61.91 KiB) Visto 36 veces

Imagen

Si no te habías dado cuenta, es un mal menor !!! xD

dancresp
Mensajes: 5017
Registrado: 13 Nov 2010 02:08
Agradecido : 17 veces
Agradecimiento recibido: 89 veces

Re: BattleShips-1K para ZX-81

Mensajepor dancresp » 02 Jun 2014 21:59

ron escribió:EL mismo eightyone genera los .p, abres la ventana del tape, una vez tengas en programa haces un SAVE "PROG" y te mostrará el programa. Lo pinchas y le das al icono del diskette, el cual te permitirá salvarlo en el formato que tu elijas.

Estaba convencido que los debía poder hacer de alguna manera, pero es que para según que cosillas soy bastante limitadete... -banghead

Pues nada, que lo acabo de probar y me lo ha hecho a la primera.

Por fin voy a poder tener mis juegos en formato ".p" !!! -thumbup

Gracias ron. -drinks

Avatar de Usuario
ron
Mensajes: 17360
Registrado: 28 Oct 2010 14:20
Ubicación: retrocrypta
Agradecido : 571 veces
Agradecimiento recibido: 589 veces

Re: BattleShips-1K para ZX-81

Mensajepor ron » 02 Jun 2014 22:06

dancresp escribió:
Pues nada, que lo acabo de probar y me lo ha hecho a la primera.

Por fin voy a poder tener mis juegos en formato ".p" !!! -thumbup

Gracias ron. -drinks


intuía que no diste con ello porque muchas veces no miramos las opciones de los emus, nos conformamos con que carguen, saquen un snap y no se fostien xD

que va, para nada, las Gracias a ti que eres un crack !!!


Volver a “Lenguajes de Programación y herramientas Dev”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado