Adam Majczak: PASCAL

ROZDZIAŁ PRZYKŁADOWY

Wstęp do wydania elektronicznego

Język Pascal jest wygodnym narzędziem do szybkiej budowy aplikacji dla Windows 7/8 (Delphi) i dla Linuxa (Kylix), dlatego warto go poznać.

Nauka Pascala online może być najwygodniejszym wyjściem z sytuacji.

Tablice dwu- i wielo-wymiarowe

Jako przykład tablicy dwuwymiarowej zastosujmy znaną Ci niemal „od urodzenia” tabliczkę mnożenia. W ludzkim języku sprecyzowalibyśmy to tak:

TabliczkaMnożenia to Tabela o wymiarach 10 x 10 złożona z liczb całkowitych;

W Pascalu zapiszemy to samo tak:

TabM : Array[1..10, 1..10] : Integer;

Aby nie zaprzątać sobie głowy szczegółami i skrócić czas „wklepywania” programu - możemy zawartość tablicy wygenerować automatycznie. Pascal obliczy 100 wyników szybko i bez zmęczenia. Ponieważ jednak musimy numerować elementy tablicy w dwóch wymiarach (najłatwiej wyobrazić to sobie jako kolumny i wiersze tabelki) - będziemy potrzebować dwóch indeksów - i, j. Wartość poszczególnych elementów tabelki można bardzo łatwo wyznaczyć w oparciu o prosty wzór:

TabM[1][1] = 1 * 1 = 1,

TabM[2][2] = 2 * 2 = 4,

TabM[3][5] = 3 * 5 = 15, itd., itp. ...

uogólniając:

TabM[ i ] [ j ] := i * j;

Pozostaje nam. już tylko napisać podwójnie zagnieżdżoną pętlę - i tablica zostanie automatycznie wypełniona danymi. Najprostszy wariant programu może wyglądać tak:

* Tablica dwuwymiarowa

uses Crt;

var I, J : Integer;

TabM : Array[1..10, 1..10] Of Integer;

BEGIN

ClrScr;

For I:=1 To 10 Do

For J:=1 To 10 Do

TabM[I][J] := I * J;

WriteLn('Tablica GOTOWA!, Drukuje...');

For I:=1 To 10 Do

For J:=1 To 10 Do

Write(' ', TabM[I][J]);

ReadKey;

END.

Wszystko działa poprawnie, ale wydruk jest nieelegancki. Aby dokonać prostego „sformatowania wyjścia” powinniśmy po „doliczeniu do 10” przenieść dane do nowego wiersza. Prócz tego po wynikach jednocyfrowych dodamy trzy spacje a po wynikach dwucyfrowych - 2 spacje. Oto wersja programu bardziej dopracowana.

* Tablica dwuwymiarowa, formatowana

uses Crt;

var I, J : Integer;

TabM : Array[1..10, 1..10] Of Integer;

BEGIN

ClrScr;

For I:=1 To 10 Do

For J:=1 To 10 Do

TabM[I, J] := I * J;

WriteLn('Tablica GOTOWA!, Drukuje...');

For I:=1 To 10 Do

Begin

For J:=1 To 10 Do

Begin

If (TabM[I, J] < 10) Then Write(' ');

Write(' ', TabM[I, J]);

If (J=10) Then WriteLn;

End;

End;

ReadKey;

END.

Tabliczka mnożenia zupełnie jak na okładce dawnych zeszytów, prawda?

Dla dociekliwych...

Zwróćmy uwagę na dualizm zapisu indeksów w tablicy. Tab[I, J]; i/lub: Tab[I][J];

Ta druga notacja (z prawej) jest notacją przeniesioną z C/C++. Niestety nie wszystkie kompilatory Pascala tolerują oba rodzaje zapisu.

Na płaskim ekranie zademonstrowanie trójwymiarowej tablicy jest trochę skomplikowane. Posłużymy się tu techniką stosowaną w rysunku technicznym dla prezentacji perspektywy - głębi. W trzecim wymiarze pomnożymy każdy element tabliczki mnożenia np. przez 10 a na ekranie przesuniemy wydruk ukośnie. Nie jest to może najbardziej eleganckie, ale pozwala zobaczyć tablicę quasi 3D.

Dla dociekliwych...: 2D, 3D...

Rysunki płaskie - dwuwymiarowe są w skrócie określane jako 2D. To D pochodzi od ang. Dimension - wymiar. Rysunki 3-wymiarowe (dokładniej niby-3-wymiarowe) nazywają się w skrócie 3D drawings. Dla przykładu - Bar3D to procedura rysująca quasi 3-wymiarowy słupek.

Oto prosty program demonstrujący tablicę 3D:

* Tablica trójwymiarowa

uses Crt;

var I, J, K, X, Y : Integer;

TabM : Array[1..10, 1..10, 1..3] Of Integer;

