Vamos a ver cómo podemos crear bucles, es decir, partes del programa que se repitan un cierto número de veces.
Según cómo queramos que se controle ese bucle, tenemos tres posibilidades, que vamos a comentar en primer lugar:
La diferencia entre
estos dos últimos es que "while"
comprueba la condición antes de repetir las demás
sentencias, por
lo que puede que estas sentencias ni siquiera se lleguen a ejecutar, si
la condición de entrada es falsa. En "repeat", la
condición
se comprueba al final, de modo que las sentencias intermedias se
ejecutarán
al menos una vez.
Vamos a verlos con más detalle...
El formato de "for" es
for variable := ValorInicial to ValorFinal
do
Sentencia;
Se podría traducir por algo como "desde que la variable valga ValorInicial hasta que valga ValorFinal" (y en cada pasada, su valor aumentará en una unidad).
Como
primer ejemplo, vamos a ver un pequeño programa
que escriba los
números del uno al diez:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Primer ejemplo de }
{ "for": contador }
{ FOR1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{--------------------------}
Program For1;
var
contador: integer;
begin
for contador := 1 to 10 do
writeln( contador );
end.
Ejercicio propuesto: Crea un programa que muestre los números del 10 al 15, cada uno en una línea.
Ejercicio propuesto: Crea un programa que muestre los números del 5 al 20, todos ellos en la misma línea, separados por espacios en blanco.
Ejercicio propuesto: Crea un programa que escriba 10 veces "Hola" (en la misma línea).
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Segundo ejemplo de }
{ "for": bucles enlaza- }
{ dos -> tabla de }
{ multiplicar }
{ FOR2.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{--------------------------}
Program For2;
var
tabla, numero: integer;
begin
for tabla := 1 to 5 do
for numero := 1 to 10 do
writeln( tabla, ' por ', numero ,' es ', tabla * numero );
end.
Ejercicio propuesto: Crea un programa que escriba tres veces seguidas los números del 1 al 3.
Ejercicio propuesto: Crea un programa que escriba 3 líneas, cada una de las cuales contendrá 4 veces la palabra "Hola".
Así, vamos a mejorar el ejemplo anterior haciendo
que deje una
línea en blanco entre tabla y tabla:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Tercer ejemplo de }
{ "for": bucles con }
{ sentencias compuestas }
{ FOR3.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{--------------------------}
Program For3;
var
tabla, numero: integer;
begin
for tabla := 1 to 5 do
begin
for numero := 1 to 10 do
writeln( tabla, ' por ', numero ,' es ', tabla * numero );
writeln; (* Línea en blanco *)
end;
end.
Recordad, como vimos, que es muy conveniente usar laescritura indentada,
que en este caso ayuda a ver dónde empieza y termina lo que hace
cada "for"... espero O:-)
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Cuarto ejemplo de }
{ "for": letras como }
{ índices en un bucle }
{ FOR4.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{--------------------------}
Program For4;
var
letra: char;
begin
for letra := 'a' to 'z' do
write( letra );
end.
Como último comentario: con el bucle "for", tal y como lo hemos visto, sólo se puede contar en forma creciente y de uno en uno. Para contar de forma decreciente, se usa "downto" en vez de "to".
Ejercicio propuesto: Crea un programa que escriba las letras de la B a la M.
Ejercicio propuesto: Crea un programa que escriba las letras de la Z a la A (de forma descendente).
Ejercicio propuesto: Crea un programa que escriba los números del 10 al 1 (de forma descendente).
Para contar de dos en dos (por ejemplo), hay que buscarse la vida: multiplicar por dos o sumar uno dentro del cuerpo del bucle, etc... Eso sí, sin modificar la variable que controla el bucle (usar cosas como "write(x*2)" en vez de "x := x*2", que pueden dar problemas en algunos compiladores).
Pero todo eso os dejo que lo investigueis con los ejercicios... }:-)
Ejercicio propuesto: Un programa que escriba la secuencia de números 2, 4, 6, 8 ... 16.
Ejercicio propuesto: Un programa que escriba la secuencia de números 6, 5, 4,..., 1.
Ejercicio propuesto: Un programa que escriba la secuencia de números 3, 5, 7,..., 21.
Ejercicio propuesto: Un programa que escriba la secuencia de números 12, 10, 8,..., 0..
Ejercicio propuesto: Crea un programa que sume dos vectores, cuyos componentes indicará el usuario. Por ejemplo, la suma de (1,2,3) y (7,11,-1) sería (8,13,2).
Ejercicio propuesto: Crea un programa que halle el producto escalar dos vectores, cuyos componentes indicará el usuario.
Ejercicio propuesto: Crea un programa que multiplique dos matrices.
Ejercicio propuesto: Para los más osados (y que conozcan el problema), un programa de resolución de sistemas de ecuaciones por Gauss.
Vimos como podíamos crear estructuras repetitivas con la orden "for", y comentamos que se podía hacer también con "while..do", comprobando una condición al principio, o con "repeat..until", comprobando la condición al final de cada repetición. Vamos a ver estas dos con más detalle:
La sintaxis de "while" es
while
condición do
sentencia;
Que se podría traducir como "MIENTRAS se cumpla la condición HAZ sentencia".
Un ejemplo que nos diga la longitud de todas las frases que queramos es:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de "While": }
{ muestra la longitud }
{ del texto tecleado }
{ WHILE1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{--------------------------}
Program While1;
var
frase: string;
begin
writeln('Escribe frases, y deja una línea en blanco para salir');
write( '¿Primera frase?' );
readln( frase );
while frase <> '' do
begin
writeln( 'Su longitud es ', length(frase) );
{ SURPAS 1.00 no reconoce "length" }
write( '¿Siguiente frase?' );
readln( frase )
end
end.
En el ejemplo anterior, sólo se entra al bloque begin-end (una sentencia compuesta) si la primera palabra es correcta (no es una línea en blanco). Entonces escribe su longitud, pide la siguiente frase y vuelve a comprobar que es correcta.
Como comentario casi innecesario, length es una función que nos dice cuantos caracteres componen una cadena de texto.
Si ya de principio la condición es falsa, entonces la sentencia no se ejecuta ninguna vez, como pasa en este ejemplo:
while (2<1) do
writeln('Dos es menor que uno');
Ejercicio propuesto: Crea un programa vaya sumando los números que el usuario introduzca, y mostrando dicha suma, hasta que introduzca el número 0, usando "while".
Ejercicio propuesto: Crea un programa que pida al usuario su contraseña. Deberá terminar cuando introduzca como contraseña la palabra "acceso", pero volvérsela a pedir tantas veces como sea necesario.
Ejercicio propuesto: Crea un programa que escriba en pantalla los números del 1 al 10, usando "while".
Para "repeat..until", la sintaxis es
repeat
sentencia;
...
sentencia;
sentencia
until condición;
Es decir, REPITE un grupo de sentencias HASTA que la condición sea cierta. Ojo con eso: es un grupo de sentencias, no sólo una, como ocurría en "while", de modo que ahora no necesitaremos "begin" y "end" para crear sentencias compuestas.
El conjunto de sentencias se ejecutará al menos una vez, porque la comprobación se realiza al final.
Como último detalle, de menor importancia, no hace falta terminar con punto y coma la sentencia que va justo antes de "until", al igual que ocurre con "end".
Un ejemplo clásico es la "clave de acceso" de un programa, que iremos mejorando cuando veamos distintas formas de "esconder" lo que se teclea, bien cambiando colores o bien escribiendo otras letras, como * (empleando métodos que veremos en el tema 10, y lo aplicaremos a un "juego del ahorcado").
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de "Repeat": }
{ comprobación de una }
{ clave de acceso }
{ REPEAT.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{--------------------------}
program ClaveDeAcceso;
var
ClaveCorrecta, Intento: String[30];
begin
ClaveCorrecta := 'PaskalForever';
repeat
WriteLn( 'Introduce la clave de acceso...' );
ReadLn( Intento )
until Intento = ClaveCorrecta
(* Aquí iría el resto del programa *)
end.
Se entiende, ¿verdad?
Ejercicio propuesto: Crea un programa que pida números positivos al usuario, y vaya calculando la suma de todos ellos (terminará cuando se teclea un número negativo o cero), usando "repeat".
Ejercicio propuesto: Crea un programa que escriba en pantalla los números pares del 26 al 10 (descendiendo), usando "repeat".
Ejercicio propuesto: Crea un programa que pida al usuario su nombre de usuario y su contraseña, y no le permita seguir hasta que introduzca como nombre "yo" y como contraseña "acceso", usando "repeat"
Es bastante por hoy. Ahora os toca experimentar a vosotros.
Ejercicio propuesto: Mejorar el programa de la clave de acceso con "while" (6.5b), para que avise de que la clave no es correcta..
Ejercicio propuesto: Mejorar el programa de la clave de acceso con "repeat" (6.6c), para que avise de que la clave no es correcta..
Ejercicio propuesto: Mejorar más todavía el programa de la clave de acceso con "while", para que sólo haya tres intentos.
Ejercicio propuesto: Mejorar más todavía el programa de la clave de acceso con "while", para que sólo haya tres intentos.
Por cierto, si alguien viene de Basic puede que se pregunte "¿Y
mi goto? ¿No existe en Pascal?" Pues sí,
existe, pero no contaremos nada sobre él por ahora, porque va en
contra de todos los principios de la Programación Estructurada,
su uso sólo es razonable en casos muy concretos que todavía no necesitamos.
Ya se verá más adelante la forma de usarlo.
Allá va...
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de "Repeat": }
{ adivinar un número }
{ ADIVINA.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program adivina;
var
correcto, { Número que se debe acertar }
probado, { El número que se prueba }
maxIntentos, { Máximo de intentos permitido }
intentoAct: integer; { El número de intento actual }
i: byte; { Para bucles }
begin
{ Primero pedimos los datos iniciales }
write('Usuario 1: Introduzca el número a adivinar. ');
readln(correcto);
write('¿Cuantos intentos va a permitir? ');
readln(maxIntentos);
{ Borramos la pantalla de forma "fea" pero que sirve }
for i:= 1 to 25 do writeln;
intentoAct := 0; { Aún no ha probado }
{ Comienza la parte repetitiva }
repeat
writeln;
write('Usuario 2: Introduzca un número. ');
readln(probado); { Pedimos un número }
if probado > correcto then { Puede ser mayor }
writeln('Se ha pasado!')
else if probado < correcto then { Menor }
writeln('Se ha quedado corto!')
else writeln('Acertó!'); { O el correcto }
intentoAct := intentoAct + 1; { Ha gastado un intento más }
writeln('Ha gastado ', intentoAct,
' intentos de ', { Le recordamos cómo va }
maxIntentos,' totales.');
until (intentoAct >= maxIntentos) { Seguimos hasta que gaste todos }
or (probado = correcto); { o acierte }
if (intentoAct >= maxIntentos) and (probado <> correcto) then
writeln('Lo siento, ha agotado sus intentos.');
end.
(Más adelante podrás encontrar un ejemplo más desarrollado:
el juego del ahorcado, como parte del tema 10).Los arrays se pueden crear y recorrer con mucha facilidad usando estructuras repetitivas, como "for". Por ejemplo, podríamos pedir al usuario 5 números y mostrarlos al revés de la siguiente forma:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de uso de }
{ arrays (01): }
{ Pedir datos y mostrar }
{ al revés }
{ ARRAY01.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.4.2w }
{--------------------------}
Program Array01;
var
datos: array[1..5] of integer;
i: integer;
begin
for i := 1 to 5 do
begin
write('Deme el dato ',i,': ');
readln(datos[i]);
end;
write('Los datos al reves son: ');
for i := 5 downto 1 do
write(datos[i], ' ');
writeLn;
end.
Ejercicio propuesto: Crea un programa que pida al usuario cuatro nombres y luego muestre todos ellos en la misma línea.
Es muy habitual que no sepamos cuántos datos querremos guardar. En ese caso, podemos crear un array "sobredimensionado" (más grande de lo que esperamos necesitar), y llevar un contador en qué posición tenemos que guardar el siguiente dato, y hasta qué posición debemos recorrer. La única precaución adicional es asegurarnos de que no "nos salimos" del array:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de uso de }
{ arrays (02): }
{ Pedir datos y mostrar }
{ al revés, en un array }
{ parcialmente lleno, }
{ usando un contador }
{ ARRAY02.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.4.2w }
{--------------------------}
Program Array02;
const
capacidad = 200;
var
datos: array[1..capacidad] of integer;
cantidad: integer; { Los datos existentes }
i: integer; { Para bucles }
begin
cantidad := 0;
repeat
if cantidad >= capacidad then
writeLn('No caben mas datos!')
else
begin
cantidad := cantidad+1;
write('Deme el dato ',cantidad,' (999 para salir): ');
readln(datos[cantidad]);
end;
until datos[cantidad]=999;
{ El ultimo dato no hay que guardarlo }
cantidad := cantidad-1;
{ Al final, muestro todos }
write('Cantidad de datos: ', cantidad);
write('Los datos al reves son: ');
for i := cantidad downto 1 do
write(datos[i], ' ');
writeLn;
end.
Ejercicio propuesto: Crea un programa que pida al usuario varios nombres, hasta que introduzca "fin" y luego diga si alguno de ellos es "Nacho".
Una alternativa es tener un "centinela" que indique cual es la primera ficha no válida. Por ejemplo, si las fichas almacenan números del 1 al 10, en la primera ficha vacía podríamos guardar el número -1, o el 999, o cualquier otro no válido, y para hacer las búsquedas y lecturas usarías un "while" en vez de un "for":
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de uso de }
{ arrays (03): }
{ Pedir datos y mostrar }
{ al revés, en un array }
{ parcialmente lleno, }
{ usando un centinela }
{ ARRAY03.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.4.2w }
{--------------------------}
Program Array03;
const
capacidad = 200;
var
datos: array[1..capacidad] of integer;
cantidad: integer; { Los datos existentes }
i: integer; { Para bucles }
begin
cantidad := 0;
repeat
if cantidad >= capacidad then
writeLn('No caben mas datos!')
else
begin
cantidad := cantidad+1;
write('Deme el dato ',cantidad,' (999 para salir): ');
readln(datos[cantidad]);
end;
until datos[cantidad]=999;
{ Al final, muestro todos }
write('Los datos leidos son: ');
i := 1;
while datos[i] <> 999 do
begin
write(datos[i], ' ');
inc(i);
end;
writeLn;
end.
Suele ser más eficiente usar un contador. Generalmente, sólo tiene sentido usar centinelas cuando la situación es un poco más complicada. Por ejemplo, si las fichas borradas no se eliminan realmente, sino que se marcan como disponibles. En ese caso, podríamos usar dos centinelas: la marca de final de datos (por ejemplo, 999) y la marca de ficha borrada (por ejemplo, 998), que se comprobaría con un "if" para no escribirla en pantalla cuando se muestran todos lo datos.
Ejercicio propuesto: Crea un programa que pida al usuario varios nombres, luego le pregunte tres que quiera borrar (para lo que usará "centinelas") y luego muestre todos los nombres que no se han borrado.
En el tema 7 tienes un ejemplo más detallado, que usa un "array de records" para crear una agenda.