> ÍNDICE DE REVISTAS <
Número 2 - Agosto 2003 ZX Certified webmaster speccy.org
 

Segunda entrega de nuestro curso de juegos en BASIC, en la cual vamos a profundizar en qué son y cómo se usan las variables, las instrucciones que nos permiten tomar decisiones en nuestro programa, creación de subrutinas y el control del flujo de nuestro programa. Todo esto lo ilustraremos con algún pequeño ejemplo en forma de un sencillo juego con el que llevaremos a la práctica todos estos conceptos teóricos.

VARIABLES EN EL BASIC DEL SPECTRUM

Las variables son posiciones de memoria que se reservan para almacenar un determinado valor al que necesitamos acceder con facilidad desde nuestro programa y modificarlo a nuestro gusto. A estas posiciones de memoria se accede con el nombre que les damos al declarar las variables. Realmente poco nos importa en que posición de memoria las almacena nuestro ordenador, ya que siempre nos referiremos a ellas por su nombre.

  • DECLARACIÓN DE LAS VARIABLES

    Las variables tenemos que declararlas para poder usarlas, el ordenador no sabe ni el nombre ni el valor ni el tipo de la misma si no se lo decimos antes. Esto lo podemos hacer en cualquier lugar de nuestro programa siempre que lo hagamos antes de utilizarla. Para tener esto un poco más claro veamos el siguiente ejemplo:

    - PROGRAMA 1 -
    10 IF A=10 THEN LET A=A+1

    No os preocupéis, de momento, por lo que hace la línea anterior.

    Si ejecutamos la anterior línea con RUN, nos dará el siguiente error: 2 Variable not found, 10:1. Esto quiere decir que no ha encontrado la variable que intentamos utilizar en la parte uno de la línea 10, o lo que es lo mismo, la variable 'A' justo después del IF. El error ha sido generado por no haber declarado antes de su uso la variable.

    Añadamos al programa anterior la línea 5 LET A=10, de manera que el programa quede de la siguiente forma:

    - PROGRAMA 2 -
     5 LET A=10
    10 IF A=10 THEN LET A=A+1

    Lo volvemos a ejecutar con RUN y, en esta ocasión, nos devolverá el mensaje 0 OK, 10:2, con lo cual nos dice que la ejecución del programa se ha llevado a cabo correctamente.

    Si cambiásemos el número de la línea 5 por 15, nos volvería a generar un error de variable no definida, ya que declaramos la variable, pero después de hacer uso de ella.

  • TIPOS DE VARIABLES

    Las variables en el BASIC del Spectrum pueden ser de dos tipos: numéricas y alfanuméricas.

    • VARIABLES NUMÉRICAS

      Al contrario de lo que pasa en otros lenguajes de programación, en los que tenemos diferentes tipos de variables para cada número que queremos almacenar, INT, FLOAT, DOUBLE, etc., en el BASIC del Spectrum no se distingue el tamaño de las variables numéricas. Al contrario, en ellas podemos almacenar cualquier tipo de número, ya sea entero o fraccionario, positivo o negativo.

      El nombre por el que las vamos a designar debe comenzar obligatoriamente por una letra y puede estar seguida de más letras o números. Veamos los siguientes ejemplos de lo que son variables numéricas correctas e incorrectas:

      Variables numéricas correctas
      LET A=56
      LET A1=-456
      LET VIDAS=3
      LET X1X=5.60
      LET HOLA1N=-124.675

      Todas estas declaraciones de variables son perfectamente válidas. Y las siguientes no podríamos declararlas:

      Variables numéricas incorrectas
      LET 1=45
      LET 1A=-85
      LET 4PLAYER=3
      LET 1PUNTOS=5.5

      Al intentar teclear estas instrucciones, el intérprete BASIC del Spectrum simplemente no nos dejaría introducirlas, generando un pitido y colocando el cursor en el punto erróneo.

      A la hora de asignar los nombres a las variables numéricas, tenemos un par de excepciones que tener en cuenta: las variables que controlan los bucles y las que denominan a una matriz (a continuación explicamos qué es una matriz), que únicamente pueden estar nombradas con una sola letra:

      FOR F=1 TO 10: PRINT F: NEXT F sería correcto y
      FOR F1= 1 TO 10: PRINT F1: NEXT F1 sería incorrecto.

      Las variables que controlan los bucles no es necesario declararlas antes de utilizarlas, ya que en el mismo FOR se hace su declaración.

      DIM A(10,10) válido y
      DIM A1(10,10) inválido.

      Las matrices se componen de una serie de valores almacenados en una cuadrícula a la que se accede por el nombre de la variable más su índice, cuya numeración comienza por uno. Es decir, si tenemos declarada una variable tal que DIM A(10), podemos asignar a cada una de sus diez posiciones un valor diferente y utilizarlo de la misma forma que cualquier otra variable.

      Por ejemplo, si queremos asignar a la quinta posición de nuestra matriz llamada 'A' el valor 345, nos bastaría con hacer: LET A(5)=345 y lo podríamos utilizar, por ejemplo, de la siguiente forma: IF A(5)>345 THEN CLS.

      Las matrices pueden tener más de una dimensión, podemos tener una cuadrícula de NxN elementos, sin más límite que la memoria del Spectrum. Imaginaos que definimos A(10,10), con lo cual tendremos una matriz de 10x10=100 elementos, cada uno almacenando un valor independiente, y a la que accedemos de la siguiente forma: LET A(5,7)=10. ¿Sencillo, verdad?

      Imaginaos las aplicaciones que a una matriz se le puede dar en un juego. Valga como ejemplo el famoso juego de los barquitos, que los colocamos en una cuadrícula de NxN elementos, lo extrapolamos a una matriz y tendríamos el problema de cómo resolver su almacenamiento solucionado de una forma muy sencilla. Laberintos en un juego tipo Maziacs, las cartas en el Póker, etc.

    • VARIABLES ALFANUMÉRICAS

      El otro tipo de variables que tenemos disponibles son las alfanúmericas. En ellas podemos almacenar todo tipo de caracteres ASCII, es decir, números, letras y cualquier otro carácter o token del Spectrum.

      Los nombres de las variables alfanuméricas solo pueden estar formados por una letra seguidos del símbolo '$', y no son válidas como índice de bucles, aunque sí para realizar comparaciones y diferentes operaciones de cadenas, como pueden ser concatenar unas con otras, elminar caracteres, etc. Este tipo de variables necesita que el valor que vayamos a asignarlas se indique entre comillas. Unos cuantos ejemplos:

      Variables alfanuméricas correctas
      LET A$="BUENOS DIAS"
      LET A$="BUENOS"+"DIAS"
      LET A$=CHR$ 65 (CHR$ meterá el caracter ASCII correspondiente al código 65, en este caso la letra 'A').

      Todos los ejemplos anteriores son válidos y, al igual que anteriormente con los numéricos, los siguientes generarán un error:

      Variables alfanuméricas incorrectas
      LET A1$="BUENOS DIAS"
      LET A$=BUENOS DIAS

      También podemos crear matrices con contenido alfanumérico. Éstas tienen un peculiaridad muy importante. Siempre reservamos una longitud fija para almacenar la cadena. Mejor lo vemos con un ejemplo:

      DIM A$(10,10)

      Con esta instrucción le decimos a nuestro Spectrum que nos reserve memoria para una matriz de 10 elementos y con una longitud de 10 caracteres por elemento, es decir, podríamos almacenar diez 'frases' diferentes con una longitud de 10 caracteres y, si no rellenamos esos diez caracteres, el ordenador los rellena con espacios a la derecha de la cadena. Por ejemplo:

      LET A$(2)="HOLA"

      introduciría la palabra 'HOLA' (mejor dicho, sus códigos ASCII) en la posición 2 de la matriz, y rellenaría con seis espacios (carácter ASCII 32) los seis bytes restantes. Hay que tener en cuenta que cada carácter en ASCII tiene un byte de longitud.

    • CONSIDERACIONES FINALES SOBRE LAS VARIABLES

      Con las variables se pueden efectuar una amplia variedad de operaciones aritméticas, trigonométricas y lógicas: suma, resta, multiplicación, división, seno, coseno, etc., como pueden ser la siguientes:

      LET A=A+B que suma el contenido de las variables A y B dejando el resultado en A.
      LET A=A+1 que suma a la variable A uno a su valor inicial.
      LET A=C*10 que pone en A el resultado de multiplicar por 10 el contenido de la variable C.

      Y así con todas las operaciones disponibles.

      Debemos tomar por costumbre nombrar a las variables con nombres que nos indiquen su utilidad, pero teniendo en cuenta que a mayor longitud del nombre, más espacio ocupan en memoria, y en el Spectrum la RAM es un bien escaso. Como ejemplo nos puede valer lo siguiente:

      VIDASJ1=3 con lo cual queremos indicar que el jugador 1 tiene tres vidas; esto ocupa, sólo por la definición del nombre, 7 bytes, sin contar el coste de almacenar el valor en memoria. En cambio si ponemos 'VJ1=3' lo reducimos en 4 bytes, esto puede parecer poco, pero si nos imaginamos un programa que utilice 30 variables, y sumamos los bytes gastados en la declaración más los que usemos cada vez que tengamos que realizar una operación con ella, podemos darnos cuenta de que se nos dispara el consumo de memoria.

