Tema 5: Programación en BASIC 1. Lenguajes de programación. Los lenguajes de programación son los "lenguajes" que se utilizan para dar órdenes o instrucciones al ordenador. Estas instrucciones han de ser traducidas (COMPILAR) a ceros y unos (CÓDIGO BINARIO) para que el ordenador las entienda y pueda ejecutarlas. Un PROGRAMA es el conjunto de órdenes que resuelven o realizan una determinada tarea. Tipos de lenguaje: Ensamblador / Bajo nivel, conocer todos los componentes del ordenador / máximo rendimiento. Basic, Pascal, C, Fortran / Alto nivel / Sencillos y funcionan en cualquier ordenador. Visual Basic, C++, Java, Actionscript / Orientados a objetos / hacen uso de objetos como ventanas, barras de desplazamiento, botones, etc. 2. Algoritmos y toma de decisiones. Cuando realizamos un programa, hemos de hacer previamente el diseño del mismo antes de comenzar a escribir las instrucciones. Hay que crear una especie de receta o conjunto de pasos para resolver el problema que se denomina ALGORITMO. El algoritmo se representa gráficamente por un DIAGRAMA DE FLUJO en el que cada tipo de operación se representa por un símbolo diferente. Las operaciones que podemos encontrar son: Procesos. Datos. Inicio y Fin. Salida por pantalla. Toma de decisiones. Ejemplo 1: diagrama de flujo de un algoritmo para calcular el área de un triángulo. Ejemplo 2: diagrama de flujo de un algoritmo para comprobar si un número es par o impar. 3. El lenguaje BASIC. Primer programa en BASIC. El lenguaje BASIC se llama así porque es un lenguaje sencillo, básico, ideal para aprender a programar. Existen muchas versiones de Basic: QBasic, TurboBasic, Liberty Basic o el moderno Visual Basic orientado al desarrollo de juegos. Vamos a escribir el siguiente programa: CLS PRINT PRINT "Hola a tod@s" PRINT "Este es mi primer programa en Basic" END Si ahora pulsas F5, el ordenador compilará el programa y lo ejecutará, apareciendo en pantalla el resultado de lo que acabamos de realizar. Las instrucciones de este programa significan: CLS: abreviatura de clear screen, que quiere decir que borra la pantalla. Se utiliza para que no aparezca nada escrito con anterioridad. PRINT "Mensaje": se emplea para presentar una frase o mensaje por pantalla. El texto del mensaje aparece entre comillas. La primera instrucción PRINT aparece sola, lo cual produce una línea de móvil. END: indica el final del programa. 4. Instrucciones gráficas. Para poder crear un programa que realice un gráfico sencillo, hemos de decir al ordenador la resolución con la que va a trabajar, es decir, el número de píxeles horizontales y verticales de la pantalla. Por esta razón, en los programas en los que creemos gráficos, la primera instrucción será SCREEN 12. Esta instrucción indica que la resolución será de 640x480 píxeles y 16 colores. Cualquier punto de la pantalla estará indicado por dos coordenadas: x, o desplazamiento horizontal, e y, o desplazamiento vertical. La instrucción que dibuja un punto es PSET(x,y), color, donde x es un número entre 0 y 639, e y, un número entre 0 y 479; en color se sustituye por un número entre 0 y 15. Para dibujar una línea, hemos de indicar el punto de inicio y el punto final. Se utiliza la instrucción LINE(x1,y1)- (x2,y2), color. Ejemplo 3: programa que crea una línea amarilla. CLS SCREEN 12 LINE(0,0)-(639,479),14 A la instrucción anterior se le puede añadir le puede añadir la opción ,B que dibuja un cuadrilátero a partir de la diagonal especificada. También admite la opción ,BF que rellena el cuadrilátero de color. Otras instrucciones útiles para dibujar son: CIRCLE(x,y), r, color: dibuja un círculo de radio r y color especificado en el punto (x,y). SLEEP t: detiene el ordenador durante t segundos. PAINT(x,y), pintura, límite: pinta una figura usando el color señalado en pintura. Debemos especificar un punto (x,y) del interior de la figura y el color de su perímetro en límite. Ejemplo 4: programa que crea un semáforo intermitente. SCREEN 12 CIRCLE(100,100),40,15 SLEEP 3 PAINT(100,100),14,15 SLEEP 2.5 PAINT(100,100),0,15 En este programa no se incluye la instrucción END, ya que en Basic es opcional. QBasic no distingue entre mayúsculas y minúsculas. 5. Variables. Hasta ahora, hemos creado unos programas que dan un mensaje o realizan una figura. Pero un programa resulta más útil cuando podemos modificar los valores de algunas cantidades o palabras que denominaremos de forma común VARIABLES. Una variable puede almacenar una cadena de caracteres, un número entero o un número real (con decimales). A una variable se le puede dar el nombre que queramos pero: Las variables cadena de caracteres siempre terminan en $. Las variables número entero siempre terminan en %. Las variables número real terminan en cualquier carácter excepto en los anteriores. Ejemplo 5: programa que pide el nombre y la edad. CLS INPUT INPUT ap% = PRINT END "¿Cómo te llamas";n$ "¿Cuántos años tienes";a% a% + 1 n$;"el año que viene tendrás";ap%;"años." En este programa se incluye la instrucción INPUT que permite sacar un mensaje por pantalla a la vez que pide el valor de una variable. El programa se detiene hasta que, mediante el teclado, introduzcamos el valor de la variable (pulsando INTRO). Es importante señalar que los mensajes deben ir entre comillas y separados del nombre de las variables por un ";". Como podemos ver en la 4ª línea, los valores des variables que introducimos en el programa, pueden ser modificados dentro del programa o utilizados para calcular otras variables (en este caso ap%). Con la instrucción PRINT que ya vimos, podemos mostrar el valor de las variables que han sido introducidos o calculados en el programa. Como en la instrucción INPUT los mensajes deben ir entre comillas y separados del nombre de la variable por un ";". Ejemplo 6: programa que suma dos números enteros. CLS INPUT INPUT suma% PRINT END "Introduce el primer número";n1% "Introduce el segundo número";n2% = n1% + n2% "El resultado es";suma% Operaciones con variables numéricas Las operaciones que pueden realizarse sobre variables numéricas (enteras o reales) son : Operador Operación Ejemplo (a = 11, b = 2) Resultado ^ Potenciación a^b 121 - Cambio de signo -a -11 * / Multiplicación y división a*b a/b 22 5,5 \ División entera a\b 5 Resto de división entera a MOD b 1 Suma y resta a+b a-b 13 9 MOD + - Nota: en algunas variantes de Basic y en otros lenguajes de programación, la división de un entero entre otro se realiza siempre como una división entera, desechando los decimales. También existen funciones que pueden aplicarse a las variables numéricas como: ABS(a): da el valor absoluto de “a”. INT(a): da la parte entera de “a”. SQR(a): calcula la raíz cuadrada de “a”. 6. La instrucción IF La instrucción IF es la que nos permite llevar a cabo la toma de decisiones en un programa. Tiene dos variantes: IF simple: funciona de la siguiente forma: IF condición THEN Instrucción 1 Instrucción 2 ... END IF Las instrucciones 1, 2, etc., se realizan cuando la condición se cumple (es cierta). En caso contrario no se realizan. IF compuesto: funciona de la siguiente forma: IF condición THEN Instrucción 1a Instrucción 2a ... ELSE Instrucción 1b Instrucción 2b ... END IF En el caso de que la condición se cumple, se realizan las instrucciones 1a, 2a, etc., y en caso contrario se realizan las instrucciones 1b, 2b, etc. Formas de indicar la condición: Condición (p = 7; q = 3; a$ = “SI”) Resultado p>q Verdadero p<0 Falso (p + q) = 10 Verdadero q >= 3 Verdadero q <= 3 Verdadero a$ <> “NO” Verdadero NOT(p < 0) Verdadero a$ = “SI” OR a$ = “si” Verdadero (p > q) AND (q < 3) Falso En la tabla han aparecido los operadores lógicos AND, OR y NOT. Funcionan de la siguiente forma: condición 1 AND condición 2: es VERDADERO si ambas condiciones son VERDADERAS y en caso contrario es FALSO. condición 1 OR condición 2K: es VERDADERO cuando al menos una de las condiciones es VERDADERA. Es FALSO cuando ambas condiciones son FALSAS. NOT(condición): es VERDADERO si la condición es FALSA. Ejemplo: Programa que pide un número y le suma 1 si éste es menor que 10. CLS INPUT “Introduce un número” ; n% IF n% < 10 THEN n% = n% + 1 PRINT “El número ha sido modificado y, ahora vale:” ;n% END IF END Ejemplo: Programa que comprueba si un número es par o impar. REM Par o Impar INPUT “Introduce un número” ; n% resto% = n% MOD 2 IF resto% = 0 THEN PRINT “El número”;n%;”es par” ELSE PRINT “El número”;n%;”es impar” END IF END La instrucción REM no produce ningún efecto en el programa, la utilizamos simplemente para poner algún comentario que nos indique cómo funciona o para que sirve el programa. Ejercicio: Realiza un programa que te haga una pregunta y que si la aciertas te felicite, pero si la fallas te mande a estudiar. Ejercicio: Realiza un programa que calcule la raíz cuadrada de un número si es positivo. En caso contrario debe avisar de que no se puede realizar. 6. Bucles. En programación un bucle es una repetición sucesiva de una o varias instrucciones que se realizan hasta que se cumple una condición de terminación. Existen dos tipos de bucles: Bucles de contador: realiza unas instrucciones desde que una variable que denominamos "contador" cumple una condición de inicio, hasta que cumple llega a una condición de finalización. Dentro del bucle el contador va cambiando de valor hasta que se llega a la condición de finalización. Tienen la estructura siguiente: FOR contador = inicio TO fin Instrucciones NEXT contador El bucle comienza en la instrucción FOR en la que la variable contador toma el valor inicial "inicio", realiza las Instrucciones y cambia (instrucción NEXT). Se repite este proceso hasta que el contador alcanza el valor que indiquemos en fin. Normalmente, al contador se le suele asignar una variable entera a la que le damos el nombre i%, j% ó k%, pero admite cualquier nombre de variable siempre que sea de tipo número entero. Ejemplo: Programa que suma los 100 primeros números. CLS suma% = 0 FOR i%=1 TO 100 REM i% es el contador suma% = suma% + i% NEXT i% PRINT "El resultado es:";suma% END Ejemplo: Programa dibujar 150 circunferencias concéntricas. SCREEN 12 FOR i%=1 TO 150 REM i% es el contador y también indicara el radio. REM c% indica el color y tomara valores 0, 1 ó 2. c% = i% MOD 3 CIRCLE(320,240),i%,c% NEXT i% END Ejemplo: Programa que hace una cuenta atrás. SCREEN 12 FOR i%=10 TO 0 STEP -1 REM i% es el contador que, ahora, va hacia atrás. LOCATE 10, 10 PRINT i% SLEEP 1 NEXT i% END En este último ejemplo, cabe destacar que hemos utilizado la instrucción STEP -1 para indicar que el contador disminuya cada vez una unidad. En los anteriores casos en que no hemos puesto nada, el contador aumenta de 1 en 1. Con STEP podemos elegir el "paso" que queramos (2 en 2, 3 en 3, -2 en -2, etc.). La instrucción LOCATE sitúa el cursor en la posición x,y (en este caso x = y = 10) de la pantalla. Bucles condicionales: los bucles condicionales sirven para realizar una serie de instrucciones hasta que se cumple una condición. Sin embargo, a diferencia del caso anterior, esta condición no es necesario que la cumpla un contador; puede ser, por ejemplo, el pulsado de una tecla. DO Instrucciones LOOP UNTIL condición Ejemplo: Programa que muestra la hora en pantalla hasta que pulsamos la tecla "f". CLS DO a$ = TIME$ SLEEP 1 LOCATE 12,35:PRINT a$ b$ = INKEY$ LOOP UNTIL b$ = "f" END La instrucción TIME$ nos da la hora del ordenador y, en este caso, la asigna a la variable a$. Por su parte, la instrucción INKEY$, detecta si se ha pulsado alguna tecla y, en este caso le asigna su valor a la variable b$. En muchas ocasiones puede ser mejor que el programa termine al apretar cualquier tecla, en lugar de una en concreto. En ese caso, cambiaríamos la instrucción del final del bucle por: LOOP UNTIL b$ <> "" Es decir, hasta que la variable b$ es distinta de "" (sin valor), lo cual ocurre al apretar cualquier tecla ya que está acción le asignará un valor diferente sin valor. 7. Aleatoriedad. Algunos procesos, como lanzar una moneda al aire o tirar un dado, son fenómenos aleatorios, es decir, no podemos conocer a priori, su resultado. Lo único que podemos saber es la probabilidad de que suceda cada resultado posible. En nuestros programas, introduciremos la aleatoriedad generando número al azar, es decir, números cuyo valor nos dará el ordenador pero que nosotros no sabemos de antemano lo que valen. La instrucción RANDOMIZE TIMER indica al ordenador que debe comenzar a generar números al azar. A partir de ese momento, cada vez que utilicemos la instrucción RND, generaremos un número al azar comprendido entre 0 y 1. Hay que señalar que el número generado nunca es exactamente 0 ni 1. Ejemplo: Programa que "simula" el lanzamiento de una moneda al aire. REM Cara o cruz RANDOMIZE TIMER a = RND IF a < 0.5 THEN PRINT "Cara" ELSE PRINT "Cruz" ENDIF END Cuando queramos generar números aleatorios mayores que 1, tenemos que modificar la instrucción RND. Por ejemplo, para simular el lanzamiento de un dado necesitamos números enteros entre 1 y 6. La instrucción: a = 6*RND generaría un número aleatorio entre 0 y 6 (nunca 0 ni 6). El problema es que el número no sería entero. Para transformarlo en entero podríamos hacer: a = INT(6*RND) Pero esta instrucción nos generaría números entre 0 y 5. Para resolverlo sumamos 1: a = INT(6*RND) + 1 Esto ya nos genera número entre 1 y 6. 8. Trabajo con muchos datos. 8.1. Arrays En ocasiones un programa requiere que trabajemos con muchos datos, que deberíamos almacenar en diferentes variables, una por cada dato. Por ejemplo, podemos crear un programa para almacenar las horas a las que empieza cada clase en un colegio y nos avise para dar el timbre: CLS REM Activar Timbre REM Las horas se almacenan como INPUT "Hora de entrada";h1$ INPUT "Segunda hora";h2$ INPUT "Tercera hora";h3$ INPUT "Cuarta hora";h4$ INPUT "Quinta hora";h5$ INPUT "Sexta hora";h6$ INPUT "Séptima hora";h7$ INPUT "Hora de salida";h8$ i = 1 DO h$ = TIME$ IF h$ = h1$ THEN LOCATE 12,35: PRINT i = i + 1 END IF IF h$ = h2$ THEN LOCATE 12,35: PRINT i = i + 1 END IF … … IF h$ = h8$ THEN LOCATE 12,35: PRINT i = i + 1 END IF b$ = INKEY$ LOOP UNTIL b$ = "f" OR i = 9 END cadena de caracteres "ACTIVA TIMBRE" "ACTIVA TIMBRE" "ACTIVA TIMBRE" El programa termina al final del día (i = 9) o cuando pulsamos "f". En este programa vemos lo costoso que resulta trabajar de esta manera cuando tenemos muchas variables (y eso que 9 no son tantas!). Para resolver esta dificultad existen los Arrays, que son unas variables pueden almacenar muchos valores al mismo tiempo, siendo cada una de ellas identificada por un valor distinto de un índice. Un Array es, por tanto, un elemento que permite almacenar diversas variables del mismo tipo. Para crear un array utilizamos la instrucción DIM indicando, a continuación, el nombre del array (con la misma terminación que el tipo de variables que va a almacenar) y, entre paréntesis, sin poner espacios tras el nombre del array, el número de variables que podrá almacenar. Por ejemplo, en el caso anterior, podríamos crear un array de 8 variables de tipo cadena de caracteres de la siguiente forma: DIM horas$(8) Con esto, podríamos modificar el programa anterior haciéndolo más compacto: CLS REM REM DIM FOR Timbre automático Las horas se almacenan como cadena de caracteres horas$(8) i = 1 TO 8 INPUT "Teclea la hora";horas$(i) NEXT i i = 1 DO h$ = TIME$ IF h$ = horas$(i) THEN LOCATE 12,35: PRINT "ACTIVA TIMBRE" i = i + 1; END IF b$ = INKEY$ LOOP UNTIL b$ = "f" OR i = 9 END 8.2. Leer y escribir en archivos externos. Hasta ahora, los resultados de los programas que hemos realizado se guardaban en la memoria mientras el programa se encontraba en ejecución, pero luego se perdían. La ventaja de la utilización de archivos externos es que si queremos que los resultados que producen nuestros programas, podemos guardarlos en algún archivo de texto. Además, también podremos hacer que nuestros programas lean los datos desde algún archivo de texto y, de este modo, no tendremos que teclearlos cada vez. Las instrucciones que utilizaremos para escribir en un archivo de texto serán: OPEN nombre_archivo FOR OUTPUT AS #nº_archivo: abre (y lo crea si no existe previamente) un archivo con el nombre especificado en nombre_archivo. Con la instrucción FOR OUTPUT indicamos que ese archivo recogerá los resultados del programa. La instrucción AS #nº_archivo crea un identificador del archivo para que, después, podamos referirnos a él de forma rápida y sencilla. WRITE #nº_archivo: sirve para escribir en el archivo especificado por el identificador #nº_archivo los resultados del programa. Veamos un ejemplo que nos permite escribir en un archivo las horas en las que tendrá que sonar el timbre del apartado anterior: CLS REM Fichero de datos para el timbre automático OPEN "C:\Tecno\timbre" FOR OUTPUT AS #1 i = 1 DO INPUT "Teclea la hora o pulsa f";h$ IF h$ <> "f" THEN WRITE #1, i, h$ REM "i" indica el número de hora i = i +1 END IF LOOP UNTIL h$ = "f" CLOSE #1 END La instrucción CLOSE #nº_archivo cierra el archivo en el que se han escrito los datos. En este ejemplo, se crea un archivo llamado timbre dentro de la carpeta Tecno que se encuentra en el disco duro (C:). El bucle permite ir escribiendo todas las horas hasta que le damos la condición de finalización (teclear "f"). La instrucción WRITE escribe los resultados en un fichero que queda de la siguiente forma: Las instrucciones que utilizaremos para leer de un archivo de texto serán: OPEN nombre_archivo FOR INPUT AS #nº_archivo: abre (el archivo debe existir previamente) un archivo con el nombre especificado en nombre_archivo. Con la instrucción FOR INPUT indicamos que de ese archivo se leerán los datos con los que trabajará programa. La instrucción AS #nº_archivo crea un identificador del archivo para que, después, podamos referirnos a él de forma rápida y sencilla. INPUT #nº_archivo, variable1, variable2: sirve para leer del archivo especificado por el identificador #nº_archivo las variables incluidas en la lista. Veamos un ejemplo que lee las horas del archivo timbre y las utiliza para dar el mensaje de activar el timbre: CLS REM Timbre automático con lectura de datos externa. REM Las horas se almacenan como cadena de caracteres DIM horas$(8) DIM Num(8) OPEN "C:\Tecno\timbre" FOR INPUT AS #1 i = 1 DO INPUT #1, Num(i), horas$(i) i = i +1 LOOP UNTIL (EOF(1)) i = 1 DO h$ = TIME$ IF h$ = horas$(i) THEN LOCATE 12,35: PRINT "ACTIVA TIMBRE":SLEEP 15 i = i + 1; END IF b$ = INKEY$ LOOP UNTIL b$ = "f" OR i = 9 CLOSE #1 END Mediante el primer bucle (DO … LOOP UNTIL (EOF(1))), el programa lee, el número de hora y las horas del archivo timbre y las guarda en los arrays Num y horas$. La condición de finalización del bucle utiliza la función EOF(nº_archivo) que da el valor VERDADERO cuando se llega al final del archivo que se está leyendo, de forma que, en ese momento, termina la lectura de datos. El segundo bucle (DO … LOOP UNTIL b$ = "f" OR i = 9) consulta continuamente la hora mediante h$ = TIME$ y la compara con la primera hora almacenada en el array (observa que, al entrar al bucle, i = 1). Cuando coinciden las dos horas [h$ = horas$(i)], se da el mensaje de activar el timbre y aumenta el valor de i. De esta forma, la siguiente comparación se realizará entre la segunda hora almacenada en el array (i = 2) y la hora actual. Si se pulsa "f" o ya no hay más clases (i = 9), el programa sale del bucle y termina. 8.3. Subrutinas. En algunas ocasiones, hay algunas operaciones que queremos realizar muchas veces y para realizarlas, hemos de realizar, cada vez varias operaciones complicadas. Por ejemplo, podemos crear un programa que dibuje un círculo situado cada vez en diferentes posiciones. Con este fin, nos interesaría tener un miniprograma que haga la operación de crear un circunferencia y, que cada vez que queramos hacer una, nos baste con hacer una llamada a este miniprograma. Este tipo de miniprogramas se pueden realizar y se denominan subrutinas. Subrutinas sin argumentos La instrucción que nos permite hacer una llamada a una de estas subrutinas es GOSUB seguido del nombre de la subrutina. Por su parte, la subrutina es similar a cualquier otro programa pero debe comenzar con el nombre que se le haya dado, seguido de dos puntos, y debe terminar con la instrucción RETURN que indica que se debe volver, una vez realizadas todas las operaciones, al programa principal. Veamos, mejor, el funcionamiento de las subrutinas con un ejemplo: Ejemplo: programa que dibuja un círculo amarillo utilizando una circunferencia. SCREEN 12 GOSUB PELOTA BEEP 'Tras dibujar la pelota el programa emite un pitido' END PELOTA: CIRCLE(100,100), 10, 7 PAINT(100,100), 14, 7 RETURN La primera parte, lo que llamamos programa principal, lo único que hace es llamar a la subrutina PELOTA, que es la encargada de crear un círculo de radio 10 píxeles y pintarlo de amarillo. Cuando la subrutina termina vuelve (RETURN) al programa principal y, entonces, se emite un pitido. Subrutinas con argumentos El anterior tipo de subrutinas es interesante para algunas cosas como dibujar de forma repetida una figura. Sin embargo, resulta mucho más útil el uso de otro tipo de subrutinas que permiten pasar valores entre el programa principal y la propia subrutina. Para emplear este tipo de subrutinas, el programa principal debe incluir, antes que cualquier otra, la instrucción DECLARE SUB nombre_subrutina(lista de argumentos). En esta expresión, nombre_subrutina es el nombre que daremos a la subrutina y lista de argumentos es una serie de variables que enviamos a la subrutina, o bien que la subrutina nos devuelve. En este caso, para llamar a la subrutina, utilizaremos nombre_subrutina(lista de argumentos). Veámoslo con un ejemplo: la función CALL Ejemplo: programa que crea 10 círculos amarillos de posiciones y tamaños aleatorios utilizando una subrutina. DECLARE SUB PELOTA2(x,y,r) SCREEN 12 RANDOMIZE TIMER FOR i = 1 TO 10 x1 = 639*RND x2 = 379*RND r1 = 15*RND + 1 CALL PELOTA2(x1, x2, r1) NEXT i END ……………………………………………………………………………………………… SUB PELOTA2(a1,a2,a3) CIRCLE(a1,a2), a3, 7 PAINT(a1,a2), 14, 7 BEEP END SUB En este caso, el programa principal no aparece junto a la subrutina. En cuanto escribamos la instrucción SUB para comenzar a crear la subrutina, el editor nos abrirá una nueva ventana donde crearla. Para pasar del programa principal a la subrutina y viceversa, hemos de pulsar "F2" y elegir aquella parte que queramos modificar. El funcionamiento de este ejemplo es más sencillo de lo que puede parecer. Primero, en el programa principal se declara la subrutina que se va a utilizar. Se debe poner el nombre y la lista de argumentos que va a utilizar. Importante: los argumentos que ponemos al declarar la subrutina no tienen que tener el mismo nombre que las variables que se le pase (observa que la instrucción CALL PELOTA2(x1, x2, r1) no utiliza los mismos nombre que al declarar la función), pero sí deben ser del mismo tipo. El programa hace un bucle de 10 iteraciones en el que, cada vez, se genera un número aleatorio entre 0 y 639 para la posición x (x1) y otro número aleatorio entre 0 y 379 para la posición y (x2). Así mismo, se genera un valor aleatorio del radio entre 1 y 16. Estos valores se le envían a la subrutina que los recibe en forma de sus propias variables a1, a2 y a3, que, de nuevo, no es necesario que tengan el mismo nombre que en el programa principal que en la subrutina paro sí que sean del mismo tipo. Con estas variables a1, a2 y a3 la subrutina crea un círculo, lo pinta de amarillo y emite un pitido antes de volver al programa principal, en el que el bucle continúa hasta que se realizan 10 iteraciones. ¿Por qué tanto lío con el nombre de las variables? es decir, ¿por que no utilizar siempre el mismo nombre? Hay dos razones: 1. Por un lado, la razón de que en el programa principal y en la subrutina las variables tengan nombres diferentes es que las subrutinas se pueden crear de forma independiente a los programas para luego se utilizados por varios de ellos. Es decir, puedo crear una subrutina, guardarla y, después, esa misma subrutina utilizarla con muchos programas. De este modo, cada vez que creamos un programa que vaya a utilizar la subrutina es suficiente con saber el tipo de argumentos que utiliza y no su nombre exacto. 2. El hecho de que en la declaración y en la llamada los nombre de las variables puedan ser diferentes es debido a que, en ocasiones nos puede convenir utilizar instrucciones como esta: FOR i = 1 TO 10 CALL PELOTA2(i,i,i*i) NEXT i que genera círculos en las posiciones (x=1,y=1), radio = 1; (x=2,y=2), radio 4, y así sucesivamente. Al no crear una variable para x y otra para y cada vez, ahorramos espacio de memoria y tiempo de ejecución. En cualquier caso, si no nos entendemos bien con diferentes nombres, utilizaremos siempre el mismo. Ejemplo: programa que ordena tripletes de números. DECLARE ORDENA(x1,x2,x3) REM x1, x2 y x3 serán los número de entrada sin ordenar REM La subrutina devolverá en x1, x2 y x3 los números ordenados de REM menor a mayor INPUT "Dame un número";x1 INPUT "Dame otro número";x2 INPUT "Dame otro más";x3 CALL ORDENA(x1, x2, x3) LOCATE 12, 35: PRINT x1;"<";x2;"<";x3 END ……………………………………………………………………………………………… SUB ORDENA(a1,a2,a3) DIM A(3) A(1) = a1 A(2) = a2 A(3) = a3 FOR i = 1 TO 3 FOR j = 1 TO i IF A(j) > A(i) THEN amin = A(i) A(i) = A(j) A(j) = amin END IF NEXT j NEXT i a1 = A(1) a2 = A(2) a3 = A(3) END SUB 8.4. Guardar imágenes en memoria. Volviendo al programa que dibujaba una pelota por medio de una subrutina, vamos a ver cómo podemos conseguir que el dibujo se guarde en la memoria. Para ello, hemos de reservar una cantidad de memoria y guardar el dibujo en la misma. Estudiemos el ejemplo: SCREEN 12 DIM bola%(2000) GOSUB PELOTA GET(88,88)-(112,112), bola% CLS END PELOTA: CIRCLE(100,100), 10, 7 PAINT(100,100), 14, 7 RETURN Guardar el dibujo en la memoria La instrucción DIM bola%(2000) reserve 2000 posiciones de memoria (2000 bytes) para guardar el dibujo y, a ese espacio "reservado" le denomina bola%, para, más tarde, poder hacer referencia e él. Una vez reservada la memoria, y con el dibujo en pantalla, se recorta y quarda en la memoria del ordenador. Para ello se utiliza la instrucción GET(x1,y1)-(x2,y2), bola%. Esta instrucción recorta un rectángulo (que debe englobar al dibujo) de extremo superior izquierdo (x1,y1) y extremo inferior derecho (x2,y2) y lo guarda en bola% u otro nombre que especifiquemos a continuación del segundo vértice. Llevar el dibujo de la memoria a la pantalla Para ver cómo podemos llevar un dibujo guardado en la memoria a la pantalla, analicemos el siguiente ejemplo: SCREEN 12 DIM bola%(2000) GOSUB PELOTA GET(88,88)-(112,112), bola% CLS FOR y = 1 TO 200 PUT(200,y), bola%, pset GOSUB RETARDO NEXT y END …………………………………………………………………………………… PELOTA: CIRCLE(100,100), 10, 7 PAINT(100,100), 14, 7 RETURN RETARDO: FOR i = 1 TO 10000 i = 1 + 1 NEXT i RETURN En este ejemplo, el programa principal, en primer lugar crea una pelota amarilla (instrucción GOSUB) y la guarda en la memoria con el nombre de bola% (instrucción GET). Una vez guardada la pelota, el programa entra en un bucle que utiliza la instrucción PUT(200, y), bola%, pset. Esta instrucción lo que hace es situar el objeto guardado con el nombre bola% con su vértice superior izquierdo en la posición (x=200, y). Añadir pset al final sirve para que, en su desplazamiento, la pelota no borre el fondo de la pantalla (si quieres entender mejor qué significa esto, prueba el programa con y sin pset). Como y va cambiando, la pelota irá bajando en la pantalla. La llamada a la subrutina RETARDO lo único que hace es perder el tiempo para que la pelota no vaya tan rápida. Apéndice I: Ejercicios. 1) Realiza un programa que dibuje los aros olímpicos. 2) Modifica el programa anterior para que los aros salgan uno tras otro. 3) Realiza un programa que calcule la intensidad de corriente que atraviesa una resistencia a partir del valor de la misma y del voltaje entre sus extremos. Diseña antes de escribir el programa en Basic el correspondiente diagrama de flujo. (Recuerda (I = V/R )). 4) Realiza un programa que te haga una pregunta y que si la aciertas te felicite, pero si la fallas te mande a estudiar. 5) Realiza un programa que calcule la raíz cuadrada de un número si es positivo. En caso contrario debe avisar de que no se puede realizar. 6) Realiza un programa que realice una cuenta atrás pero que nos pida los valores de tiempo inicial y final. 7) Crea un programa que controle el funcionamiento de un semáforo (que cambie entre verde, rojo y amarillo) y que emita pitidos para avisar a las personas ciegas de que pueden cruzar. 8) Crea un programa que nos muestra la hora en pantalla y que finalice al pulsar cualquier tecla. 9) Crea un programa que genere 100 puntos situados aleatoriamente en la pantalla y cuyo color también sea generado al azar. 10) Realiza un programa que simule el lanzamiento de un dado. 11) Modifica el programa anterior para almacenar en un array de 6 posiciones el número de veces que sale cada número (de 1 a 6) cuando lanzamos el dado 500 veces. 12) Realiza un programa que almacene en un array de 22 posiciones los nombres y apellidos de los alumnos de 4º de ESO y en otro sus edades. 13) Modifica el programa anterior para que los nombres y las edades se guarden en un archivo de texto (Nombre Apellido1 Apellido2, Edad ). 14) Crea un programa que lea el archivo de texto anterior con los nombres y las edades y escriba en otro archivo de texto diferente el nombre y los apellidos de los alumnos junto con su asignatura preferida (que tendrá que preguntar el programa). 15) Crea un programa que genere 300 números al azar entre 0 y 1000 y los escriba en un archivo de texto llamado numaleat.txt de tres en tres (x1, x2, x3). 16) Utilizando la subrutina ORDENA, crea un programa que lea el archivo numaleat.txt, que ordene los tríos de números y los guarde de nuevo, ordenados, en un archivo llamado ordenados.txt. 17) Mediante modificaciones en el programa de la pelota en movimiento, crea un nuevo programa en el que dos pelotas se muevan según las diagonales de la pantalla y se crucen en el centro. Apéndice II: glosario de instrucciones A continuación se muestra un listado de las instrucciones más utilizadas en QBasic con una breve descripción de su función. Este glosario es únicamente una referencia de consulta rápida para aquellos usuarios que se hallan familiarizado ya un poco con el uso de las diferentes instrucciones. Las explicaciones más detalladas se pueden encontrar a lo largo del documento. BEEP: el programa emite un pitido. CALL nombre_subrutina(lista_argumentos): llama a la subrutina con el nombre especificado por nombre_subrutina, enviándole las variables que sirven de argumentos especificados en la lista de argumentos. Estas variable pueden ser modificadas o no en la subrutina antes de ser devueltas al programa principal. CLS: borra la pantalla. CIRCLE(x,y), r, color: dibuja una circunferencia de radio r con centro en el punto (x,y) y del color especificado en color. CLOSE #nº_archivo: cierra el archivo correspondiente al identificados dado por nº_archivo. DECLARE SUB nombre_subrutina: declara la subrutina que será utilizada en el programa principal. DIM nombre_array(tamaño): especifiquemos en tamaño. DO declara un array de tantas variables como procesos LOOP UNTIL condición Realiza iterativamente las instrucciones que figuran en la lista de procesos hasta que se cumple la condición de finalización. END: indica final de programa. END SUB: indica final de subrutina. EOF(nº_archivo): comprueba si el archivo correspondiente al identificador nº_archivo a llegado a su final. FOR contador = inicio TO fin STEP paso procesos NEXT contador Realiza iterativamente las instrucciones que figuran en la lista de procesos desde que el contador tiene el valor de inicio hasta que toma el valor final, aumentando o disminuyendo éste en cada iteración tantas unidades como especifiquemos en paso. IF condición THEN procesos END IF Realiza las instrucciones que figuran en la lista de procesos si se cumple la condición. IF condición THEN procesos si verdadero ELSE procesos si falso END IF Realiza las instrucciones que figuran en la lista de procesos si verdadero si se cumple la condición, y en caso contrario se llevan a cabo las instrucciones que figuran en la lista procesos si falso. GET(x1,y1)-(x2,y2), nombre_objeto: guarda un dibujo, comprendido en el rectángulo de vértice superior izquierdo (x1,y1) y vértice inferior izquierdo (x2,y2), con el nombre nombre_objeto. GOSUB nombre_subrutina: llama a la subrutina especificada por nombr_subrutina. INKEY$: lee el valor de la tecla que pulsemos. INPUT "Mensaje"; [lista_variables]: muestra en pantalla la cadena de texto incluida en Mensaje y lee los valores de las variable incluidas en lista_variables. INPUT LINE(x1,y1)-(x2,y2), color: dibuja una línea del color especificado por color entre los puntos (x1,y1) y (x2,y2). LOCATE x,y: situa el cursor en la posición (x,y) de la pantalla. OPEN nombre_archivo FOR OUTPUT AS #nº_archivo: abre un archivo con el nombre especificado, creándolo en caso de que no exista previemente, para escritura y le asigna un identificador para poder hacer, más tarde, referencia a él. OPEN nombre_archivo FOR INPUT AS #nº_archivo: abre un archivo con el nombre especificado, para lectura y le asigna un identificador para poder hacer, más tarde, referencia a él. PAINT(x,y), limite, color: pinta del color especificado por color el relleno de la figura que tenga como punto interior (x,y) y su borde lo pinta del color especificado por limite. PRINT "Mensaje" / PRINT [lista de variables]: muestre en pantalla la cadena de texto incluida en Mensaje y/o una serie de variables. Los mensajes y las variables se pueden intercalar separando unos de otras por medio de ";". PSET(x,y), color: dibuja un punto del color especificado por color en la posición (x,y). PUT(x y), nombre_objeto, pset: muestra un dibujo guardado en memoria con el nombre nombre_objeto, colocándolo en la posición (x,y). La opción pset evita que el objeto borre el fondo de la pantalla. RENDOMIZE TIMER: inicializa el generador de números aleatorios. REM comentario: se utiliza para escribir comentarios, que no tendrán ninguna influencia en el programa, que nos ayudarán a comprender su funcionamiento. #nº_archivo, lista_variables: lee las variables incluidas lista_variables del archivo correspondiente al identificador nº_archivo. en RETURN: indica que una subrutina que no admite argumentos ha terminado y ha de volver al programa principal. RND: genera un número aleatorio entre 0 y 1. SCREEN 12: establece la definición de pantalla en 640x340 píxeles y 15 colores. SLEEP t: detiene el programa durnante t segundos. SUB nombre_subrutina(lista_argumentos): indica el inicio de la subrutina nombre_subrutina que utiliza y devuelve las variables incluidas en lista_argumentos. TIME$: lee la hora del ordenador en formato cadena de caracteres. WRITE #nº_archivo, lista_variables: escribe en el archivo de texto correspondiente al identificador nº_archivo las variables incluidas en lista_variables.