BEGIN

ClrScr;

GoToXY(30, 20);

Write('Tablica 3D:');

For K:=1 To 3 Do

Begin

For I:=1 To 5 Do

Begin

For J:=1 To 5 Do

Begin

TabM[I, J, K]:=I*J*K;

X:=4*(K-1) + 12*I;

Y:=3*(K-1) + 2*J;

GoToXY(X, Y);

Write(TabM[I, J, K]);

End;

End;

End;

ReadKey;

END.

A poniżej program w działaniu. Przy odrobinie wyobraźni można dostrzec trzeci wymiar tablicy.

Tablica nie musi składać się z liczb. Poniżej przykład trochę żartobliwego generatora tekstów losowych z zastosowaniem kilku tablic. Elementami tablic są łańcuchy znakowe. Z losowanych losowo łańcuchów składane jest zdanie, które następnie zostaje wyprowadzone na ekran. Zabawę przerywa naciśnięcie klawisza [Esc] o kodzie ASCII #27.

* Łączenie tekstów wybieranych losowo z tablic

uses Crt;

var Slowo: Array[0..2] Of String;

Podmiot: Array[0..2] Of String;

Orzeczenie: Array[0..2] Of String;

Dodatek: Array[0..4] Of String;

Zdanie : String;

i : Integer;

BEGIN

Slowo[0] := 'Nasz';

Slowo[1] := '';

Slowo[2] := 'PC-Kurier donosi: ';

Podmiot[0] := ' Lechu ';

Podmiot[1]:= 'a Buba ';

Podmiot[2]:= ' Jurek ';

Orzeczenie[0]:='uczy sie ';

Orzeczenie[1]:='boi sie ';

Orzeczenie[2]:= 'nie lubi ';

Dodatek[0]:= 'mowic,';

Dodatek[1]:='logiki,';

Dodatek[2]:='liczyc,';

Dodatek[3]:='czytac,';

Dodatek[4]:='myslec, ';

ClrScr;

Repeat

Zdanie := Slowo[Random(3)] + Podmiot[Random(3)];

Zdanie := Zdanie + Orzeczenie[Random(3)] + Dodatek[Random(5)];

WriteLn(Zdanie);

