Rafinarea


Principii

Rezolvarea informatica a multor probleme complexe necesita o analiza structurata bine facuta, cât si o proiectare la fel de bine realizata.

Pentru a scrie programe PASCAL (rezonabile) vom avea nevoie mereu de un algoritm.

Schitati pentru început actiunile neprimitive (ce urmeaza a fi descompuse) ale algoritmului. Dupa aceea, descompuneti (rafinati) aceste actiuni pâna când ajungeti la o primitiva recunoscuta de calculator.

O tehnica ce se preteaza de minune la proiectarea top - down este stepwise refinement (rafinarea pas cu pas). Pentru aplicarea acestei tehnici trebuie parcursi urmatorii pasi :

  1. Scrieti în limba româna (engleza) o solutie simpla. Nu va preocupati prea mult de detalii;
  2. Rafinati solutia folosind limbajul pseudocod. Eliminati detaliile suparatoare, imaginându-va ca aveti deja procedurile care fac lucruri complicate;
  3. Rafinati rezultatele pasului 2 pâna când ati scris corect programul principal PASCAL , chiar daca programul contine mai multe referiri la procedurile care nu au fost înca scrise;
  4. Codificati toate procedurile ca proceduri nule. Compilati procedurile, eliminati erorile pâna când obtineti o compilare corecta (curata);
  5. Înlocuiti cu logica necesara atâtea proceduri nule câte sunt necesare pentru a putea realiza o executie a programului principal ( evident, fara toate procedurile scrise nu putem astepta raspunsurile finale, dar putem cunoaste raspunsurile intermediare );
  6. Înlocuiti în mod gradat procedurile nule ramase cu cele reale pâna când programul va opera corect.

Remarca:

Pentru programele mari, câtiva din acesti pasi pot fi combinati sau pot fi facuti mintal. Cu cât veti avea mai multa experienta, cu atât veti face rafinari mai putine.


Exemplificare

Vom exemplifica acesti pasi pe un caz concret, oferit de urmatoarea aplicatie:

Aplicatie

Sa se editeze blocuri (etichetate) de numere întregi care reprezinta calendarul lunilor.


..L....M....M....J....V....S....D
.. ....1....2....3....4....5....6
..7....8....9...10...11...12...13
.14...15...16...17...18...19...20
.21...22...23...24...25...26...27
.28...29...30...31

Formatul datelor de iesire

Tabela de variabile:

TABELA DE VARIABILE
Variabile de intrare Variabile de stare Variabile de iesire
nz: numarul de zile ale lunii
l_1: ziua de intâi a lunii
i: index
 

Utilizând metodologia stepwise refinement vom începe prin a face analiza problemei urmata de o solutie (în limba româna).

Pasul 1:

Prima linie a blocului de numere contine cel putin un numar (cel mult 7) si poate începe cu blancuri (1-6) astfel încât putem considera prima linie ca pe un caz special.

Urmatoarele trei linii sunt intotdeauna complete, chiar daca prima zi "pica" duminica. Deci, putem tipari cele trei linii. Si a cincea linie poate fi completa, dar nu mereu. De asemenea, poate exista o a sasea linie pentru lunile de 30 si 31 de zile în care prima zi a lunii este ultima zi din saptamâna. Ultimele doua situatii vor fi tratate ca pe un caz special, fiecare.

Pasul 2:

Procedam la o rafinare a textului stabilit în pasul anterior si elaboram algoritmul de baza listând atât actiunile primitive cât si cele neprimitive. Pentru descrierea algoritmului vom folosi pseudocodul, retinând de aceasta data câteva din detaliile... suparatoare ale primei etape.

PSEUDOCODUL
FOR toate lunile anului DO
..BEGIN
....Citeste nz, l_1
....Tipareste zilele saptamânii (prima litera)
....Tipareste o linie alba
....Tipareste prima linie
....Tipareste urmatoarele trei linii
....Tipareste a-5-a linie daca este nevoie
....Tipareste a-6-a linie daca este nevoie
....Tipareste o linie alba
END

Pasul 3:

Generam o prima forma a programului PASCAL în care fiecare actiune din pseudocod este înlocuita cu un enunt (valabil) sau cu apeluri ale unor proceduri nule (nescrise).

