A. Considerații teoretice

Rezolvarea problemelor complexe presupune scrierea unor programe de dimensiuni mari, care conțin operații, uneori foarte laborioase. Scrierea unor asemenea programe este aproape imposibil de realizat într-o singură fază. Limbajul Pascal oferă suport și facilitează dezvoltarea programelor prin tehnica de rafinare pas cu pas, cunoscută și sub denumirea Step-Wise Refinement. Această tehnică se încadrează în categoria metodelor de proiectare de sus în jos (top down), în care se pornește de la general și prin detalieri (rafinări) succesive, se ajunge la concret, la particular.


B. Exemple

Se cere să se scrie un program pentru evidența activității într-o consignație de autoturisme. La pornire, în cont sunt 100.000 de € (euro), capacitatea depozitului este de 100 de mașini, iar pentru fiecare mașină se înregistrează: denumirea, capacitatea cilindrică (în cmc), anul fabricației și prețul (prezumtiv) de vânzare. Se pot efectua următoarele operații:

După listarea inventarului se va afișa numerarul din cont, împreună cu beneficiul realizat.

În permanență, lista de mașini se va păstra ordonată după denumire, capacitatea cilindrică, anul de fabricație și prețul de vânzare.

Rezolvare

În prima fază se face definirea variabilelor globale și o descriere schematică a programului.

program Consignatie;
const 
  ContInitial = 100000.00
  nMax = 100; {numarul maxim de masini din depozit}
type
  masina = record
    Denumire: string[30];
    CapCil: integer;
    AnFabr: integer;
    PretAch, PretVz: real
  end;
var
  Optiune: char;
  Depozit: array [1..nMax] of masina;
  Cont: real;
  Beneficiu: real;

procedure Initializare;
begin
  NrMasiniInDepozit := 0;
  Beneficiu := 0;
  Cont := ContInitial
end; {Initializare}

procedure AfisareMeniu;
begin
  writeln;
  writeln('Tastati:');
  writeln('A - Achizitionare');
  writeln('V - Vanzare');
  writeln('I - Inventar');
  writeln('T - Inchidere')
end; {Afisarea meniului}

procedure Achizitie;
begin
  writeln('Inventar...')
end; {Achizitie}

procedure Vanzare;
begin
  writeln('Vanzare...')
end; {Vanzare}

procedure Inventar;
begin
  writeln('Inventar...')
end; {Inventar}

begin {Programul Principal}
  Initializare;
  repeat
    AfiseazaMeniu;
    write('Optiunea: ');
    readln(Optiune);
    case Optiune of
      'a', 'A': Achizitie;
      'v', 'V': Vanzare;
      'i', 'I': Inventar
    end
  until Optiune in ['T', 't'];
  writeln;
end.

Pentru a se putea face o primă rulare a programului, procedurile Achizitie, Vanzare și Inventar conțin câte o instrucțiune de scriere, care afișează numele procedurii respective. Lansând în execuție programul de mai sus, se observă că, în funcție de opțiunea tastată (A, V sau I), se va afișa numele procedurii corespunzătoare.

Următorul pas constă în detalierea fiecărei proceduri, folosind aceeași tehnică. Se șterg instrucțiunile care afișează numele procedurii și se detaliază fiecare procedură în parte. De exemplu:

procedure CitesteDatele(var oMasina: masina);
begin
  writeln('Citire date')
end; {CitesteDatele}

procedure IntroduInDdepozit(var oMasina: masina);
begin
  writeln('Introducere in depozit')
end; {IntroducereInDepozit}

procedure Achizitie;
var oMasina: masina;
begin
  if NrMasini = 100 then
    writeln('Nu mai avem spatiu de depozitare...')
  else begin
    write('Pretul: '); readln(oMasina.PretAch);
    if oMasina.PretAch > Cont then
      writeln('Nu avem suficienti bani...')
    else begin
      CitesteDatele(oMasina);
      IntroduInDepozit(oMasina)
    end
  end
end; {Achizitie}

Similar pentru Vanzare. Pentru această operație, mai întâi se afișează lista mașinilor din depozit, după care se execută operațiile aferente vânzării.

