Bloques de control – Repeticiones

En ocasiones necesitamos que nuestros programas repitan varias veces las mismas acciones. Imagina que quieres enviar el mismo mensaje de correo electrónico a diez personas distintas. En lugar de tener que escribir diez veces las mismas instrucciones para cada destinatario, podemos usar un bucle o repetición para ahorrarnos el trabajo.
En este capítulo vamos a aprender cómo hacerlo.

 Introducción

En ocasiones necesitamos que nuestros programas repitan varias veces las mismas acciones. Imagina que quieres enviar el mismo mensaje de correo electrónico a diez personas distintas. En lugar de tener que escribir diez veces las mismas instrucciones para cada destinatario, podemos usar un bucle o repetición para ahorrarnos el trabajo.

 Bucles (for range)

Cuando sabes de antemano el número de repeticiones que necesitas usamos el bloque de control for range. Vamos con un ejemplo.
Crea un nuevo proyecto y llámalo "bucles".
Desde el Diseñador añade a tu programa un botón y debajo una etiqueta.
Cambia el texto del botón por "Repetir".
Ahora vamos al Editor de bloques.
Lo primero que vamos a hacer es crear tres variables numéricas. A la primera llámala min, a la siguiente max y a la última salto.
A la variable min dale un valor de 1, a la variable max dale 10 y a la variable salto 1.
Ahora coge el evento del botón .Click. Dentro de este evento lo primero que vamos a hacer es poner la etiqueta en blanco. Usa el bloque set Label1.Text y pégale un bloque de texto en blanco.
Después coge el bloque “for each number” que encontrarás dentro de Built-in/Control.
Este bloque va a repetir las instrucciones que pongamos dentro tantas veces como rango de números haya entre from y to. Si el valor de from es 1 y el valor de to es 10, el bucle se activará 10 veces, es decir, repetirá 10 veces lo que pongamos dentro.
Utiliza las variables que acabamos de crear y ponlas en from y to respectivamente.
El siguiente parámetro que nos interesa se llama by (salto) y nos permite decidir si queremos que mientras se ejecuta el bucle saltemos un número de pasos. Con el ejemplo lo vas a entender mejor.
10 Pon la variable salto que hemos creado antes aquí.
Por último el parámetro variable que AppInventor pone por nosotros como number contiene el número actual de la repetición. Es decir, si estamos haciendo un bucle desde el número 1 hasta el número 10, esta variable nos dirá si en este momento estamos en la repetición 5 o 6, etc.
11 Ahora vamos a cambiar la etiqueta para que nos muestre una frase. Coge el bloque "set label1.Text" y ponlo dentro del bloque for range do.
12 Ahora necesitamos crear un bloque de texo join con tres cadenas. Para introducir una cadena más de las que no da el bloque por defecto has click en la rueda azul y añade un bloque string más.
13 Ahora te quedarán tres espacios libres. En el primer espacio ponemos la variable "Label1.Text" que está dentro de Screen1/Label1.
14 En el segundo espacio, la variable i que encontrarás en Built-in/Variables, y la capturamos con el bloque get.
15 Y en el último espacio añade un bloque de texto y escribe por ejemplo: " - Esto es un bucle! ". No olvides el espacio al principio del texto y poner al final " ". De esta forma hacemos un salto de línea.
Prueba ahora tu programa y prueba a cambiar las variables que añadimos al principio para que entiendas como funciona. Cambia también la variable salto para que veas el resultado. Prueba también con estos valores: min=10, max=1 y step=-1 ¿Qué ocurre en este caso?

 Mientras sea cierto (While)