TOMANDO DECISIONES

Cuando programemos nuestro juego, llegará un momento en que tengamos que hacer una cosa u otra dependiendo de determinadas condiciones que se den en el programa: si se nos terminan las vidas tiene que finalizar la partida, si matamos a un enemigo, que nos incrementen los puntos, etc. Esto se puede hacer en BASIC con los comandos que nos provee.

Para tomar una decisión hacen falta dos elementos que queramos comparar (o más en alguna ocasión) y un operador lógico que realice la comparación, es decir, podemos ver si entre dos variables una es mayor que la otra, si son iguales, si diferentes...

La principal instrucción que nos da el BASIC para efectuar comparaciones es IF condición THEN. Con esto conseguimos que, si el resultado de la comparación es cierto, se ejecuten los comandos que vienen a continuación del THEN. Lo veremos más claramente con un ejemplo:

10 IF VIDAS=0 THEN PRINT "ESTAS MUERTO": STOP

Con esta instrucción comparamos si el contenido de la variable VIDAS es igual a 0, en caso afirmativo, se ejecutan los comandos situados después del THEN. En caso de que no sea cierta, simplemente se ignoran y se pasa la ejecución del programa a la siguiente línea del mismo.

Pero no sólo podemos realizar una comparación única por cada IF THEN que tengamos, podemos concatenar varias comparaciones:

