PEŁNY KURS TURBO PASCALA - część VII
pętle REPEAT..UNTIL oraz WHILE..DO
Nareszcie doszliśmy do tzw. pętli. Pętle są tak częste w programach, że nie sposób bez nich żyć. Jest ich kilka rodzajów. W tej części poznacie dwa z nich, bardzo zresztą podobne do siebie. Może zacznijmy od definicji, czym jest pętla w programie. Otóż przydaje się, gdy chcemy jakąś czynność (polecenie) wykonać określoną ilość razy. Nie będziemy oczywiście stosować metody „kopiuj / wklej” i tak np. 50 razy, gdyż jest to nieładne i czasochłonne i w ogóle tak się nie robi. Do tego są właśnie pętle. Zapętlają określony fragment kodu programu i rozkazują go wykonywać dopóki jakiś warunek zostanie spełniony. Pierwszy rodzaj pętli składa się z dwóch słów: „REPEAT” (powtarzaj) oraz „UNTIL” (dopóki). Zaraz powinno wam się wszystko w głowach rozjaśnić.
Załóżmy, że chcemy, aby program napisał coś takiego: „Witam cię po raz 1, witam cię po raz 2, witam cię po raz 3, witam cię po raz 4 … i tak dalej, aż do załóżmy 100. Nie będziemy przecież pisać 100 razy tej samej kwestii metodą kopiuj/wklej. Do tego użyjemy pętli. Wprowadźmy najpierw samą pętle, a potem wyjaśnijmy.
USES CRT;
BEGIN
clrscr;
REPEAT
(tu będą polecenia)
UNTIL (warunek)
readln;
END.
Wszystko, co będzie między znacznikami „REPEAT” i „UNTIL” będzie się w kółko powtarzało, aż warunek będzie spełniony. My chcemy, aby program wypisał 100 razy ten sam tekst z ciągle zwiększającą się liczbą o jeden. Zatem do dzieła:
USES CRT;
VAR
licznik:longint;
BEGIN
clrscr;
licznik:=0;
REPEAT
licznik:=licznik+1;
writeln('Witam cię po raz ',licznik);
UNTIL licznik=100
readln;
END.
A teraz wyjaśnienie. Na początku zdeklarowaliśmy zmienną o nazwie „licznik”. Zaraz po „BEGIN” czyścimy ładnie ekran i zerujemy licznik (przypisujemy wartość 0). Zaczynamy pętle. Od tego momentu, zatem, wszystko będzie powtarzane. Licznik przyjmuje wartość „licznik+1”. Licznik miał wartość 0, zatem 0+1 jest jeden. Licznik, więc ma wartość 1. Program rozkazuje napisać tekst i wstawić wartość licznika. Pętla się kończy. Program sprawdza, czy warunek jest spełniony. Aby pętla się zakończyła, wartość licznika musi wynosić 100. Nasz licznik aktualnie ma wartość 1. Zatem warunek nie został spełniony - program wraca do słowa „REPEAT”. I znowu - licznik zwiększa swoją wartość o 1, czyli ma już 2. Rozkazuje napisać tekst i wstawić licznik. Sprawdza warunek -warunek nie jest spełniony - i znowu „REPEAT” Licznik podnosi swoją wartość do 3 i tak dalej. Pętla się zakończy, aż wartość licznika będzie równa 100. Gdy pętla się zakończy, program wykonuje dalsze instrukcje (w tym wypadku jest to „READLN”). I tak oto wyjaśniłem wam działanie pętli.
Jednakże jeden program to trochę mało, aby was czegoś nauczyć. Zróbmy teraz inny. Zróbmy program, który będzie kazał napisać użytkownikowi hasło. Hasło będzie cyfrowe, załóżmy, że liczba 123. Użytkownik nie będzie mógł wyjść z programu, aż napisze poprawne hasło. No to do dzieła:
USES CRT;
VAR
haslo:longint;
BEGIN
REPEAT
clrscr;
writeln('Podaj hasło!');
read(haslo);
UNTIL haslo=123;
writeln('BRAWO! Odgadłeś hasło!');
readln;
END.
Jak widzimy, pętla ta nie zakończy się, gdy ktoś poda nieprawidłowe hasło. I tak za każdym razem. Napis „Brawo…” wyświetli się tylko wtedy, gdy ktoś poda prawidłowe hasło.
Spróbujmy teraz zrobić program z innej parafii. Naszym celem jest napisanie prostego alarmu. Program ma wytwarzać dźwięk podobny do alarmu. Dodatkowo, tak napiszemy ten program, aby alarm zapiał 10 razy. Do dzieła:
USES CRT;
VAR
ilosc,ton:longint;
BEGIN
ilosc:=0;
ton:=0;
REPEAT
ton:=ton+1;
IF ton=1000 THEN
BEGIN
ton:=1;
ilosc:=ilosc+1;
END;
Sound(ton);
Delay(1);
UNTIL ilosc=10;
Nosound;
END.
Jak widzicie zdeklarowałem dwie zmienne: „ilosc” i „ton”. Zmienna „ilosc” będzie nam mówiła ile razy alarm już zatrąbił. Zmienna „ton” decydować będzie to częstotliwości dźwięku. Najpierw zeruje oba zmienne. Później zaczynam pętle. Zmiennej „ton” zwiększam wartość (tak jak w poprzednich programach z pętlą). Program sprawdza, czy ta wartość równa jest sto. Na razie nie jest równa, więc program opuszcza instrukcję warunkową. Następnie przez 1/1000 sekundy wydobywa się dźwięk o częstotliwości ”ton”, czyli aktualnie 1. Pętla się zamyka. Następuje ponowne uruchomienie pętli, ponieważ wartość zmiennej „ilosc” nie jest równa 10. Kolejne zadania w pętli odgrywają dźwięk o coraz to wyższej częstotliwości. Daje to wrażenie alarmu. W pewnym momencie, zmienna „ton” jest już równa 1000, więc w pętli dokonuje się wstawiona tam instrukcja warunkowa. A w niej: „ton” przyjmuje wartość 1 oraz „ilosc” zwiększa swoją wartość o 1. Instrukcja warunkowa kończy się, a program odgrywa dźwięk o częstotliwości „ton”, czyli znowu 1. I znowu wszystko zaczyna się, z tym, że wartość zmiennej „ilosc” jest większa. Cały proces trwa do momentu, aż zmienna „ilosc” przyjmie wartość 10. Program wtedy ucichnie dzięki poleceniu „NoSound”. Skomplikowane, nieprawdaż? W praktyce usłyszysz 10 razy szybki wzrost częstotliwości. Da to efekt alarmu, zresztą - sam się przekonaj.
To teraz zajmijmy się poleceniem „WHILE..DO”, które jest drugą pętlą omawianą na tej lekcji. Nie różni się zbytnio od poprzedniej, natomiast jest nieco rzadziej używana. W poprzedniej pętli, zawsze to, co było ujęte w nią - wykonało się, co najmniej raz. Musi tak być, ponieważ warunek na zakończenie pętli był na jej końcu. Program działał w sposób, że najpierw wykonał pętle, a potem dopiero sprawdził, czy to jej koniec. Pętla „WHILE..DO”, najpierw sprawdza warunek, a potem dopiero, (jeżeli jest on spełniony) się wykonuje. Dlatego właśnie w tej pętli zaistnieć może sytuacja, że pętla w ogóle się nie włączy, gdy warunek nie będzie spełniony. Poza tym, program działa tak: dopóki warunek jest spełniony, wykonuj…, a nie jak poprzednio: wykonuj… aż warunek zostanie spełniony. Po słowie „WHILE” zawsze jest warunek. Potem następuje słowo „DO” i wpisujemy polecenia pętli. Po słowie „DO”, musimy zastosować „BEGIN”. Zatem wszystkie polecenia pętli muszą być ujęte w oddzielny blok. Wszystko zaraz się wyjaśni na konkretnym przykładzie (mam nadzieję).
Załóżmy, że chcemy zrobić prosty program, który pyta użytkownika o jakąś liczbę. Jeżeli ta liczba jest równa 10 lub 20, program wykonuje pętle. Jeżeli nie - program się wyłącza. Pętla polega na 10 krotnym wypisaniu słowa „Podałeś liczbę 10 lub 20”. Program głupi jest i nieprzydatny, ale jak do ćwiczeń, to dobry. Starymi sposobami, program ten można zrobić tak:
USES CRT;
VAR
liczba,licznik:longint;
BEGIN
clrscr;
writeln('Podaj jakąś liczbę');
read(liczba);
IF (liczba=10) OR (liczba=20) THEN
BEGIN
licznik:=0;
REPEAT
licznik:=licznik+1;
writeln('Podałeś liczbę 10 lub 20');
UNTIL licznik=10;
writeln;
END;
Halt;
END.
Jak widzimy program ma dwie zmienne: „liczba” i „licznik”. Użytkownik wprowadza liczbę. Jeżeli nie jest równa 10 lub 20, program opuszcza instrukcję warunkową, a zarazem pętle i dochodzi do polecenia „Halt”. Jeżeli liczba równa jest 10 lub 20, program wykonuje instrukcję warunkową - wypisuje 10 razy napis. A teraz powyższy program przekształćmy, tak aby można było użyć w nim pętli „WHILE..DO”. Będzie on wyglądał tak:
USES CRT;
VAR
liczba,licznik:longint;
BEGIN
clrscr;
writeln('Podaj jakąś liczbę');
read(liczba);
IF (liczba=10) OR (liczba=20) THEN
BEGIN
licznik:=0;
WHILE licznik<11 DO
BEGIN
licznik:=licznik+1;
writeln('Podałeś liczbę 10 lub 20');
END;
writeln;
END;
Halt;
END.
Pętla sprawdza warunek, czy licznik<11. Jeżeli tak, pętla się wykonuje. Wykonuje się tak długo, aż licznik nie będzie mniejszy od 11 (czyli, aż osiągnie wartość 11). Z tego wynika, że napis wyświetli się 10 razy. Jak widzimy, łatwiej jest operować pętlą „REPEAT” niż omawianą. Ale jak to mówią: „róbta co chceta”. Pamiętajcie, że w pętli „WHILE..DO” nie ma słowa „UNTIL”.
Do omówienia zostało jeszcze zagnieżdżanie pętli. Czy wiesz, że w pętle można wpisać jeszcze jedną pętle, a w nią następną i następną… i tak dalej. My nie będziemy zapętlali miliony razy, ale zrobimy bardzo fajny program, który nazywać się będzie „tabliczka mnożenia”. Jego zadaniem będzie wypisanie mnożeń, tzn. 1*1=1, 1*2=2, 1*3=3… aż dojdzie do 10*10=100. Wszystkie działania będą linijka pod linijką. Gdybyśmy chcieli to zrobić ręcznie, musielibyśmy zająć co najmniej 100 linijek tekstu (jedną na każde działanie), np:
writeln('4*3=12');
writeln('4*4=16');
writeln('4*5=20');
writeln('4*6=24');
writeln('4*7=28');
writeln('4*8=32');
writeln('4*9=36');
writeln('4*10=40');
writeln('5*1=5');
writeln('5*2=10');
writeln('5*3=15');
writeln('5*4=20');
i tak dalej...
Do tego celu zagnieździmy pętle. Tzn. wpiszemy drugą pętle „REPEAT” do już istniejącej. Najpierw zobaczcie na program, a potem sobie wyjaśnimy:
USES CRT;
VAR
a,b:longint;
BEGIN
clrscr;
writeln(' A oto tabliczka mnożenia:');
a:=0;
REPEAT
a:=a+1;
b:=0;
REPEAT
b:=b+1;
writeln(a,'*',b,'=',a*b);
delay(100);
UNTIL b=10;
UNTIL a=10;
END.
To teraz wyjaśnienie. Deklarujemy dwie zmienne: „a” i „b”. Zmienna „a” będzie pierwszą liczbą, którą będziemy mnożyć, zmienna „b” natomiast - drugą. (a*b). Po napisie, zerujemy zmienną „a”. Rozpoczynamy pętle ZEWNĘTRZNĄ. „a” zwiększa wartość o 1. Zerujemy „b”. Zaczynamy pętle „WEWNĘTRZNĄ”. „b” zwiększa wartość o 1. Program pisze: a*b=wynik. Zarówno „a” jak i „b” wynoszą 1, więc jest „1*1=1”. Napis trwa 1/10 sekundy. Wartość „b” nie jest równa 10, więc pętla zaczyna się jeszcze raz. Znowu „b” zwiększa wartość, ale „a” pozostaje takie samo. Jest zatem 1*2=2. Jak zauważyliśmy, wszystko idzie dobrze. Tabliczka mnożenia idzie przez 1 do momentu, aż „b” wyniesie 10 (1*10=10). Pętla wewnętrzna się kończy. Pamiętamy jednak, że cały czas jesteśmy w pętli zewnętrznej. Pętla zewnętrzna kończy się dopiero, kiedy „a” jest równe 10. W tej chwili „a” jest równe 1, więc pętla zewnętrzna zaczyna się od początku. Wartość „b” się zeruje i zaczyna się pętla wewnętrzna. Teraz wszystko mnoży się przez „2”. Zatem, w jednym poleceniu pętli zewnętrznej wykonuje się 10 razy pętla wewnętrzna. Pętla zewnętrzna wykonuje się 10 razy. Zatem końcowy napis będzie „10*10=100”. Tak oto stworzyliśmy tabliczkę mnożenia dzięki podwójnej pętli (zagnieżdżeniu). Polecenie „Delay” służy tylko temu, abyśmy zdążyli tę tabliczkę zobaczyć, bo bez niego program ją wypisze w mgnieniu oka.
I to tyle, jeśli chodzi o te dwie pętle. Nie zaglądaj nawet do następnej lekcji, dopóki nie zrozumiesz tej - a zwłaszcza ostatniego programu z tabliczką mnożenia. Pamiętaj, że pętle są wykorzystywane w 90% programów, więc bez nich ani rusz.
Zadanie domowe: Napisz program, który pyta użytkownika o jakąś liczbę. Po wprowadzeniu liczby przez użytkownika, program ma pomnożyć ją przez wszystkie liczby od 1 do 2000 i pokazać wyniki (linijka pod linijką).
6