Existe otro tipo de bucles (repeticiones) que podemos usar cuando no sabemos con anterioridad el número de repeticiones que vamos a necesitar. En este caso las instrucciones se repiten dependiendo de que una condición lógica sea verdadera o falsa.
Imagina un programa para controlar la temperatura de tu habitación. Si la temperatura sube por encima de 25 grados entonces tu programa activa un evento y enciende el aire acondicionado. A partir de ese momento podrías utilizar un bucle while (mientras) que fuera algo así: "mientras temperatura > 25 entonces aire acondicionado sigue encendido". Cuando la condición deja de cumplirse "temperatura < 25" el bucle terminaría y apagaríamos el aire acondicionado. Vamos a verlo con otro ejemplo:
Vamos a crear una aplicación que busque un número al azar (azar) entre un rango de números (min y max). Cuando encontremos el número que buscamos (premio) nos dirá cuántos intentos ha necesitado (intentos). En cada repetición nuestro programa pensará un número al azar (azar) y si el número que ha pensado no coincide con el que buscamos (premio) volverá a intentarlo hasta encontrar el que buscamos. Entonces el programa termina y nos dice el número de intentos (intentos) que ha necesitado.
Crea un proyecto nuevo y llámalo "bucle_azar".
Desde el Diseñador añade un componente textbox, un botón y finalmente una etiqueta.
Vamos ahora al Editor de bloques.
Primero crea cinco (5) variables numéricas. Llámalas de la siguiente manera: min, max, intentos, premio y azar. A min dale un valor de 1, a max de 10, a intentos 0, a premio 5 y finalmente a azar 1.
Coge el evento .Click de nuestro botón.
Para empezar vamos a asignar a la variable premio el valor del textbox "set global premio=TextBox.Text".
Ya sabemos el número que buscamos. Ahora coge un bloque while desde Built-in/Control.
En el campo test tendremos que poner la expresión lógica que queremos comprobar. En nuestro caso queremos comprobar si el número que buscamos (premio) coincide o no con el número pensado al azar (azar) por nuestro programa.
Crea un bloque Math ≠.
En el primer espacio pondremos la variable "global azar" que es la variable pensada por nuestro programa.
10 En el segundo espacio pondremos la variable "global premio" que es el número que buscamos y escribimos en el textbox.
11 Pégalo al campo test. Quedaría así: "mientras azar y premio no coincidan"...
¿Qué queremos hacer mientras los números no coincidan? Buscar un nuevo número.
12 Coge un bloque "set global azar" dentro de Built-in/Variables y ponlo dentro del bloque while en do.
13 Ahora crea un bloque Math/random integer (numero aleatorio).
14 En el campo from pon la variable min y en el campo to la variable max.
15 Ahora pega este bloque a bloque "set global azar". Así nuestro programa piensa un nuevo número al azar en el rango que hemos dicho y se lo asigna a la variable azar.
16 Como hemos tenido que buscar otro número nuevo, vamos a sumar un intento más. Coge el bloque "set global intentos" ponlo debajo del bloque anterior y pégale un bloque Math +.
17 En el primer espacio pon la variable "global intentos" y en el segundo un bloque numérico con el número 1. De esta manera sumamos un uno más a la variable.
18 Por ultimo actualizamos la etiqueta para que nos vaya mostrando los números que va pensando pero que no coinciden con el que buscamos. Coge el bloque "set label1.Text" y ponlo debajo del anterior bloque.
19 Ahora crea un bloque text/join pero con tres cadenas, ya sabes como hacerlo!
20 En el primer espacio por la variable "label1.Text".
21 En el segundo pon un bloque de texto con una coma ",".
22 Y en el último la variable "global azar".
23 Junta toda la frase al bloque anterior "set label1.Text". Así saldrán todos los número separados por comas.
Con esto tenemos nuestro bucle completo. Vamos a repasarlo.
Cuando pulsamos el botón cogemos el número que ha puesto el usuario en el textbox y con eso sabemos el número que buscamos poniéndolo en la variable premio. Si las variables premio y azar fueran iguales nuestro programa terminaría y nunca llegaría a entrar en el bucle. Si las variables no coinciden lo primero que hacemos es buscar otro número (azar) usando el bloque "random integer" que volvemos a comparar con premio. Así hasta encontrar el número que buscamos.
24 Cuando ambos números coincidan el bucle terminará así que tenemos que actualizar la segunda etiqueta con el número de intentos que nos llevó. Coge el bloque "set label2.Text" y ponlo debajo del bucle.
25 Ahora crea un bloque text/join pero con tres cadenas para componer una frase, ya sabes como hacerlo! A por ello.
26 En el primer espacio pon un bloque de texto con la frase "Encontrado en: ".
27 En el segundo espacio pon la variable "global intentos".
28 En el último pon otro bloque de texto con la frase " intentos.".
29 Junta toda la frase al bloque anterior "set label1.Text".
Así queda nuestro programa. Compáralo con el tuyo.