10 IF VIDAS=0 OR TIEMPO=0 THEN PRINT "ESTAS MUERTO": STOP

Aquí hacemos dos comparaciones y gracias al operador lógico OR, las instrucciones a continuación del comando THEN se ejecutan si cualquiera de los dos casos se cumple, que vidas o tiempo sea igual a 0.

Podemos tener la necesidad de que tengan que ser ciertas las dos, y no sólo una. Para que nuestra condición se cumpla:

10 IF VIDAS>0 AND TIEMPO >0 THEN LET TIEMPO=TIEMPO-1

Fácil de comprender, si tenemos más vidas y tiempo que lo indicado, '0', ejecutamos las instrucciones colocadas después del THEN.

  • OPERADORES

    Con estos elementos podremos comparar diferentes circunstacias entre variables. Y siempre devolverá la comparación si es cierto o falso.

    • Mayor que ">" Cierto si el resultado de comparar el primer dato es mayor que el segundo.
    • Menor que "<" Cierto si el resultado de comparar el primer dato es menor que el segundo.
    • Igual que "=" Cierto si los dos datos son exactamente iguales.
    • Diferente que "<>" Será cierto si los datos comparados son diferentes.
    • Mayor o igual que ">=" Cierto si el primer dato es mayor o igual que el segundo.
    • Menor o igual que "<=" Cierto en caso de que el primer dato sea menor o igual que el segundo.

    Con este conjunto de operados lógicos podremos realizar las comparaciones necesarias en nuestro programa.

FLUJO DEL PROGRAMA

En el BASIC del Spectrum, las diferentes instrucciones de los programas las vamos introduciendo con un número delante, que nos sirve para poder controlar el flujo del programa como necesitemos durante la ejecución del mismo, entre otras cosas. La numeración de estas líneas la podemos indicar desde el número 1 al 9999, con los saltos intermedios que queramos, podemos numerarlas de 2 en 2, de 10 en 10, etc. Es aconsejable irlas numerando de manera que quede hueco entre una y otra para poder introducir una línea con instrucciones adicionales sobre la marcha, en caso de que sea necesario. Por ejemplo de 10 en 10.