procedure ListeazaMasini;
begin
  writeln('Lista masini')
end; {ListeazaMasini}

procedure VindeMasina(var pozitie: integer);
begin
  writeln('Vinde Masina')
end; {VindeMasina}

procedure Vanzare;
var pozitia: integer;
begin
  ListeazaMasini;
  write('Doriti masina nr.: '); readln(pozitia);
  if (pozitia < 1) or (pozitia > NrMasiniInDepozit) then
    writeln('Nu avem...')
  else
    VindeMasina(pozitia)
end; {Vanzare}

În acest fel se poate dezvolta și testa programul, până se ajunge la varianta finală.


C. Teme

  1. Să se finalizeze programul pentru exemplul de mai sus.
     

  2. Un post de radio organizează un "top" al melodiilor. Persoanele care participă, trimițând scrisori, la alcătuirea topului se împart în patru categorii, după sex și după vârstă (mai tinere de 20 de ani și mai în vârstă). Fiecare persoană trebuie să nominalizeze 5 melodii, fiecare identificată prin nume (maxim 15 caractere). Rezultatele se păstrează într-un tablou. Astfel, fiecare intrare în tablou va conține numele și prenumele unui participant la top, sexul, vârsta și cele 5 preferințe în ordine. Acest tablou va fi prelucrat pentru afișarea:

    • unei liste a melodiilor în ordinea popularității;

    • patru liste separate cuprinzând numele și prenumele persoanelor care au menționat pe prima poziție una din cele trei melodii cele mai solicitate la categoria lor.
       

  3. Se cere să se scrie un program pentru editarea unui fișier text. Editarea presupune ștergerea sau înlocuirea unor linii specificate, sau inserția unor linii noi. Editarea este guvernată de o secvența de instrucțiuni de editare (comenzi), după cum urmează:

    I m

    inserția unui text după linia m

    D m n

    ștergerea liniilor de la m la n

    R m n

    înlocuirea liniilor de la m la n

    E

    terminarea procesului de editare

    m și n sunt numere zecimale, iar textele care trebuiesc inserate urmează imediat comenzilor I sau R. Ele se termină printr-o linie goală.

    Se convine ca instrucțiunile de editare să fie furnizate într-o asemenea maniera încât editarea propriu-zisă să se realizeze în ordinea strict crescătoare a numărului liniilor.

    Sugestii de rezolvare (fragment de program):

    program editor;
    
    {fisierele se vor deschide si inchide o singura data}
    
    var
      fin, fout: text;
      fname, line: string;
      pos: longint;	{pozitia in fisierul de intrare -
    			 numarul ultimei linii prelucrate
    			 de ultima comanda executata}
      m, n: longint;	{parametrii comenzii}
      c: char;		{comanda}
    
    procedure ins(m: longint);
    var i: longint;
    begin
      {copiaza, nemodificate, liniile ramase dupa ultima
       comanda, pana la pozitia de inserare}
      for i := pos+1 to m do
        if not eof(fin) then begin
          readln(fin, line);
          writeln(fout, line)
        end;
      {inserarea propriuzisa}
      readln(line);
      while line <> '' do begin
        writeln(fout, line);
        readln(line)
      end;
      pos := m			{ultima linie prelucrata}
    end;
    
    procedure del(m, n: longint);
    var i: longint;
    begin
      {copiaza, nemodificate, liniile ramase dupa ultima
       comanda, pana la pozitia de stergere}
    ...............
      for i := m to n do
        if not eof(fin) then
          readln(fin, line);	{stergere prin necopiere}
      pos := n			{ultima linie prelucrata}
    end;
    
    ...............
    
    begin				{programul principal}
    ...............
          case c of
    ...............
            'R' : begin		{inlocuire}
              readln(m, n);
              {inlocuire = stergere + inserare}
              del(m, n);
              ins(n)
            end;
            'E' : begin		{terminare}
              readln;		{citeste CR+LF din buffer}
              {copiaza, nemodificate, liniile ramase dupa
               ultima comanda, pana la sfarsitul fisierului}
              copy_to_end
            end;
    ...............
          end
    ...............
    end.