30 Prueba a cambiar el premio y el rango de número para que veas lo que tarda tu programa en encontrar el número.
Cuanto mayor es el rango, más tardará. Prueba a poner un rango entre 1 y 1000 y verás que tu programa parece que se queda colgado porque le cuesta más encontrarlo.
Otra forma de entender este programa que acabamos de hacer es la siguiente: Imagina un dado de los que se usan en los juegos de mesa. Ahora imagina un número del 1 al 6. ¿Cuántas veces tienes que tirar el dado hasta que salga el número que has pensado? Ahora imagina que el dado tiene 1000 caras y por lo tanto 1000 posibles respuestas. ¿Cúantas veces hay que tirar el dado hasta encontrar el número que has pensado? Esto mismo es lo que hace nuestro programa.
Es muy importante que la condición del bucle se cumpla en algún momento, de lo contrario nuestro programa se quedaría colgado. A esto se le llama bucle infinito. Por ejemplo, supón que buscas el número 100 (premio) pero el rango que has puesto es entre 1 y 10. Lógicamente nuestro programa nunca encontrará el número dentro de ese rango y el bucle se repetirá hasta el infinito. Es importante que cuando uses este tipo de bucles te asegures de que la condición se va a cumplir en un momento u otro. De lo contrario tendrás un problema porque tu programa se quedará atascado. Si esto te ocurre, tendrás que volver a conectar el Editor de bloques con tu dispositivo para que tu programa se reinicie.

TRUCO

Cuando trabajas con variables es muy útil saber el valor que tienen mientras estás ejecutando tu programa. Esto te ayuda a entender qué está pasando en el caso de que tu programa no funcione como crees que debe de funcionar. Si pinchas con el botón derecho del ratón encima de cualquier variable en el Editor de bloques verás que aparece un menú con una opción llamada Watch (observar/mirar) Si la activas verás que aparece una pequeña ventana que te indicará mientras tu programa está funcionando el valor de esa variable. Esto es muy útil si alguna condición lógica no se comporta como esperas. Puedes ver el valor de las variables mientras tu programa está funcionando y así poder entender qué está pasando.

 Una imagen vale más