En cualquier programa la ejecución de las instrucciones se va realizando de manera correlativa, en primer lugar la línea superior y consecutivamente las siguientes hasta llegar a la última. Esto para un programa sencillo puede servir, por ejemplo para uno que nos dé la equivalencia entre kilómetros y millas. Pero, en un juego, en el que hay porciones del programa que se ejecutarán varias veces, no es útil.

Tenemos dos instrucciones que nos van a permitir variar este flujo: GO TO y GO SUB.

  • GO TO

    Con GO TO saltaremos a la línea indicada después de la misma instrucción, saltando las que pudiese haber tanto delante como detrás de la misma:

    - PROGRAMA 3 -
     10 LET A=5
     20 IF A=5 THEN GO TO 100
     30 PRINT "NO ES CIERTO"
     40 STOP
    100 PRINT "SI ES CIERTO"

    Al ejecutar este programa, como A=5, ya que así lo hemos asignado al principio del mismo, la condición analizada en la línea 20 se cumple y se ejecuta la instrucción GO TO, saltando directamente a la línea 100 sin pasar por la 30 ni la 40. Podemos variar ahora la línea 10 cambíando 5 por cualquier otro número. Veremos cómo la condición no se cumple y la ejecución del programa sigue por la línea 30 finalizando en la 40 por obra del STOP situado en ella, instrucción que sirve para detener la ejecución del programa drásticamente.

  • GO SUB y RETURN

    La instrucción GO SUB es una evolución de GO TO ya que nos permite desviar en un momento dado la ejecución del programa, ejecutar un bloque de instrucciones y devolver el flujo a la línea siguiente donde se ejecutó el GO SUB con la instrucción RETURN. Este tipo de construcciones se denominan subrutinas.

    Lo vamos a ver con un ejemplo:

    - PROGRAMA 4 -
     10 LET A =5
     20 IF A=5 THEN GO SUB 100
     30 PRINT "DESPUES DEL GOSUB"
     40 STOP
    100 PRINT "EL GOSUB HA FUNCIONADO"
    110 RETURN

    Es un programa similar al que usamos para ilustrar al comando GO TO. Si la condición de la línea 20 se cumple, que lo hará porque A vale 5 en un comienzo, salta a la línea 100, ejecuta lo que hay en ella y al llegar a la instrucción RETURN de la línea 110 , devuelve el flujo a la línea 30, justo después de la ejecución del GO SUB.

    GO SUB nos va a ser muy útil a la hora de tener porciones de programa que se tienen que ejecutar varias veces, para no reescribirlos en varias ocasiones, simplemente lo tenemos una vez y cada vez que nos haga falta lo llamamos con el correspondiente GO SUB.

    Una precaución que tenemos que tener con el uso de RETURN, si lo ponemos en una línea, y el programa llega a ella sin haber ejecutado previamente una sentencia GO SUB, se detendrá la ejecución del mismo con el informe de error 7 RETURN without GO SUB, 0:1. Es decir, la ejecución de RETURN tiene que estar ligada forzosamente a una llamada anterior por medio de GO SUB.

    Damos por supuesto que el lector ha comprendido que la utilización de GO TO y GO SUB no se limita al ámbito de una instrucción comparativa, sino que puede ser puesta en cualquier línea como un comando más para alterar el flujo del programa:

    - PROGRAMA 5 -
     10 PRINT "HOLA MUNDO"
     20 GO TO 100
     30 REM A ESTA LINEA NO LLEGARA NUNCA LA EJECUCION DEL PROGRAMA
     40 REM YA QUE EL GO TO HACE QUE LA EJECUCION SALTE ESTA LINEA
    100 PRINT "POR AQUI CONTINUA EL PROGRAMA"

    Vemos una instrucción nueva, REM, que sirve para insertar comentarios en nuestros programas, y que no se ejecuta en ningún caso. Nuestro programa se ejecuta escribiendo un saludo y luego salta directamente a la línea 100.

BUCLES

Podemos tener la necesidad de ejecutar una serie de instrucciones un número determinado de veces. Para eso tenemos los bucles, formados por los comandos FOR TO, NEXT y STEP.

El comando FOR necesita de una variable que irá incrementando o decrementando hasta que la condición de salida sea cierta y salga del mismo. Esta variable no es necesario que se declare previamente y su nombre constará de una única letra.

10 FOR F=1 TO 10
20 PRINT F
30 NEXT F

Este programa ejecutará 10 veces las instrucciones contenidas entre las instrucciones FOR y NEXT. En la línea 10 le decimos que vamos a crear un bucle llamado F que va a comprender un rango de 1 a (TO) 10, en la línea 20 ejecutamos lo que queremos, en este caso un PRINT y en la 30 cerramos el bucle.

La iteración del bucle no tiene por que ir de uno en uno, podemos hacer que la suma sea mayor con la inclusión del comando STEP. Cambiamos la línea 10 únicamente:

10 FOR F=1 TO 10 STEP 2

El bucle ahora se ejecutaría la mitad de veces, ya que le estamos indicando que incremente el valor de F de dos en dos, en lugar de uno como es lo habitual.

Para hacer que el bucle se ejecute hacia atrás, necesitaremos ponerle obligatoriamente un STEP -1, ya que de otra manera, la iteración siempre suma. Cambiando la línea 10 del anterior programa por la siguiente podremos ver los resultados:

10 FOR F=10 TO 1 STEP -1

Podemos anidar un bucle dentro de otro sin ningún problema, siempre que nos preocupemos de cerrar el más interno antes de que se ejecute otra iteración del externo, Con un ejemplo lo veremos perfectamente:

- PROGRAMA 6 -
10 FOR F=1 TO 10
20 PRINT "TABLA DEL: ";F
30 FOR D=1 TO 10
40 PRINT F*D
50 NEXT D
60 NEXT F

Con este programa sacaremos por pantalla las tablas de multiplicar del 1 al 10, y podemos apreciar como antes de cerrar el bucle externo, hay que hacer lo propio con el interno, en caso contrario el resultado obtenido no será el deseado. Se puede probar intercambiando las líneas 50 y 60.

NUESTRO PRIMER JUEGO

Para ilustrar todo lo que acabamos de leer, vamos a crear un jueguecillo simple de adivinación de números en el que vamos a utilizar las instrucciones vistas hasta aquí.

- ADIVINACIÓN -
 10 PRINT "DEBE ADIVINAR UN NUMERO ELEGIDO ALEATORIAMENTE ENTRE 1 Y 100 EN LA CANTIDAD DE INTENTOS QUE USTED INTRODUZCA"
 20 INPUT "Introduzca el número de intentos (Max.10) ";A
 30 IF A<1 OR A >10 THEN GO TO 20
 40 LET VALOR=(RND*100)+1
 50 FOR F=1 TO A
 60 INPUT "INTRODUZCA NUMERO ";B
 70 IF B=VALOR THEN PRINT "ENHORABUENA, ACERTO EN ";F;" INTENTOS": STOP
 80 IF B>VALOR THEN PRINT "EL NUMERO INTRODUCIDO ES MAYOR"
 90 IF B<VALOR THEN PRINT "EL NUMERO INTRODUCIDO ES MENOR"
100 NEXT F
110 CLS: PRINT "NO HA SIDO CAPAZ DE ADIVINAR EL NUMERO EN ";A; " INTENTOS"
120 PRINT "EL NUMERO ERA ";VALOR

El programa es muy sencillo de entender, y solo haremos hincapié en unas cuantas instrucciones nuevas.

  • INPUT, que como se habrá podido apreciar, sirve para introducir un valor por el teclado y asignarlo a una variable.
  • PRINT, Sirve para presentar texto por pantalla.
  • RND, que vale para generar números aleatorios, en este caso le decimos que busque un número entre 1 y 100 (como puede asignar 0 a este valor, le sumamos 1 para que nunca ocurra este caso).
  • CLS, sirve para borrar la pantalla.
  • STOP, con este comando paramos la ejecución del programa.

Algunas de estas instrucciones las comentaremos en profundidad en próximos capítulos del curso, de momento con saber qué hacen será suficiente.

CONCLUSIONES

Este mes hemos visto una serie de instrucciones que van a ser imprescindibles para realizar nuestros programas, así como dejamos sentados unos cuantos conceptos de programación sin los cuales no conseguiremos realizar un proyecto medianamente serio.

El juego de ejemplo de este mes puede no decir gran cosa, ya que carece de gráficos, efectos, movimiento, etc. pero sirve perfectamente para ver todo lo explicado en este artículo.

En la siguiente entrega de este curso, en la que abordaremos la presentación gráfica y la lectura de teclado, veremos moverse algo por la pantalla controlándolo a nuestro antojo.


MIGUEL
 
Volver arriba
> ÍNDICE DE REVISTAS <
2003-2009 Magazine ZX