PROGRAM calendar;
VAR
....nz, l_1: integer;
....i: integer;
BEGIN { program principal }
....FOR i:=1 TO 12 DO
........BEGIN
............readln(nz, l_1)
............bloc;
............linie1(l_1);
............linie234(valoare de start);
............linie56(valoare de start,valoare de end);
............linie56(valoare de start,valoare de end);
............writeln
........END
END {calendar}.

Programul principal contine patru proceduri:

In aceasta etapa nu este bine sa va necajiti, facându-va probleme ca nu aveti, înca, nici o idee despre valorile parametrilor efectivi, declarati în program. Suntem de-abia la începutul ... sfârsitului !

Ati remarcat ca fraza pseudocod
....."FOR toate lunile anului DO"
s-a tradus direct în PASCAL prin:
....."FOR i:=1 TO 12 DO"?

Am ales ca structura de iteratie FOR întrucât stim de la început ca programul va genera 12 blocuri de numere - calendarul pentru 12 luni (am folosit ca index, variabila întreaga "i").

V-a trecut supararea? Daca da, atunci ... sa navigam încercând sa realizam codul PASCAL pentru câteva proceduri, celelalte ramânând (nu pentru mult timp ) nule.

PROGRAM calendar;
VAR
. i,nz,l_1:integer;
 
PROCEDURE bloc;
BEGIN
. writeln;
. writeln(’..L....M....M....J....V....S....D’);
. writeln
END { bloc }
 
PROCEDURE linie1(n: integer);
VAR
. j:integer;
BEGIN
. FOR j:=1 TO n-1 DO
. . write(’ ’:5);
. FOR j:=1 TO 8-n DO
. . write(j:5);
. writeln
END { linie1 };
 
PROCEDURE linie234(primul, ultimul: integer); { procedura nula }
BEGIN
END { linie234 };
 
PROCEDURE linie56(primul, ultimul:integer); { procedura nula }
BEGIN
END { linie56 };
 
BEGIN { program principal }
. FOR i:=1 TO 12 DO
. BEGIN
. . writeln(’introduceti pentru luna ’,i:2);
. . write(’numarul total de zile ’);
. . readln(nz);
. . write(’pozitia lui 1 in saptamina (joi=4) ’);
. . readln(l_1);
. . bloc;
. . linie1(l_1);
. . linie234(9-l_1);
. . linie56(0,0);..{ cit timp sunt intregi argumentele }
. . linie56(0,0);..{ nu au importanta,din moment ce }
. . writeln . . . { linie56 este nula }
. END
END {calendar}.

Încercati o compilare a programului. V-a reusit? Daca într-adevar compilarea este corecta sa trecem si la executia programului. Introduceti numarul de zile ale lunii (31) si ziua de întâi a lunii (6).

Ati obtinut imaginea de mai jos?

..introduceti pentru luna 1
..numar total de zile 31
..pozitia lui 1 in saptamana (joi=4)..6..
....L...M...M...J...V...S...D
....L...M...M...J...V...1...2

Daca nu, confruntati programul dumneavoastra cu cel realizat de noi si vedeti ce lipseste. Daca ati reusit, continuati! Daca n-ati reusit, continuati !

Trebuie sa recunoastem ca am facut într-adevar progrese. Dar înca n-am terminat programul ! Tot ceea ce ne-a mai ramas de facut este sa scriem codul pentru procedurile nule: linie234, linie56 si apoi sa ne gândim la parametrii efectivi ale caror valori sa "hraneasca" procedurile ramase necodificate (linie234 si linie56).

Programul final este urmatorul:

PROGRAM calendar;
VAR
..i,nz,11:integer;
 
PROCEDURE bloc;
BEGIN
..writeln;
..writeln (’ L M N J V S D’);
..writeln
END { bloc };
 
PROCEDURE linie1(n:integer);
VAR
..j:integer;
BEGIN
..FOR j:=1 TO n-1 DO
....write (’ ’:5);
..FOR j:=1 TO 8-n DO
....write (j:5);
..writeln
END;{ linie1 }
 
PROCEDURE linie234(n:integer);
VAR
..i,j:integer;
BEGIN
..FOR i:=1 TO 3 DO
..BEGIN
....FOR j:=1 TO 7 DO
....BEGIN
......write(n:5);
......n:=n+1
....END;
....writeln
..END;
END; { linie234 }
 
PROCEDURE linie56(primul,ultimul:integer);
VAR
..i,limita:integer;
BEGIN
..IF (ultimul-primul)<7 THEN
....limita:=ultimul
..ELSE
....limita:=primul+6;
..FOR i:=primul TO limita DO
....write(i:5);
..writeln
END; { linie56 }
 
BEGIN { programul principal }
..FOR i:=1 TO 12 DO
..BEGIN
....writeln(’Introduceti pentru luna ’,i:2);
....write(’numar total zile ’);
....readln(nz);
....write(’pozitia lui 1 in saptamina (joi=4) ’);
....readln(l_1);
....bloc;
....linie1(l_1);
....linie234(9-l_1);
....linie56(30-l_1, nz);
....linie56(37-l_1, nz);
....writeln
..END
END { calendar }.

Rezultatele executiei programului:

Introduceti pentru luna 1
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 6
 
..L...M...M...J...V...S...D
 
......................1...2
..3...4...5...6...7...8...9
.10..11..12..13..14..15..16
.17..18..19..20..21..22..23
.24..25..26..27..28..29..30
.31
 
Introduceti pentru luna 2
numar total zile 28
pozitia lui 1 in saptamina (joi=4) 2
 
..L...M...M...J...V...S...D
 
......1...2...3...4...5...6
..7...8...9..10..11..12..13
.14..15..16..17..18..19..20
.21..22..23..24..25..26..27
.28
 
Introduceti pentru luna 3
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 2
 
..L...M...M...J...V...S...D
 
......1...2...3...4...5...6
..7...8...9..10..11..12..13
.14..15..16..17..18..19..20
.21..22..23..24..25..26..27
.28..29..30..31
 
Introduceti pentru luna 4
numarul total zile 30
pozitia lui 1 in saptamina (joi=4) 5
 
 
..L...M...M...J...V...S...D
 
..................1...2...3
..4...5...6...7...8...9..10
.11..12..13..14..15..16..17
.18..19..20..21..22..23..24
.25..26..27..28..29..30
 
Introduceti pentru luna 5
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 7
 
..L...M...M...J...V...S...D
 
..........................1
..2...3...4...5...6...7...8
..9..10..11..12..13..14..15
.16..17..18..19..20..21..22
.23..24..25..26..27..28..29
.30..31
Introduceti pentru luna 6
mumar total de zile 30
pozitia lui 1 in saptamina (joi=4) 3
 
..L...M...M...J...V...S...D
 
..........1...2...3...4...5
..6...7...8...9..10..11..12
.13..14..15..16..17..18..19
.20..21..22..23..24..25..26
.27..28..29..30
 
Introduceti pentru luna 7
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 5
 
 
..L...M...M...J...V...S...D
 
..................1...2...3
..4...5...6...7...8...9..10
.11..12..13..14..15..16..17
.18..19..20..21..22..23..24
.25..26..27..28..29..30..31
 
Introduceti pentru luna 8
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 1
 
..L...M...M...J...V...S...D
 
..1...2...3...4...5...6...7
..8...9..10..11..12..13..14
.15..16..17..18..19..20..21
.22..23..24..25..26..27..28
.29..30..31
 
Introduceti pentru luna 9
numar total zile 30
pozitia lui 1 in saptamina (joi=4) 4
 
 
..L...M...M...J...V...S...D
 
..............1...2...3...4
..5...6...7...8...9..10..11
.12..13..14..15..16..17..18
.19..20..21..22..23..24..25
.26..27..28..29..30
 
Introduceti pentru luna 10
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 6
 
 
..L...M...M...J...V...S...D
 
......................1...2
..3...4...5...6...7...8...9
.10..11..12..13..14..15..16
.17..18..19..20..21..22..23
.24..25..26..27..28..29..30
.31
Introduceti pentru luna 11
numar total zile 30
pozitia lui 1 in saptamina (joi=4) 2
 
..L...M...M...J...V...S...D
 
......1...2...3...4...5...6
..7...8...9..10..11..12..13
.14..15..16..17..18..19..20
.21..22..23..24..25..26..27
.28..29..30
 
Introduceti pentru luna 12
numar total zile 31
pozitia lui 1 in saptamina (joi=4) 4
 
..L...M...M...J...V...S...D
 
..............1...2...3...4
..5...6...7...8...9..10..11
.12..13..14..15..16..17..18
.19..20..21..22..23..24..25
.26..27..28..29..30..31