Una forma de comprender cómo funcionan los bucles es utilizarlos para dibujar. En el siguiente programa vamos a pintar en la pantalla utilizando un bucle y además vamos a aprender a crear nuestros propios colores.
Empieza un proyecto nuevo. Puedes llamarlo "bucle_arcoiris".
En las propiedades del componente screen (pantalla) desactiva la propiedad Scrollable.
3 Ahora coge un componente HorizontalArragement y pon dentro un componente textbox y un botón.
Añade debajo un componente canvas y cambia las propiedades Width y Height a "Fill Parent".
5 Puedes cambiar el texto del botón y poner lo que quieras, p.ej.: "Dibujar".
Cambia el nombre al componente textbox y llámalo numero_repeticiones.
Ajusta también el largo (Height) del componente textbox y del botón, pon, por ejemplo, 35 en ambos casos. Puedes cambiar también el color del fondo del canvas. Ahora vamos al Editor de bloques.
El funcionamiento de nuestro programa es muy sencillo. Le pedimos al usuario el número de repeticiones que quiere hacer y con ese dato, al pulsar el botón, hacemos un bucle dibujando tantas líneas como repeticiones quiera el usuario. Por lo tanto lo primero que hacemos, como siempre, es coger el evento button1.Click
Primero borramos el canvas. Así cada vez que pulsemos el botón empezaremos con un canvas limpio. Coge el bloque canvas1.Clear y ponlo dentro del evento.
Ahora vamos a hacer una comprobación. Si el usuario ha metido un número de repeticiones muy alto vamos a mostrar un mensaje de error. El número máximo de repeticiones que vamos a aceptar es igual al número máximo de pixeles verticales que acepta nuestra pantalla. La razón es que vamos a dibujar líneas horizontales de arriba hacia abajo, por lo tanto el número máximo de repeticiones será igual al número máximo de líneas horizontales que entran en nuestra pantalla, es decir, en número máximo de pixeles verticales del canvas. Este dato lo tenemos en la variable canvas1.Height. (el alto del canvas)
10 Coge un bloque de control if, y conviértelo en ifelse, ya sabes como! PISTA: Pulsa el botón azul del bloque. Ponlo debajo del canvas1.Clear.
11 La expresión lógica que queremos comprobar (test) será: "¿Es el número de repeticiones mayor que el tamaño vertical del canvas?". Para hacerlo coge un bloque Math > y en el primer espacio ponemos el número que nos pide el usuario. Como siempre este datos está en numero_repeticiones.Text.
12 E n el segundo espacio pondremos el bloque "Canvas1.Height" y pegamos el bloque completo en el espacio test del bloque de control.
13 Si la respuesta es verdadera (el número es mayor) vamos a mostrar un mensaje. Coge el bloque Canvas1.DrawText y pégale un bloque de texto diciendo :"Demasiadas repeticiones!"
14 Cambia las coordenadas x e y por 1 y 15 respectivamente.
15 Si la respuesta es negativa (el número de repeticiones es menor) entonces vamos a dibujar. 
16 De momento cogemos un bloque de control for each number.
17 El campo variable nos lo proporciona AppInventor (number). Sabemos que queremos hacer un bucle empezando por 1 y terminando por el número de repeticiones que nos pide el usuario así que cogemos el bloque numero_repeticiones.Text y lo pegamos en el espacio to.
18 No queremos saltos (by) así que dejamos este campo en 1. Ya tenemos nuestro bucle montado.
19 Ahora vamos a dibujar la líneas. Para dibujar una línea tenemos el bloque canvas1.DrawLine. (dibujar línea) Cógelo y ponlo dentro del bucle.
Este bloque nos pide las coordenadas de inicio y final de la línea. ¿Recuerdas cómo funcionan las coordenadas?. En la esquina superior izquierda tendríamos la coordenada 0,0 que irían aumentando hasta llegar a la esquina inferior derecha donde las coordenadas serían igual al tamaño de tu pantalla. Imagina una línea diagonal que empieza arriba a la izquierda y que apunta a la esquina inferior derecha. Este bloque DrawLine nos pide las coordenadas de inicio de la línea (x1,y1) y las coordenadas de final (x2,y2)
Las líneas que queremos dibujar son líneas horizontales de izquierda a derecha, es decir, la coordenada x1 siempre será 0 (empezando a la izquierda) y la coordenada x2 siempre será el final de la pantalla (canvas.Width). Son líneas que van a recorrer la pantalla completamente de izquierda a derecha, por eso empiezan en el margen izquierdo (x1=0) y terminan en el margen derecho (x2=canvas.Width). No olvides que usamos el valor de canvas.Width porque nunca sabremos exactamente el tamaño de la pantalla de nuestros usuarios, pero este dato siempre lo tendremos ahí. Además si el usuario cambia la orientación de la pantalla, este dato también se actualiza con lo que no tienes que preocuparte.
Lo que queremos que cambie dentro de nuestro bucle son las coordenadas y1 e y2. La razón es que queremos que por cada repetición se dibuje una nueva línea pero un poco más abajo que la anterior. Iremos dibujando líneas horizontales cada vez un poco más abajo. En concreto, un pixel más abajo.
20 Recuerda que nuestro bucle empieza en 1 y termina en el número de repeticiones que nos pide el usuario, así que podemos usar la variable number de nuestro bucle como coordenada y1 e y2.
21 Completa el bloque DrawLine de la siguiente manera. x1=0 y1="numberi" x2="canvas.Width" y2="number"
22 Prueba tu programa.
¿Ves lo que está ocurriendo? Cada vez que hacemos una repetición el valor de la variable i de nuestro bucle se incrementa en 1 hasta llegar al valor máximo de numero_repeticiones. Por cada repetición las coordenadas y1 e y2 de nuestra línea aumentan en 1 mientras que las coordenadas x1 e x2 no varían. De esta forma vamos pintando tantas líneas horizontales como repeticiones queremos. Vamos ahora con los colores.
Ya has visto que AppInventor tiene unos bloques definidos para los colores. Ahora vamos a aprender a crear colores nuevos.
23 Cuando pintamos sobre el canvas, AppInventor utiliza el color que tengamos activo en ese momento. Para cambiar el color utilizamos el bloque Canvas.PaintColor. Cógelo y ponlo dentro de tu bucle. Normalmente puedes pegar a este bloque un bloque de color directamente pero en esta ocasión vamos a hacerlo de otra manera. Dentro de la categoría Colors verás un bloque llamado make color. Este bloque nos permite definir nuestros propios colores a partir del estándar RGB. Esta forma de representar el color se basa en la mezcla de los colores primarios Red (rojo), Green (verde), Blue (azul) por eso se llama RGB. De esta forma podemos controlar la cantidad de cada color que queremos hasta encontrar el color que buscamos. Cada cantidad de color se representa con un valor en AppInventor que va desde 1 hasta 255. Vamos a ver cómo usarlo.
24 Coge el bloque make color y pégalo al bloque .PaintColor anterior.
25 Ahora en los bloques numéricos para definir el color que queremos pon los siguientes valores: 100, 150 y 200.
26 Vamos a hacerlo más interesante haciendo que los colores sean aleatorios. Crea un bloque "random integer" y en from pon un bloque numérico con el valor 1 y para el espacio to pon un bloque numérico con el valor 255.