Until(ReadKey = #27);

END.

Aby łatwiej uzyskać zgodność z funkcją Random(...) losującą od zera do zadanego w postaci argumentu MAX-1, elementy tablic są indeksowane od zera a nie od jedynki.

Deklarowanie i definiowanie zbiorów i elementów zbioru

W dość ciekawy sposób można w Pascalu realizować algebrę zbiorów. Przy konstruowaniu aplikacji poszukujących określonych elementów w zbiorach, wyznaczających iloczyn (część wspólną), sumę, czy dopełnienie (różnicę) zbiorów - najwygodniej posługiwać się w Pascalu słowem kluczowym set. Set - to właśnie zestaw / zbiór. Składnia takiego zapisu w Pascalu jest następująca:

type Cyfry = set of 0..9;

var x : Cyfry;

Jest to poprawna deklaracja nowego typu zbiorów. Po polsku można by zapisać to mniej więcej tak:

typ Cyfry to zestaw składający się z elementów z zakresu od 0 do 9;

nasz roboczy zbiór takiegoż typu (zmienna) będzie się w programie nazywać x;

Aby posługiwać się w programie zbiorem takiego typu należy oczywiście zainicjować zmienną, czyli przyporządkować zbiorowi początkowy zestaw elementów. Do wyliczenia poszczególnych elementów stosuje się nawiasy kwadratowe a elementy rozdziela przecinkami. Składnia takiego przypisania wygląda następująco:

x := [1, 2, 3];

Od tej chwili zbiór x składa się z trzech elementów - cyfr 1, 2 i 3.

UWAGA:

Nie należy mylić następujących pojęć:

- deklaracja typu określa, jakie elementy mogą potencjalnie znajdować się w zbiorze

- zainicjowanie zmiennej określa, jakie elementy rzeczywiście znajdują się w zbiorze w danej chwili.

Zawartość rzeczywista-bieżąca zbioru (jak każdej zmiennej) może w trakcie pracy programu ulegać zmianom.

Aby upewnić się, czy dany element znajduje się w określonym zbiorze, należy zastosować konstrukcję:

If 0 in x Then WriteLn('Zero jest') Else WriteLn('Zera - brak.');

Gdybyśmy przetłumaczyli to na zwykły, ludzki język, brzmiałoby to mniej więcej tak:

Jeśli element 0 znajduje się w zbiorze X To Napisz(‘Jest!) A jeśli nie - Napisz (‘Brak!’);

Poniżej prosty program przykładowy, który:

- deklaruje nowy typ zbioru,

- deklaruje pojedynczy zbiór - zmienną danego typu,

- przypisuje zmiennej wartość, czyli umieszcza w zbiorze zestaw <set> elementów,

- sprawdza, czy elementy 0 i 1 znajdują się w zbiorze.

W przypadku elementu „0” program wydrukuje na ekranie zaprzeczenie (bo zera w zbiorze rzeczywiście nie ma) a w przypadku elementu „1” - program potwierdzi obecność tego elementu w zbiorze X. Oto prosty program w całości.

* Identyfikacja elementów zbioru

Uses Crt;

type Cyfry = set of 0..9;

var x : Cyfry;

BEGIN

ClrScr;

x := [1, 2, 3];

If 0 in x Then WriteLn('Zero jest') Else WriteLn('Zera - brak.');

If 1 in x Then WriteLn('1 - jest w zbiorze.');

ReadKey;

END.

Można by tu stwierdzić sceptycznie, że konstrukcje takie nie wprowadzają w zasadzie ani rzeczywistej nowej jakości, ani nie stwarzają nowych możliwości dla programisty. Byłoby to jednakże, najdelikatniej mówiąc, twierdzenie mijające się zlekka z prawdą - co najmniej tak jak prawo naturalne (czytaj uznaniowe) mija się ze zdrowym rozsądkiem i nowoczesnym pojęciem demokracji.

Aby wykazać elastyczność Pascala - w przykładowym programie poniżej stosuję kilka typów zbiorów. Elementy zbiorów mogą być w Pascalu typami złożonymi a moje samoograniczenie się typów prostych wynika tu jedynie z chęci uproszczenia przykładu.

type Cyfry = set of 0..9;

Litery = set of Char;

Teksty = String;

{ <-- UWAGA: Zwykła zmienna }

Kolory = set of (Bialy, Czarny, Zielony);

Deklaracja typów zawiera cztery typy zbiorów:

- Cyfry: pojedyncze cyfry z zakresu 0, 1, 2, 3,....9

- Litery: pojedyncze znaki z zestawu 255 znaków ASCII typu 1-bajtowego Char;

- Teksty - łańcuchy znaków o maks. długości 255 pascalowskiego typu String

- Kolory - trójelementowy zbiór kolorów (typu wyliczeniowego - enumerator)

Dalsza część programu zawiera deklarację roboczych zmiennych (zbiorów danego typu). Dla uproszczenia deklaruję tu po jednym zbiorze dla każdego typu. Na początku roboczej części programu następuje natomiast zainicjowanie zbiorów, czyli przypisanie im początkowej zawartości.

var x : Cyfry;

y : Litery;

z : Kolory;

t : Teksty;

BEGIN

x := [2];

y := ['Z'];

z := [Czarny];

t := 'Napis';

{ <-- UWAGA: Zwykła zmienna}

Identyfikacja elementów zbioru przebiega w sposób zgodny z intuicyjnym oczekiwaniam, czyli tak, jak wymagają etgo tezy teorii mnogości...

Sprawdźmy to, czyli weryfikacja elementów zbioru

W przeciwieństwie do prawd przyjmowanych na wiarę, w Pascalu wszystko musi być sprawdzalne i powtarzalne. Robocza część programu sprawdza zatem, czy w zbiorach rzeczywiście znajdują się te elementy, które powinny tam się znajdować. Można także dokonać sprawdzenia odwrotnego - czy aby na pewno nie ma tam tych elementów, których się nie spodziewamy. Oto program przykładowy w całości.

* Weryfikacja elementów zbioru

Uses Crt;

type Cyfry = set of 0..9;

Litery = set of Char;

Teksty = String;

Kolory = set of (Bialy, Czarny, Zielony);

var x : Cyfry;

y : Litery;

z : Kolory;

t : Teksty;

BEGIN

x := [2];

y := ['Z'];

z := [Czarny];

t := 'Napis';

ClrScr;

If 2 in x Then WriteLn(2) Else WriteLn('Nie zgadza sie!');

If 'Z' in y Then WriteLn('Z') Else WriteLn('To nie bylo Z !');

If Czarny in z Then WriteLn('Czarny') Else WriteLn('Inny Kolor!');

WriteLn(t);

WriteLn('Teraz warunek nie bedzie sie sprawdzac: ');

If 1 in x Then WriteLn(2) Else WriteLn('Nie zgadza sie!');

If 'Y' in y Then WriteLn('Z') Else WriteLn('To nie bylo Z !');

If Zielony in z Then WriteLn('Czarny') Else WriteLn('Inny Kolor!');

If ('Tekst’ = t) Then WriteLn('Tekst ten sam!') Else WriteLn('Nie pasuje!');

ReadKey;

END.

Potrafimy już zatem zadeklarować i zdefiniować typ zbioru, zainicjować początkową zawartość (wyjściowy zestaw elementów) zawarty w zbiorze. Pora na algebry zbiorów część drugą, czyli operacje na zbiorach.