Diferencias
Muestra las diferencias entre dos versiones de la página.
Próxima revisión | Revisión previa | ||
cursos:basic:zxmines_ejemplo_comentado [20-03-2009 19:16] – creado sromero | cursos:basic:zxmines_ejemplo_comentado [24-03-2009 09:29] (actual) – sromero | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
====== ZXMines: Juego Completo en BASIC comentado ====== | ====== ZXMines: Juego Completo en BASIC comentado ====== | ||
- | ZXMines es un juego en BASIC que se presentó al concurso de programación de Juegos en Basic 2003 de ByteManiacos. ZXMines implementa en BASIC un sencillo juego de Buscaminas en el cual debemos destapar todo el tablero sin levantar las casillas en que se alojan las minas (destapar una mina finaliza el juego). Para poder destapar totalmente el tablero sin levantar casillas con minas disponemos de una información providencial: | + | //ZXMines es un juego en BASIC que se presentó al concurso de programación de Juegos en Basic 2003 de ByteManiacos. ZXMines implementa en BASIC un sencillo juego de Buscaminas en el cual debemos destapar todo el tablero sin levantar las casillas en que se alojan las minas (destapar una mina finaliza el juego). Para poder destapar totalmente el tablero sin levantar casillas con minas disponemos de una información providencial: |
- | ZXMines: el clásico juego Buscaminas, en BASIC | + | \\ |
- | ZXMines: el clásico juego Buscaminas, en BASIC | + | \\ |
Así, si destapamos una casilla y contiene el número 1, sabemos que alguna de las 8 casillas de alrededor de la misma contiene una mina. Utilizando la información numérica que nos proporcionan las diferentes casillas que vamos destapando podemos ser capaces de averiguar qué casillas contienen minas y evitarlas. El juego acaba cuando destapamos una mina (y perdemos) o bien cuando destapamos todas las casillas del tablero quedando sólo por destapar las casillas con minas (ganando el juego). Por último, una cosa a destacar es que si destapamos una casilla sin minas alrededor, se abre todo un área de juego a la vista, para acelerar el ritmo de juego. | Así, si destapamos una casilla y contiene el número 1, sabemos que alguna de las 8 casillas de alrededor de la misma contiene una mina. Utilizando la información numérica que nos proporcionan las diferentes casillas que vamos destapando podemos ser capaces de averiguar qué casillas contienen minas y evitarlas. El juego acaba cuando destapamos una mina (y perdemos) o bien cuando destapamos todas las casillas del tablero quedando sólo por destapar las casillas con minas (ganando el juego). Por último, una cosa a destacar es que si destapamos una casilla sin minas alrededor, se abre todo un área de juego a la vista, para acelerar el ritmo de juego. | ||
+ | |||
+ | \\ | ||
+ | {{ : | ||
+ | ;#; | ||
+ | //ZXMines: el clásico juego Buscaminas, en BASIC// | ||
+ | ;#; | ||
+ | \\ | ||
El objetivo del presente artículo es mostrar y explicar el código BASIC utilizado para programar ZXMINES, mostrando así algunos trucos que en BASIC proporcionan una mayor velocidad de ejecución. | El objetivo del presente artículo es mostrar y explicar el código BASIC utilizado para programar ZXMINES, mostrando así algunos trucos que en BASIC proporcionan una mayor velocidad de ejecución. | ||
- | PSEUDOCÓDIGO DEL JUEGO | + | \\ |
+ | |||
+ | ===== Pseudocódigo del juego ===== | ||
Lo primero que hacemos es definir el juego mediante lenguaje humano, para posteriormente adaptar ese lenguaje humano a código en BASIC. Es muy importante hacer esto antes de escribir una sóla línea en BASIC. El programa se adapta al diseño y al pseudocódigo, | Lo primero que hacemos es definir el juego mediante lenguaje humano, para posteriormente adaptar ese lenguaje humano a código en BASIC. Es muy importante hacer esto antes de escribir una sóla línea en BASIC. El programa se adapta al diseño y al pseudocódigo, | ||
Línea 15: | Línea 24: | ||
Veamos el pseudocódigo para nuestro juego buscaminas: | Veamos el pseudocódigo para nuestro juego buscaminas: | ||
+ | < | ||
Inicio ZXMINES | Inicio ZXMINES | ||
- Inicio del programa (declaracion de variables, etc.). | - Inicio del programa (declaracion de variables, etc.). | ||
Línea 85: | Línea 95: | ||
Fin ZXMINES | Fin ZXMINES | ||
+ | </ | ||
El pseudocódigo permite implementar el juego en cualquier lenguaje de una manera rápida: por ejemplo, el mismo pseudocódigo/ | El pseudocódigo permite implementar el juego en cualquier lenguaje de una manera rápida: por ejemplo, el mismo pseudocódigo/ | ||
- | EL LISTADO DEL JUEGO | + | \\ |
+ | ===== El listado del juego ===== | ||
En los siguientes apartados veremos los diferentes bloques funcionales del juego comentados. El lector podrá identificar fácilmente a qué función del pseudocódigo se corresponden. Como puede verse, la utilización de pseudocódigo permite una programación más limpia, ya que la implementación sólo tiene que ceñirse a lo que hemos diseñado, reduciendo los errores posteriores (se trata tan sólo de implementar la visión general que nos da el pseudocódigo, | En los siguientes apartados veremos los diferentes bloques funcionales del juego comentados. El lector podrá identificar fácilmente a qué función del pseudocódigo se corresponden. Como puede verse, la utilización de pseudocódigo permite una programación más limpia, ya que la implementación sólo tiene que ceñirse a lo que hemos diseñado, reduciendo los errores posteriores (se trata tan sólo de implementar la visión general que nos da el pseudocódigo, | ||
Línea 96: | Línea 109: | ||
Para empezar, veamos la relación entre el pseudocódigo y las diferentes líneas BASIC del programa (podéis utilizar el Listado 1 para identificar los diferentes bloques funcionales): | Para empezar, veamos la relación entre el pseudocódigo y las diferentes líneas BASIC del programa (podéis utilizar el Listado 1 para identificar los diferentes bloques funcionales): | ||
+ | < | ||
Inicio ZXMINES | Inicio ZXMINES | ||
- Inicio del programa (líneas 48-90) | - Inicio del programa (líneas 48-90) | ||
Línea 108: | Línea 122: | ||
FUNCIÓN Preparar_Pantalla: | FUNCIÓN Preparar_Pantalla: | ||
Fin ZXMINES | Fin ZXMINES | ||
+ | </ | ||
Como puede verse, cada función o bloque lógico del pseudocódigo se corresponde con un bloque de líneas BASIC, que será que lo veremos más detallado a continuación. | Como puede verse, cada función o bloque lógico del pseudocódigo se corresponde con un bloque de líneas BASIC, que será que lo veremos más detallado a continuación. | ||
- | INICIO DEL PROGRAMA Y PREPARACIÓN DE PANTALLA | + | \\ |
+ | ===== Inicio del programa y preparación de pantalla ===== | ||
Aparte de los comentarios del programa (líneas 9100 a 9147), el programa (lógicamente hablando) empieza con el siguiente código: | Aparte de los comentarios del programa (líneas 9100 a 9147), el programa (lógicamente hablando) empieza con el siguiente código: | ||
+ | <code basic> | ||
48 INPUT " | 48 INPUT " | ||
49 IF L$<>" | 49 IF L$<>" | ||
Línea 129: | Línea 146: | ||
85 LET DIFICULTAD=0 | 85 LET DIFICULTAD=0 | ||
90 GO SUB 8000 : REM DEFINIMOS LOS GRAFICOS | 90 GO SUB 8000 : REM DEFINIMOS LOS GRAFICOS | ||
+ | </ | ||
Lo primero que hacemos es pues preguntar al usuario el idioma para el juego, y después declarar las variables que utilizaremos en el programa. La variable L$ almacenará el idioma del juego, pudiendo contener la cadena " | Lo primero que hacemos es pues preguntar al usuario el idioma para el juego, y después declarar las variables que utilizaremos en el programa. La variable L$ almacenará el idioma del juego, pudiendo contener la cadena " | ||
Línea 138: | Línea 156: | ||
Así pues, un tablero tapado tendría la siguiente forma: | Así pues, un tablero tapado tendría la siguiente forma: | ||
+ | < | ||
V = | V = | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
Línea 151: | Línea 170: | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
+ | </ | ||
Un tablero con la casilla central destapada tendría el siguiente aspecto: | Un tablero con la casilla central destapada tendría el siguiente aspecto: | ||
+ | < | ||
V = | V = | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
Línea 167: | Línea 188: | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
+ | </ | ||
El array T(12,12) indica lo que contiene cada casilla propiamente dicha. Si contiene un cero, la casilla está vacía. Si contiene un nueve, la casilla tiene una mina. Finalmente, cualquier valor entre 1 y 8 significa el número de minas que hay alrededor de la casilla actual. | El array T(12,12) indica lo que contiene cada casilla propiamente dicha. Si contiene un cero, la casilla está vacía. Si contiene un nueve, la casilla tiene una mina. Finalmente, cualquier valor entre 1 y 8 significa el número de minas que hay alrededor de la casilla actual. | ||
Línea 172: | Línea 194: | ||
Así, inicialmente tendremos ambos arrays (V y T) llenos de ceros porque no hay minas dentro, y porque todas las casillas están tapadas. Si queremos introducir una mina en el tablero en la posición (3,5), podemos hacerlo con: | Así, inicialmente tendremos ambos arrays (V y T) llenos de ceros porque no hay minas dentro, y porque todas las casillas están tapadas. Si queremos introducir una mina en el tablero en la posición (3,5), podemos hacerlo con: | ||
+ | <code basic> | ||
T(3,5) = 9; | T(3,5) = 9; | ||
+ | </ | ||
Al igual que en el caso anterior, un array sin minas estará lleno de ceros, pero un array con 4 minas y ya correctamente " | Al igual que en el caso anterior, un array sin minas estará lleno de ceros, pero un array con 4 minas y ya correctamente " | ||
+ | < | ||
T = | T = | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
Línea 189: | Línea 214: | ||
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0 | 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0 | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
+ | </ | ||
Como puede verse, las minas se sitúan con números 9, y las casillas de alrededor de las minas contienen valores numéricos que indican la cantidad de minas circundantes. | Como puede verse, las minas se sitúan con números 9, y las casillas de alrededor de las minas contienen valores numéricos que indican la cantidad de minas circundantes. | ||
Línea 194: | Línea 220: | ||
Finalmente se produce un salto a la rutina de la dirección 8000, que prepara los UDG o gráficos definidos por el usuario: | Finalmente se produce un salto a la rutina de la dirección 8000, que prepara los UDG o gráficos definidos por el usuario: | ||
+ | <code basic> | ||
8000 REM *** Preparacion de GDUs *** | 8000 REM *** Preparacion de GDUs *** | ||
8005 RESTORE 9012 | 8005 RESTORE 9012 | ||
Línea 199: | Línea 226: | ||
8015 FOR I=0 TO 7: READ FILA : POKE USR " | 8015 FOR I=0 TO 7: READ FILA : POKE USR " | ||
8020 FOR I=0 TO 7: READ FILA : POKE USR " | 8020 FOR I=0 TO 7: READ FILA : POKE USR " | ||
+ | </ | ||
Como puede verse, se define " | Como puede verse, se define " | ||
Los 3 dibujos han sido creados con SevenuP de la misma forma. Por ejemplo, para crear la mina, abrimos SevenuP y creamos un nuevo dibujo de 8x8. Dibujamos la mina (en la siguiente figura la veremos a medio dibujar) y vamos a File , y luego a Output Options y seleccionamos "No attributes" | Los 3 dibujos han sido creados con SevenuP de la misma forma. Por ejemplo, para crear la mina, abrimos SevenuP y creamos un nuevo dibujo de 8x8. Dibujamos la mina (en la siguiente figura la veremos a medio dibujar) y vamos a File , y luego a Output Options y seleccionamos "No attributes" | ||
- | Creando nuestros gráficos en SevenuP | + | |
- | Creando nuestros gráficos en SevenuP | + | \\ |
+ | {{ : | ||
+ | ;#; | ||
+ | //Creando nuestros gráficos en SevenuP// | ||
+ | ;#; | ||
+ | \\ | ||
A continuación exportamos los datos, desde el menu File, opción Export Data. Escribimos un nombre de fichero (por ejemplo, mina.c), y en el desplegable seleccionamos "C source" | A continuación exportamos los datos, desde el menu File, opción Export Data. Escribimos un nombre de fichero (por ejemplo, mina.c), y en el desplegable seleccionamos "C source" | ||
+ | <code c> | ||
unsigned char Sprite[8] = { | unsigned char Sprite[8] = { | ||
16, 186, 116, 254, 124, 186, 16, 0 }; | 16, 186, 116, 254, 124, 186, 16, 0 }; | ||
+ | </ | ||
Estos son los valores que podremos en nuestros DATA en BASIC: | Estos son los valores que podremos en nuestros DATA en BASIC: | ||
+ | <code basic> | ||
9017 DATA 16, 186, 116, 254, 124, 186, 16, 0 | 9017 DATA 16, 186, 116, 254, 124, 186, 16, 0 | ||
+ | </ | ||
Tras el inicio del programa (líneas 48 a 90) viene la preparación de la pantalla (líneas 2300 a 2450) donde simplemente se imprimen en pantalla los mensajes que veremos en el menú principal. | Tras el inicio del programa (líneas 48 a 90) viene la preparación de la pantalla (líneas 2300 a 2450) donde simplemente se imprimen en pantalla los mensajes que veremos en el menú principal. | ||
- | Aspecto de la pantalla de presentación | ||
- | Aspecto de la pantalla de presentación | ||
- | GENERACIÓN DEL TABLERO | + | |
+ | \\ | ||
+ | {{ : | ||
+ | ;#; | ||
+ | //Aspecto de la pantalla de presentación// | ||
+ | ;#; | ||
+ | \\ | ||
+ | |||
+ | |||
+ | \\ | ||
+ | ===== Generación del tablero ===== | ||
La rutina de las líneas 2000 a 2200 es llamada desde la rutina de preparación de la pantalla para rellenar el tablero T con minas aleatorias (números 9), y al mismo tiempo calcular los valores numéricos de cada casilla indicando el número de minas alrededor. | La rutina de las líneas 2000 a 2200 es llamada desde la rutina de preparación de la pantalla para rellenar el tablero T con minas aleatorias (números 9), y al mismo tiempo calcular los valores numéricos de cada casilla indicando el número de minas alrededor. | ||
Línea 230: | Línea 276: | ||
En pseudocódigo: | En pseudocódigo: | ||
+ | < | ||
Desde I = 0 a NUMERO_DE_MINAS | Desde I = 0 a NUMERO_DE_MINAS | ||
Poner minas aleatoriamente con T(RANDOMX, | Poner minas aleatoriamente con T(RANDOMX, | ||
Línea 240: | Línea 287: | ||
Fin Desde | Fin Desde | ||
Fin Desde | Fin Desde | ||
+ | </ | ||
El código resultante es: | El código resultante es: | ||
+ | <code basic> | ||
2000 REM *** GENERACION DE TABLERO *** | 2000 REM *** GENERACION DE TABLERO *** | ||
2001 IF DIFICULTAD=0 THEN RETURN | 2001 IF DIFICULTAD=0 THEN RETURN | ||
Línea 269: | Línea 318: | ||
2101 IF L$=" | 2101 IF L$=" | ||
2102 IF L$=" | 2102 IF L$=" | ||
+ | </ | ||
En esa primera parte colocamos las minas dentro del tablero, y a continuación calculamos los valores numéricos de cada celdilla del tablero: | En esa primera parte colocamos las minas dentro del tablero, y a continuación calculamos los valores numéricos de cada celdilla del tablero: | ||
+ | <code basic> | ||
2109 LET PORCEN=0 : LET CON=0 | 2109 LET PORCEN=0 : LET CON=0 | ||
2110 FOR N=1 TO MINAS | 2110 FOR N=1 TO MINAS | ||
Línea 291: | Línea 342: | ||
2181 PRINT AT 20,1 ; INK COL; PAPER PAP; " | 2181 PRINT AT 20,1 ; INK COL; PAPER PAP; " | ||
2200 RETURN | 2200 RETURN | ||
+ | </ | ||
Nótese un pequeño truco que se ha utilizado para acelerar la generación y cálculos: en lugar de trabajar sobre arrays temporales, trabajamos sobre zonas de memoria (59000 y 59300) tratándolas como vectores de trabajo temporales. Escribimos en nuestros " | Nótese un pequeño truco que se ha utilizado para acelerar la generación y cálculos: en lugar de trabajar sobre arrays temporales, trabajamos sobre zonas de memoria (59000 y 59300) tratándolas como vectores de trabajo temporales. Escribimos en nuestros " | ||
Línea 296: | Línea 348: | ||
Así, la primera parte de la función coloca en 59000 y 59300 valores X e Y para las minas, y finalmente incorporamos las minas al tablero mediante: | Así, la primera parte de la función coloca en 59000 y 59300 valores X e Y para las minas, y finalmente incorporamos las minas al tablero mediante: | ||
+ | <code basic> | ||
2170 FOR N=1 TO MINAS : LET T( PEEK (59000+N), PEEK (59300+N)) = 9 : | 2170 FOR N=1 TO MINAS : LET T( PEEK (59000+N), PEEK (59300+N)) = 9 : | ||
NEXT N | NEXT N | ||
+ | </ | ||
El resultado de la ejecución de la rutina de arriba es un tablero tapado (V(x,y) = 0 para todo x e y), y que tiene una serie de minas (valores numéricos 9) en T(xminas, | El resultado de la ejecución de la rutina de arriba es un tablero tapado (V(x,y) = 0 para todo x e y), y que tiene una serie de minas (valores numéricos 9) en T(xminas, | ||
+ | < | ||
T = | T = | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
Línea 314: | Línea 369: | ||
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0 | 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0 | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
+ | </ | ||
Una vez tenemos definido el tablero de juego podemos continuar con el bucle principal del programa. | Una vez tenemos definido el tablero de juego podemos continuar con el bucle principal del programa. | ||
- | BUCLE PRINCIPAL DEL JUEGO | + | \\ |
+ | |||
+ | ===== Bucle principal del juego ===== | ||
El bucle principal del juego se desarrolla entre las líneas 200 y 990). | El bucle principal del juego se desarrolla entre las líneas 200 y 990). | ||
Línea 323: | Línea 382: | ||
Lo primero que hacemos es dibujar el tablero de juego con 2 bucles FOR para el ancho y para el alto: | Lo primero que hacemos es dibujar el tablero de juego con 2 bucles FOR para el ancho y para el alto: | ||
- | 00 REM *** BUCLE PRINCIPAL *** | + | <code basic> |
+ | 100 REM *** BUCLE PRINCIPAL *** | ||
300 LET P$= CHR$(16) + CHR$(0) + CHR$(17) + CHR$(7) : | 300 LET P$= CHR$(16) + CHR$(0) + CHR$(17) + CHR$(7) : | ||
FOR X=1 TO ANCHO : LET P$=P$+" | FOR X=1 TO ANCHO : LET P$=P$+" | ||
Línea 329: | Línea 389: | ||
315 PRINT AT IY+Y,IX+1 ; P$; | 315 PRINT AT IY+Y,IX+1 ; P$; | ||
370 NEXT Y | 370 NEXT Y | ||
+ | </ | ||
Se ha utilizado una cadena " | Se ha utilizado una cadena " | ||
Línea 334: | Línea 395: | ||
A continuación viene el bucle principal en sí mismo. Lo que se hace en este bucle principal es utilizar unas variables CX, CY que indican la posición dentro del array de la casilla " | A continuación viene el bucle principal en sí mismo. Lo que se hace en este bucle principal es utilizar unas variables CX, CY que indican la posición dentro del array de la casilla " | ||
+ | <code basic> | ||
400 REM Bucle principal de partida | 400 REM Bucle principal de partida | ||
405 IF DIFICULTAD=0 THEN GO TO 415 | 405 IF DIFICULTAD=0 THEN GO TO 415 | ||
Línea 360: | Línea 422: | ||
IF CY<>0 THEN GO SUB 1000 | IF CY<>0 THEN GO SUB 1000 | ||
990 GO TO 400 | 990 GO TO 400 | ||
+ | </ | ||
La actualización de la posición actual del cursor se realiza en la línea 410: | La actualización de la posición actual del cursor se realiza en la línea 410: | ||
+ | <code basic> | ||
410 OVER 1: PRINT AT IY+CY, IX+CX ; FLASH 1; INK 0 ; PAPER 7;" "; : | 410 OVER 1: PRINT AT IY+CY, IX+CX ; FLASH 1; INK 0 ; PAPER 7;" "; : | ||
OVER 0 : GO SUB 991 | OVER 0 : GO SUB 991 | ||
+ | </ | ||
Al final de esa línea se salta a la rutina 991, que simplemente se encarga con varios PRINT de actualizar los valores numéricos de números de minas y casillas restantes en el juego: | Al final de esa línea se salta a la rutina 991, que simplemente se encarga con varios PRINT de actualizar los valores numéricos de números de minas y casillas restantes en el juego: | ||
+ | <code basic> | ||
991 REM *** Actualizar contadores minas *** | 991 REM *** Actualizar contadores minas *** | ||
992 IF L$=" | 992 IF L$=" | ||
Línea 377: | Línea 443: | ||
997 PRINT AT 15, 18; " | 997 PRINT AT 15, 18; " | ||
998 RETURN | 998 RETURN | ||
+ | </ | ||
Como puede verse, en el bucle principal también se controla la pulsación de las teclas 1 a 4 para cambiar la dificultad y acabar el juego. Nótese también la siguiente línea: | Como puede verse, en el bucle principal también se controla la pulsación de las teclas 1 a 4 para cambiar la dificultad y acabar el juego. Nótese también la siguiente línea: | ||
+ | <code basic> | ||
407 IF MINAS=QUEDAN THEN GO TO 1600 | 407 IF MINAS=QUEDAN THEN GO TO 1600 | ||
+ | </ | ||
La línea 407 es el control de fin de juego para saber si el jugador ha ganado: si quedan tantas casillas por destapar como minas hemos puesto en el tablero, quiere decir que hemos destapado todas las casillas del tablero excepto las minas, con lo cual el juego se ha acabado y hemos ganado. En ese caso se salta a la línea 1600 que es la rutina de Victoria_Fin_Juego. Las rutinas de Victoria_Fin_Juego y Muerte_Fin_Juego son bastante sencillas (líneas 1300-1330 y 1600-1630): simplemente muestran un mensaje en pantalla, muestran el tablero desplegado y completo (si pulsas una mina y pierdes, tienes derecho a ver el contenido del tablero y la posición de las minas), esperan la pulsación de una tecla, reinicializan las variables del juego y saltan a la línea 400 (Inicio del bucle principal) para comenzar una nueva partida. La muestra y borrado del tablero se realiza mediante las siguientes rutinas: | La línea 407 es el control de fin de juego para saber si el jugador ha ganado: si quedan tantas casillas por destapar como minas hemos puesto en el tablero, quiere decir que hemos destapado todas las casillas del tablero excepto las minas, con lo cual el juego se ha acabado y hemos ganado. En ese caso se salta a la línea 1600 que es la rutina de Victoria_Fin_Juego. Las rutinas de Victoria_Fin_Juego y Muerte_Fin_Juego son bastante sencillas (líneas 1300-1330 y 1600-1630): simplemente muestran un mensaje en pantalla, muestran el tablero desplegado y completo (si pulsas una mina y pierdes, tienes derecho a ver el contenido del tablero y la posición de las minas), esperan la pulsación de una tecla, reinicializan las variables del juego y saltan a la línea 400 (Inicio del bucle principal) para comenzar una nueva partida. La muestra y borrado del tablero se realiza mediante las siguientes rutinas: | ||
+ | <code basic> | ||
1400 REM *** Mostrar tablero *** | 1400 REM *** Mostrar tablero *** | ||
1420 FOR Y=1 TO ALTO | 1420 FOR Y=1 TO ALTO | ||
Línea 397: | Línea 467: | ||
1463 NEXT N | 1463 NEXT N | ||
1470 RETURN | 1470 RETURN | ||
+ | </ | ||
El borrado se basa simplemente en pintar espacios sobre el tablero, mientras que la visualización del tablero muestra todos los valores de T(X,Y) (independientemente del valor de V(X,Y), ya que pretendemos mostrar el tablero destapado completo). Puede verse el uso de C$(), que es un array donde hemos almacenado los caracteres para los 10 valores posibles del tablero (0 a 9, desde una casilla sin mina hasta una mina), de tal forma que 0 se corresponde con una casilla vacía, los números del 1 al 8 con los caracteres del 1 al 9, y el 9 con una mina. | El borrado se basa simplemente en pintar espacios sobre el tablero, mientras que la visualización del tablero muestra todos los valores de T(X,Y) (independientemente del valor de V(X,Y), ya que pretendemos mostrar el tablero destapado completo). Puede verse el uso de C$(), que es un array donde hemos almacenado los caracteres para los 10 valores posibles del tablero (0 a 9, desde una casilla sin mina hasta una mina), de tal forma que 0 se corresponde con una casilla vacía, los números del 1 al 8 con los caracteres del 1 al 9, y el 9 con una mina. | ||
+ | <code basic> | ||
101 DIM C$(10) : FOR N=1 TO 10: READ C$(N) : NEXT N | 101 DIM C$(10) : FOR N=1 TO 10: READ C$(N) : NEXT N | ||
102 DIM H(10) : FOR N=1 TO 10: READ H(N) : NEXT N | 102 DIM H(10) : FOR N=1 TO 10: READ H(N) : NEXT N | ||
103 DATA " | 103 DATA " | ||
104 DATA 0, 1, 3, 2, 2, 2, 2, 2, 2, 0 | 104 DATA 0, 1, 3, 2, 2, 2, 2, 2, 2, 0 | ||
+ | </ | ||
La notación {M} significa "el UDG de M mayúscula", | La notación {M} significa "el UDG de M mayúscula", | ||
Línea 409: | Línea 482: | ||
Por último, cuando movemos el " | Por último, cuando movemos el " | ||
+ | <code basic> | ||
1500 REM *** Restaurar grafico bajo el cursor *** | 1500 REM *** Restaurar grafico bajo el cursor *** | ||
1510 IF V(CX,CY)=1 THEN PRINT AT CY+IY,CX+IX ; FLASH 0; PAPER 7; | 1510 IF V(CX,CY)=1 THEN PRINT AT CY+IY,CX+IX ; FLASH 0; PAPER 7; | ||
Línea 414: | Línea 488: | ||
1520 PRINT AT CY+IY, | 1520 PRINT AT CY+IY, | ||
1530 RETURN | 1530 RETURN | ||
+ | </ | ||
De nuevo podemos ver cómo se hace uso de CX+IX y CY+IY para saber dónde " | De nuevo podemos ver cómo se hace uso de CX+IX y CY+IY para saber dónde " | ||
Línea 419: | Línea 494: | ||
Gracias a H(), por ejemplo, podemos hacer: | Gracias a H(), por ejemplo, podemos hacer: | ||
+ | <code basic> | ||
102 DIM H(10) : FOR N=1 TO 10: READ H(N) : NEXT N | 102 DIM H(10) : FOR N=1 TO 10: READ H(N) : NEXT N | ||
104 DATA 0, 1, 3, 2, 2, 2, 2, 2, 2, 0 | 104 DATA 0, 1, 3, 2, 2, 2, 2, 2, 2, 0 | ||
(...) | (...) | ||
PRINT INK H( valor ) ; " | PRINT INK H( valor ) ; " | ||
+ | </ | ||
en lugar de: | en lugar de: | ||
+ | <code basic> | ||
IF valor=" | IF valor=" | ||
IF valor=" | IF valor=" | ||
Línea 431: | Línea 509: | ||
(...) | (...) | ||
IF valor=" | IF valor=" | ||
+ | </ | ||
Lo cual es mucho más rápido y más óptimo y legible. | Lo cual es mucho más rápido y más óptimo y legible. | ||
- | DESTAPADO DE MINAS | + | \\ |
+ | ===== Destapado de minas ===== | ||
Cuando en el bucle principal pulsamos espacio, se salta a una rutina que destapa la casilla actual: | Cuando en el bucle principal pulsamos espacio, se salta a una rutina que destapa la casilla actual: | ||
+ | <code basic> | ||
470 IF K$=" " OR K$=" | 470 IF K$=" " OR K$=" | ||
+ | </ | ||
Dicha rutina DestaparMina se desarrolla desde las líneas 1000 a 1099 del programa: Si la casilla ya está destapada, no hay nada que destapar. En caso contrario, la marcamos como ya abierta, y reducimos el número de casillas, y en una tercera línea imprimimos en pantalla el carácter al que corresponde la casilla que acabamos destapar: | Dicha rutina DestaparMina se desarrolla desde las líneas 1000 a 1099 del programa: Si la casilla ya está destapada, no hay nada que destapar. En caso contrario, la marcamos como ya abierta, y reducimos el número de casillas, y en una tercera línea imprimimos en pantalla el carácter al que corresponde la casilla que acabamos destapar: | ||
+ | <code basic> | ||
1000 REM *** Destapar mina *** | 1000 REM *** Destapar mina *** | ||
1010 IF V(CX,CY)=1 THEN RETURN | 1010 IF V(CX,CY)=1 THEN RETURN | ||
Línea 447: | Línea 530: | ||
1030 PRINT AT CY+IY,CX+IX ; PAPER 7; INK H(T(CX, | 1030 PRINT AT CY+IY,CX+IX ; PAPER 7; INK H(T(CX, | ||
| | ||
+ | </ | ||
Si es una mina lo que hemos destapado, hemos perdido. Si, por contra, es una casilla en blanco, tenemos que destapar todas las casillas en blanco alrededor de la casilla actual, algo que se hace en la porción de código a partir de la línea 1060. Para el resto de los casos (números 1 al 8) basta con haber destapado y mostrado la casilla, y podemos volver (saltando a 1098): | Si es una mina lo que hemos destapado, hemos perdido. Si, por contra, es una casilla en blanco, tenemos que destapar todas las casillas en blanco alrededor de la casilla actual, algo que se hace en la porción de código a partir de la línea 1060. Para el resto de los casos (números 1 al 8) basta con haber destapado y mostrado la casilla, y podemos volver (saltando a 1098): | ||
+ | <code basic> | ||
1040 IF T(CX,CY)=9 THEN GO TO 1300 | 1040 IF T(CX,CY)=9 THEN GO TO 1300 | ||
1050 IF T(CX,CY)=0 THEN GO TO 1060 | 1050 IF T(CX,CY)=0 THEN GO TO 1060 | ||
1055 GO TO 1098 | 1055 GO TO 1098 | ||
+ | </ | ||
A partir de aquí empieza el destapado de recuadros en blanco: lo primero es visualizar un mensaje de información de que se va a saltar a un cálculo que en BASIC es algo lento y costoso, para después llamar a la rutina Blanquear_Cuadros_Alrededor (llamada en línea 1075). Tras volver de la rutina se actualizan los contadores de minas, casillas y puntos y se vuelve al bucle principal. | A partir de aquí empieza el destapado de recuadros en blanco: lo primero es visualizar un mensaje de información de que se va a saltar a un cálculo que en BASIC es algo lento y costoso, para después llamar a la rutina Blanquear_Cuadros_Alrededor (llamada en línea 1075). Tras volver de la rutina se actualizan los contadores de minas, casillas y puntos y se vuelve al bucle principal. | ||
+ | <code basic> | ||
1060 REM Destapar todos los cuadros de alrededor que sean blancos | 1060 REM Destapar todos los cuadros de alrededor que sean blancos | ||
1066 LET PP=1 : REM Puntero a la pila | 1066 LET PP=1 : REM Puntero a la pila | ||
Línea 470: | Línea 557: | ||
1098 LET PUNTOS=PUNTOS+1 | 1098 LET PUNTOS=PUNTOS+1 | ||
1099 RETURN | 1099 RETURN | ||
+ | </ | ||
La rutina Blanquear_Cuadros_Alrededor se encarga de destapar todos los recuadros en blanco si el recuadro que acabamos de destapar está en blanco. Se usa para evitar que en zonas grandes de recuadros sin minas ni números tengamos que destapar uno a uno todos los recuadros que no contienen nada. Si no se llamara a esta función, al pulsar en un recuadro de un área vacía, simplemente se destaparía ese recuadro y ningún otro más. Lo que hace esta función es destapar todo el área vacía, para agilizar el juego. | La rutina Blanquear_Cuadros_Alrededor se encarga de destapar todos los recuadros en blanco si el recuadro que acabamos de destapar está en blanco. Se usa para evitar que en zonas grandes de recuadros sin minas ni números tengamos que destapar uno a uno todos los recuadros que no contienen nada. Si no se llamara a esta función, al pulsar en un recuadro de un área vacía, simplemente se destaparía ese recuadro y ningún otro más. Lo que hace esta función es destapar todo el área vacía, para agilizar el juego. | ||
Línea 481: | Línea 569: | ||
El algoritmo de la rutina de las líneas 3 a 14 lo que hace es lo siguiente: | El algoritmo de la rutina de las líneas 3 a 14 lo que hace es lo siguiente: | ||
- | | + | * Si la casilla actual es cero, destaparla (V(X,Y) = 1) y pintarla en pantalla. |
- | * Comprobar si las 8 casillas de alrededor son cero. | + | |
- | | + | |
La implementación es bastante ilegible (al estar optimizada) y es por eso que os animamos a mejorarla y hacerla más rápida utilizando un algoritmo diferente. | La implementación es bastante ilegible (al estar optimizada) y es por eso que os animamos a mejorarla y hacerla más rápida utilizando un algoritmo diferente. | ||
- | CÓMO PASAR NUESTRO PROGRAMA | + | \\ |
+ | ===== Cómo pasar nuestro programa | ||
Bas2tap es una utilidad muy interesante que permite teclear nuestros programas en BASIC en nuestro ordenador personal y después generar un tap tal y como si lo hubieramos tecleado en el editor del Spectrum. | Bas2tap es una utilidad muy interesante que permite teclear nuestros programas en BASIC en nuestro ordenador personal y después generar un tap tal y como si lo hubieramos tecleado en el editor del Spectrum. | ||
Línea 493: | Línea 581: | ||
Si grabamos el Listado 1 como zxmines.bas, | Si grabamos el Listado 1 como zxmines.bas, | ||
+ | < | ||
| | ||
+ | </ | ||
La sintaxis (explicada) es: | La sintaxis (explicada) es: | ||
+ | < | ||
-a1 : línea de autoarranque (en qué línea autocomenzará el programa sin | -a1 : línea de autoarranque (en qué línea autocomenzará el programa sin | ||
| | ||
| | ||
| | ||
+ | </ | ||
Podéis descargar BAS2TAP de la sección de Utilidades de WorldOfSpectrum. | Podéis descargar BAS2TAP de la sección de Utilidades de WorldOfSpectrum. | ||
- | LINKS | ||
- | | + | \\ |
- | * Fichero zxmines.tap (el programa ya compilado) | + | ===== Enlaces ===== |
- | * Concurso de BASIC 2003 de Bytemaniacos | + | |
- | * SevenuP | + | |
- | * bas2tap | + | * {{: |
+ | * [[http:// | ||
+ | * [[http:// | ||
+ | * [[http:// | ||
\\ | \\ | ||
- | ;#; | + | ;;# |
**Santiago Romero\\ Septiembre 2005\\ Magazine ZX #12** | **Santiago Romero\\ Septiembre 2005\\ Magazine ZX #12** | ||
- | ;#; | + | ;;# |