27 Ahora necesitamos dos bloques "random integer" más, así que duplica este último bloque que hemos creado dos veces más.
28 Ahora vuelve al bloque "call make a list" anterior y quita los tres número que usamos antes (100,150 y 200) y cámbialos por los bloques "random integer" que acabamos de crear. De esta forma le estamos diciendo a AppInventor que cree un color a partir de valores aleatorios de rojo, verde y azul; lo que producirá colores distintos cada vez.
29 ¿Funciona?
30 Sólo nos quedaría un asunto por solucionar. ¿Qué pasa si el usuario introduce una letra o texto en lugar de un número en el textbox? Pruébalo. ¿Cómo lo podemos solucionar?
31 Podemos coger otro bloque de control ifelse y ponerlo entre el primer bloque Canvas.Clear y el bloque ifelse anterior.
32 La expresión lógica que tendríamos que comprobar es: "¿Es numero_repeticiones un número?
33 Coge el bloque Math /is a number? (¿es un número?) y pégalo en el espacio test de nuestro nuevo bloque de control ifelse.
34 Coge la variable "numero_repeticiones.Text" y pégalo en el espacio thing. Ya tenemos la condición montada. ¿Es un número? Si es así se activará el espacio then-do por lo tanto podemos coger todos nuestro bloques anteriores y meterlos aquí.
35 Si no es un número entonces vamos a mostrar un mensaje de error. Duplica el bloque que usamos antes Canvas.DrawText y ponlo en el espacio else-do.
36 Cambia el texto y pon "Sólo números !" 
El programa final quedará así: