20 aplicatii

Embed Size (px)

Citation preview

Bogdan Ptru

20 APLICAII DELPHI I VISUAL BASIC

EduSoft Bacu 2005

Redactor: Tiberiu Socaciu

Copyright 2005 Editura EduSoft Toate drepturile asupra prezentei ediii sunt rezervate Editurii EduSoft. Reproducerea parial sau integral a coninutului, prin orice mijloc, fr acordul scris al Editurii EduSoft este interzis i se va pedepsi conform legislaiei n vigoare. Editura EduSoft 600065 Bacu, str. 9 Mai, nr. 82, sc. C, ap. 13 E-mail: [email protected], Web: www.edusoft.ro

ISBN 973-87655-3-6

2

CUPRINSINTRODUCERE PARTEA I. APLICAII N DELPHI 5 1. Ciupercile - un joc de ndemnare i perspicacitate 7 2. Harta - un program despre Romnia turistic 26 3. Mrfuri - un joc de logic 38 4. Puzzle - un joc de perspicacitate 49 5. Supraf - reprezentarea grafic a suprafeelor 54 6. Parser - analiza sintactic i lexical a unei fraze 61 7. AutoWeb - Creator de pagini web 71 8. Zodiac - ce ne este scris n stele? 84 9. Gastro - program pentru reete culinare 102 PARTEA II. APLICAII N VISUAL BASIC 113 10. Calculator de buzunar 115 11. Prinde mutele 122 12. Vntoarea de berze 128 13. Tetris 135 14. Puzzle cu numere 148 15. Puzzle cu imagini 151 16. Bila 158 17. Test gril 163 18. Test de circulaie rutier 171 19. Bioritm 182 20. Editor de hri 196 BIBLIOGRAFIE 211

3

IntroducerePrin aceast carte dorim s venim n sprijinul tuturor celor care programeaz sau doresc s programeze n mediul Windows i care vor s realizeze aplicaii Windows uor i repede. Aceast carte este o colecie de aplicaii dezvoltate n mediile de programare vizual Delphi i Visual Basic, realizate i comercializate de firmele Inprise (Borland), respectiv Microsoft. Mediul de programare Delphi permite realizarea de programe care s se execute n Windows, cu interfee de tip Windows, pe baza unui limbaj de programare de tip Pascal, iar mediul de programare Visual Basic se bazeaz pe limbajul foarte simplu de nvat Basic. Interfeele aplicaiilor vizuale se implementeaz cu uurin, dar proiectarea i dezvoltarea unor aplicaii inteligente i puternice nu se poate realiza fr un efort de gndire din partea programatorului. Aceasta presupune proiectarea i implementarea n limbajul Object Pascal, respectiv Visual Basic a unor algoritmi eficieni de rezolvare a problemelor n cauz. Aadar, cartea se adreseaz programatorilor serioi, care au cunotinele suficiente de programare obiectual i vizual n mediile de programare menionate. Dar chiar i programatorii obinuii cu medii de programare mai simple pot nva uor programarea vizual n Delphi sau Visual Basic, pe baza unor exemple ca cele din aceast lucrare. Exemplele de aplicaii prezentate n aceast lucrare sunt diferite prin temele pe care le trateaz. Am ncercat s acoperim un numr suficient de situaii pe care orice programator le-ar ntlni atunci cnd ar dori s elaboreze un program mai complex n Delphi sau Visual Basic. Cititorii care doresc s intre n posesia surselor programelor prezentate n aceast carte i a fiierelor cu date (imagini, sunete, text) sunt rugai s ne viziteze site-ul http://edusoft.inf.ro. Cu convingerea c oricine va studia cu atenie aplicaiile prezentate n aceast carte va face din programarea vizual o pasiune, le doresc cititorilor lectur plcut i compilare fr erori! Autorul

4

PARTEA I APLICAII N DELPHI

5

6

Aplicaia 1

Ciupercile - un joc de ndemnare i perspicacitate1.1. Prezentare generalNe propunem s realizm un joc de ndemnare i perspicacitate clasic, pe care l-am denumit Ciupercile i n care, mnuind un omule printr-un labirint de ziduri i scri, trebuie s culegem cu el nite ciuperci amplasate n diferite poziii ale acestui labirint. De asemenea, trebuie s ne ferim de dumani, care n cazul acestui joc sunt nite caracatie. Firete, dei scenariul pare imposibil (ciuperci, caracatie, omulei, ziduri i scri), trebuie s ne gndim c totul este doar un joc! Iat cum va arta jocul nostru n timpul execuiei programului:

7

Ceea ce observai dumneavoastr n imaginea de mai sus este un moment din timpul desfurrii jocului pe cazul unui labirint dat (vezi LAB3.LBR). De fapt, vom creea, separat, cu un editor de texte simplu (de pild Notepad) mai multe fiiere cu labirinturi, ca cele de mai jos: LAB1.LBR LAB2.LBR @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ @ @ @ * & * @ @ & ** * @ @@@@@@@#@@@@@@@@@@@#@@ @@@@@@@#@@@@@@@ @@#@@ @ * * # * # @ @ # # @ @@@#@@@@@@ @@#@@@@@@ @ & # # @ @ # # @ @@@@@@@@@@@@@@@#@@@@@@ @@@#@@ @@@@@@@@@@#@@ @ # @ @ # $ * * # @ @* $ # @ @ #@@@#@@@@@@#@@ # @ @@@#@@@@@@@@@@@@@@@@@@ @ # * # # # @ @ # * @ @ @#@@@# * @@@# @@@@ @ # @@@@@#@@ @ @ # @@@ # @ @ # * # @ @ # ** @ @ @#@@@@ # @ @@@@@@#@@@@ @@@@@@@@@ @ # & # & @ @ * & * @ @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ LAB3.LBR LAB4.LBR @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ @ * ** @ @ @ @@@@@@@#@@@ @@@@@#@@ @ **& * * @ @ ** & # * # @ @@@@@@@#@@@@@@@ @@#@@ @@@#@@@@@@ @@#@@@#@@ @ * # ** & # @ @* # * ** # * # @ @@@@#@@@@@ @@@#@#@@@@ @@@#@@@ @@#@@@@@@@#@@ @ *# # # @ @ # # & ** # @ @@@@#@ @@@@# # @ @ # @#@@@@@@#@@ # @ @* # $ # # * @ @ *# $# * *# @ @@@#@@@@@@@@@@#@@#@@@@ @ @#@@@# * @@@# @@@@ @ # * *# # @ @ # @@@ # @ @ #@@@@ @@@@#@@# @ @ * # & ** @ @ # & * *# # @ @@@@@@ @@#@ @#@@@@@@@ @ @#@@@@ @#@@@ @ @ * & # # & * @ @ # ** & # * @ @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@

8

Aceste fiiere text conin, sub o form codificat, toate informaiile necesare reprezentrii att a labirintului n care se desfoar aciunea din jocul curent, ct i poziiile ciupercilor, poziiile iniiale ale caracatielor i a omuleului. Am spus "iniiale", deoarece, o dat cu trecerea timpului, caracatiele vor avea micri aleatorii prin labirint, vor merge pe diferitele niveluri i vor trece de la un nivel la altul folosindu-se de scri. Micrile lor nu vor fi controlate de juctor, ci de un cronometru (Timer1), pe cnd omuleul va fi deplasat de ctre juctor, prin intermediul tastelor de cursor. Codificarea labirintului respect anumite reguli, de aceea, recomandm cititorului ca, nainte de a-i crea propriile fiiere cu labirinturi (LBR), s le realizeze pe cele date ca model. Fiecare simbol folosit n fiierul LBR are o anumit semnificaie: @ = zid; # = scar; * = ciuperc; & = caracati; $ = omuleul. Iat restriciile folosite n crearea labirinturilor: un labirint este o matrice cu 22 coloane i 16 rnduri; labirintul este bordat pe margini cu ziduri (@); simbolul omuleului apare o singur dat ($); scrile (#) pleac de deasupra unui zid i urc pn la un alt nivel, exact ntre dou ziduri; ciupercile (*) i caracatiele (&) stau pe ziduri; se va folosi simbolul ' ' (spaiu) pentru a marca spaiile n cadrul labirintului.

O alt restricie impus de textul programului, aa dup cum se va vedea, este ca numrul de caracatie s nu depeasc 10, iar numrul de ciuperci s nu fie mai mare de 30. Dac vei crea un labirint greit, atunci vei avea probleme i de acest lucru v vei da seama n timpul execuiei programului. l vei opri i vei corecta labirintul pn nu vor mai aprea probleme. De asemenea, putei porni de la un labirint prezentat i l modificai dup dorin, respectnd restriciile de mai sus.

9

1.2. Textul explicat al programuluin continuare vom prezenta unit-ul ciupercile1.pas, folosit n proiectul Delphi ciupercile.dpr. Acest unit conine toate declaraiile de variabile i toate procedurile i alte elemente folosite n cadrul aplicaiei. Vom comenta fiecare din aceste proceduri i algortmii pe care ele i implementeaz.unit ciupercile1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ExtDlgs; type TForm1 = class(TForm) Timer1: TTimer; Button1: TButton; Label1: TLabel; Label2: TLabel; procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1;

Declaraiile anterioare definesc o form simpl coninnd doar un buton, dou etichete i un cronometru:

10

Toate celelalte lucruri care vor aprea n joc vor fi desenate direct pe form, folosind metodele de desenare ce vor aciona asupra proprietii Canvas a formei Form1. Firete, imediat dup nceputul jocului, butonul Buton1, coninnd acel text explicativ, va disprea.implementation {$R *.DFM}

n cadrul programului vom fi nevoii s desenm mai multe figurine (omuleul, ciupercile etc.). De aceea, vom folosi un procedeu de desenare relativ, pixel cu pixel, a unor curbe, implementat de procedura de mai jos. Am ncadrat n chenar aceast procedur, pentru c o considerm de interes general pentru cititor i la fel vom proceda i cu alte proceduri de acest gen, n cadrul crii.procedure DeseneazaCurba(x0,y0,c: Integer; s: String); var i: Byte; x,y: Integer; begin x:=x0; y:=y0; for i:=1 to Length(s) do begin case s[i] of '1': Dec(y); '2': begin Inc(x); Dec(y) end; '3': Inc(x); '4': begin Inc(x); Inc(y) end; '5': Inc(y);

11

'6': begin Dec(x); Inc(y) end; '7': Dec(x); '8': begin Dec(x); Dec(y) end end; Form1.Canvas.Pixels[x,y]:=c end end;

Aceast procedur deseneaz o curb, punct cu punct, care are culoarea c. Punctul de plecare al curbei are coordonatele x0, y0, iar fiecare din urmtoarele puncte va avea coordonate n funcie de coordonatele punctului precedent. n acest sens se va folosi o codificare prin cifrele '1'..'8', reprezentnd direciile de "deplasare" pentru desenarea punctului urmtor.

De pild, pentru a desena curba din urmtoarea figur, vom apela procedura anterioar astfel: DeseneazaCurba(x0,y0,clBlack,'023354').

Ciupercile i omuleul se deplaseaz prin labirint. Deplasarea va presupune tergerea figurinei din poziia veche i redesenarea ei n noua poziie. tergerea se va face cu ajutorul procedurii de mai 12

jos, ai crei parametri indic zona dreptunghiular care urmeaz s fie tears, prin colorarea tuturor punctelor sale n culoarea fondului (aici clBtnFace).procedure ClearView(x1,y1,x2,y2: Integer); var i,j: Integer; begin for i:=x1 to x2 do for j:=y1 to y2 do Form1.Canvas.Pixels[i,j]:=clBtnFace end;

Urmeaz declaraiile de constante, variabile i tipuri de date referitoare la toate personajele din scenariul nostru:const lat=24;

Aceast variabil reprezint mrimea laturii oricrui ptrel din labirint (fie c este zid, scar sau altceva). Labrintul propriu-zis va fi stocat sub forma unei matrice cu 16 linii i 22 coloane:var L: array[1..16,1..22] of Char;

Prin vieti am notat numrul de viei ale omuleului, care va fi iniial 10 i va scdea de fiecare dat cnd o caracati l va ntlni. Xom, Yom sunt coordonatele curente ale omuleului, iar Xom_i i Yom_i sunt coordonatele sale iniiale.var vieti, Xom, Yom, Xom_i, Yom_i: Integer;

Numrul maxim de ciuperci i numrul maxim de caracatie este precizat prin declaraiile:const max_ciup=30; max_carac=10;

Urmeaz declaraiile unor tipuri de date obiectuale, TCiuperca i TCaracatita. O ciuperc este caracterizat de coordonatele sale n labirint i ca metode avem Init pentru iniializare, Display pentru afiare i Clear, pentru tergere, folosit atunci cnd omuleul a cules ciuperca n cauz.type TCiuperca = object x,y: Integer; procedure Init(x0,y0: Integer); procedure Display;

13

procedure Clear; end;

O caracati are, n plus, un atribut mut care reprezint sensul deplasrii caracatiei la un moment dat, deplasarea propriu-zis fcndu-se cu ajutorul metodei Move. Dup definirea tipului de date TCaracatita urmeaz declararea vectorilor cu ciuperci i caracatie.type TCaracatita = object x,y,mut: Integer; procedure Init(x0,y0: Integer); procedure Display; procedure Clear; procedure Move; end; var Ciup: array[0..max_ciup] of TCiuperca; Carac: array[0..max_carac] of TCaracatita;

Vom avea nevoie i de urmtoarele trei variabile, reprezentnd respectiv numrul de ciuperci rmase n labirint, numrul iniial de ciuperci, numrul de caracatie:var ciuperci,ciuperci_initiale, caracatite: Integer;

Desenarea omuleului n ptrelul de coordonate i, j din matricea labirintului se va face cu procedura de mai jos, care apeleaz att procedura DeseneazaCurba, ct i ale metode grafice (FloodFill, Rectangle) ce scriu direct n proprietatea Canvas a formei Form1.procedure Omulet(i,j: Integer); begin DeseneazaCurba(lat*j+3,lat*i+11,clBlack, '0555443433336666653332321244443331'+ '8888833322221776676777777777888'); Form1.Canvas.Brush.Style:=bsSolid; Form1.Canvas.Brush.Color:=clBlue; Form1.Canvas.FloodFill(lat*j+4,lat*i+14, clBlack,fsBorder); Form1.Canvas.Brush.Color:=clBlue; Form1.Canvas.FloodFill(lat*j+12,lat*i+16, clBlack,fsBorder); DeseneazaCurba(lat*j+8,lat*i+7,clYellow, '0565454433333222118187777777');

14

Form1.Canvas.Brush.Color:=clYellow; Form1.Canvas.FloodFill(lat*j+10,lat*i+9, clYellow,fsBorder); Form1.Canvas.Pen.Color:=clGreen; Form1.Canvas.Pen.Width:=1; Form1.Canvas.Brush.Color:=clGreen; Form1.Canvas.Rectangle(lat*j+7,lat*i+3, lat*j+18,lat*i+6); Form1.Canvas.Pen.Color:=clWhite; Form1.Canvas.MoveTo(lat*j+11,lat*i+2); Form1.Canvas.LineTo(lat*j+14,lat*i+2); DeseneazaCurba(lat*j+10,lat*i+8,clFuchsia,'0357'); DeseneazaCurba(lat*j+14,lat*i+8,clFuchsia,'0357'); DeseneazaCurba(lat*j+10,lat*i+11,clRed,'03533313') end;

Procedura Tipar realizeaz afiarea informaiei corespunztoare unei celule a matricei labirintului, n funcie de coninutul acesteia (dat de L[i,j], unde i i j sunt linia, respectiv coloana acelei celule).procedure Tipar(i,j: Integer); begin case L[i,j] of ' ': ClearView(lat*j+1,lat*i+1, lat*j+lat,lat*i+lat-1); '*': begin Ciup[0].Init(i,j); Ciup[0].Display end; { '&': begin Carac[0].Init(i,j); Carac[0].Display end; } '#': begin Form1.Canvas.Pen.Color:=clmaroon; Form1.Canvas.Pen.Width:=3; Form1.Canvas.Moveto(lat*j+lat div 3,lat*i); Form1.Canvas.LineTo(lat*j+lat div 3, lat*(i+1)-1); Form1.Canvas.MoveTo(lat*(j+1)-lat div 3, lat*i); Form1.Canvas.LineTo(lat*(j+1)-lat div 3, lat*(i+1)-1); Form1.Canvas.MoveTo(lat*j+lat div 3, lat*i+lat div 3); Form1.Canvas.LineTo(lat*(j+1)-lat div 3, lat*i+lat div 3) end; '@': begin

15

Form1.Canvas.Pen.Width:=1; Form1.Canvas.Pen.Color:=clMaroon; Form1.Canvas.Brush.Color:=clRed; Form1.Canvas.Brush.Style:=bsDiagCross; Form1.Canvas.Rectangle(lat*j+1,lat*i, lat*(j+1)-1,lat*(i+1)) end; '$': Omulet(i,j) end end;

n continuare, sunt prezentate cele trei metode ale obiectelor cele trei metode ale obiectelor TCiuperca:procedure TCiuperca.Init; begin x:=x0; y:=y0 end; procedure TCiuperca.Display; var i,j: Byte; begin i:=x; j:=y; DeseneazaCurba(lat*j+3,lat*i+9,clYellow, '0112223232323334334344445577678777777777767777'); Form1.Canvas.Brush.Color:=clYellow; Form1.Canvas.Brush.Style:=bsSolid; Form1.Canvas.FloodFill(lat*j+4,lat*i+8, clYellow,fsBorder); DeseneazaCurba(lat*j+5,lat*i+7,clRed,'0313557'); DeseneazaCurba(lat*j+13,lat*i+7,clRed,'01353'); DeseneazaCurba(lat*j+13,lat*i+3,clRed,'0753'); DeseneazaCurba(lat*j+18,lat*i+6,clRed,'0135'); DeseneazaCurba(lat*j+11,lat*i+10,clLime, '05556565656544333332212181818111177'); Form1.Canvas.Brush.Color:=clLime; Form1.Canvas.Brush.Style:=bsSolid; Form1.Canvas.FloodFill(lat*j+11,lat*i+17,clLime,fsBorder) end; procedure TCiuperca.Clear; begin ClearView(lat*y+1,lat*x+1,lat*y+lat-1,lat*x+lat-1) end;

De asemenea, TCaracatita:

avem

i 16

metodele

obiectelor

de

tip

procedure TCaracatita.Init; begin x:=x0; y:=y0; mut:=Random(2); end;

n metoda de iniializare, proprietatea (atributul) mut ia una din valorile 0 sau 1, pentru o deplasare pe orizontal.procedure TCaracatita.Display; var i,j: Byte; begin i:=x; j:=y; DeseneazaCurba(lat*j+1,lat*i+15,clBlue, '01222211112123132333433'+ '44455555644344877877644444554881717171717755'+ '44535558181188166557555611211111'+ '767757557561121222177675773123'); Form1.Canvas.Brush.Color:=clAqua; Form1.Canvas.Brush.Style:=bsSolid; Form1.Canvas.FloodFill(lat*j+10,lat*i+4, clBlue,fsBorder); DeseneazaCurba(lat*j+7,lat*i+6, clGreen,'02334557778333168'); DeseneazaCurba(lat*j+13,lat*i+6, clGreen,'0233455777825331') end;

procedure TCaracatita.Clear; begin ClearView(lat*y+1,lat*x+1,lat*y+lat-1,lat*x+lat-1); Tipar(x,y) end;

De remarcat c metoda de Clear a metodei TCaracatita se termin prin apelul procedurii Tipar, pentru a restabili coninutul "de sub" caracati din celula de unde pleac acea caracati (care ar putea fi spaiu, scar sau ciuperc). Urmeaz descrierea metodei TCaracatita.Move de deplasare a unei caracatie. Ea apeleaz la o procedur intern cu numele Muta, ce are ca argument sensul deplasrii (m: Integer).procedure TCaracatita.Move; procedure Muta(m: Integer); begin

17

Clear; Tipar(x,y); case m of 0: y:=y-1; 1: y:=y+1; 2: x:=x+1; 3: x:=x-1 end; Display end; begin case L[x,y] of ' ','*': if L[x+1,y]='@' then case mut of 0: if y>2 then if L[x+1,y-1] in ['@','#'] then Muta(mut) else mut:=1 else mut:=1; 1: if ysau Astfel, fraza considerat anterior conine doar cuvinte din vocabularul ales. Pe de alt parte, fraza "orice cine urte o pisic", dei corect sintactic n limba romn, nu este acceptat, deoarece conine cuvinte ce nu sunt trecute n vocabularul nostru. Fiierul conine, pe fiecare rnd, o regul de forma:categorie gramatical (sau parte de vorbire) -> cuvnt din limba romn

Regulile de sintax (din fiierul 'GRAM.TXT') sunt o submulime a regulilor de sintax ale limbii romne: S->NP VP NP->Pron NP->N NP->Det N NP->NP AP AP->A AP->AP CP CP->C A VP->V VP VP->V NP Astfel, folosind notaiile consacrate (S (sentence) = propoziie, NP (noun phrase) = grup verbal, VP (verb phrase) = grup verbal, N (noun) = substantiv, Det (determiner) = determinator (de pild articol nehotrt), AP = grup adjectival, A (adjective) = adjectiv, C = 62

conjuncie, V = verb, CP = grup format dintr-o conjuncie i un adjectiv. Regulile de sintax sunt date, cte una pe linie, astfel: categorie gramatical 1 -> categ. gram. 2 categ. gram. 3, cu sensul c prima categorie gramatical se formeaz din concatenarea celorlalte dou, din dreapta sgeii. Conform regulilor de sintax folosite n aplicaia noastr, fraza considerat la nceput este corect, pe cnd n figura urmtoare este prezentat un caz considerat incorect.

De remarcat c algoritmul implementat de noi folosete doar gramatici scrise n forma normal Chomsky (CNF). O gramatic CNF este o gramatic liber de context, n care produciile sunt de forma: A -> B C, n care A este un neterminal, iar B i C sunt neterminali sau preterminali. De asemenea, am considerat ca acceptabile i reguli de forma A->B. Aadar, n partea dreapt a regulilor de producie vor fi dou sau doar un singur element. Detalii referitoare la subiectul tratat, pentru cititorul neavizat, pot fi studiate n lucrri cu un pronunat caracter tiinific, ca cele menionate la bibliografie.

63

n continuare, vom prezenta algoritmul de baz de analiz (numit i parsare "chart-parsing") elaborat de Cocke, Kasami i Younger i numit algoritmul CKY de baz. Algoritmul folosete o matrice (o diagram) chart ca cele din figurile anterioare. Mai nti avem nevoie de nite definiii: Se definete operaia: Star(X,Y)=C|(A este n X) i (B este n Y) i C->AB este o regul din gramatic. Aceasta reprezint faptul c produsul a dou celule din matrice este creat prin combinarea tuturor perechilor de itemi din cele dou celule ce satisfac nite reguli din gramatic. O alt operaie ce se definete este: Closure(S) = A|(A este n S) sau ((B este n Closure(S)) i (A->B este o regul din gramatic. Aceasta reprezint faptul c nchiderea unei celule S este format din coninutul lui S plus rezultatul adugrii oricrei categorii ce deriv dintr-un membru existent al nchiderii lui S. De pild, dac N este n S atunci N aparine lui Closure(S); apoi, dac exist o regul NP->N, i NP va fi adugat n Closure(S); lucrurile continu n acest mod ct timp se mai pot aduga noi membri n Closure(S). n fine, exist i o funcie Lookup, de forma: Lookup(k) = A|A->cuvntul k, adic ne d lista de categorii gramaticale pe care le cuvntul al k-lea din fraza noastr (uneori un cuvnt poate avea mai multe categorii gramaticale, de pild "duce" poate fi att verb, ct i substantiv). Cu definiiile de mai nainte, algoritmul de baz CKY este:for k:=1 to n do begin chart[k-1,k]:=Closure(Lookup(k)); for i:=k-2 downto 0 do begin chart[i,k]:=; for j:=k-1 downto i+1 do chart[i,k]:=chart[i,k] Star(chart[i,j], chart[j,k]; chart[i,k]:=Closure(chart[i,k]); end end;

64

if S chart[0,n] then Accept else Reject

Algoritmul prezentat mai sus va fi implementat n programul care urmeaz, n care se vor realiza proceduri pentru cele trei funcii definite, din cauza unor restricii ale limbajului Pascal.

6.2. Textul explicat al programului

unit parser1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, ExtCtrls; type TForm1 = class(TForm) StringGrid1: TStringGrid; Edit1: TEdit; Label1: TLabel; procedure Edit1KeyPress(Sender: TObject; var Key: Char);

65

procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const max=20; maxreg=20; maxcuv=5; maxcuvinte=20;

Pentru a memora elementele care apar n stnga i n dreapta unei reguli din gramatic, folosim tipul Cuvint.type Cuvint=String[30]; MultimeDeCuvinte=object nc: Integer; cuv: array[1..maxcuv] of Cuvint; procedure Adauga(c: Cuvint); end;

O regul are dou pri, una n stnga i una n dreapta, iar o gramatic este constituit din mai multe astfel de reguli.regula=record st,dr: Cuvint end; type Gramatica=object nr: Integer; reg: array[1..maxreg] of regula; procedure Citeste(nf: String); end;

Diagrama este o matrice n care fiecare celul este o mulime de cuvinte. G este gramatica cu regulile, iar D este, de fapt, dicionarul de cuvinte folosit.var chart:array[0..max, 0..max] of MultimeDeCuvinte; G: Gramatica; D: Gramatica; Propoz: array[1..maxcuvinte] of Cuvint;

66

Desenarea diagramei se face conform coninutului matricei chart, folosind controlul StringGrid1:procedure DeseneazaChart(i,j: Integer); var t: String; k,kk: Integer; begin if chart[i,j].nc>=1 then begin t:='{'; for k:=1 to chart[i,j].nc-1 do t:=t+chart[i,j].cuv[k]+','; t:=t+chart[i,j].cuv[chart[i,j].nc]+'}'; Form1.StringGrid1.Cells[j,i+1]:=t; Form1.StringGrid1.Refresh end end;

Funcia urmtoare verific dac un cuvnt dat x se afl sau nu ntr-o mulime de cuvinte M.function EsteIn(x: Cuvint; M: MultimeDeCuvinte): Boolean; var este: Boolean; i: Integer; begin este:=False; for i:=1 to M.nc do if x=M.cuv[i] then este:=True; EsteIn:=este end;

Pentru obiectele de tip MultimeDeCuvinte am prevzut o procedur de adugare a unui nou cuvnt:procedure MultimeDeCuvinte.Adauga(c: Cuvint); begin nc:=nc+1; cuv[nc]:=c end;

Pe baza ultimelor dou subprograme descrise, putem defini operaiile Star, Closure i Lookup, precum i operaia de citire a unei gramatici, a crei reguli sunt scrise ntr-un fiier text dat.procedure Star(X,Y: MultimeDeCuvinte; var Z: MultimeDeCuvinte); var i,j,k: Integer; begin Z.nc:=0;

67

for i:=1 to X.nc do for j:=1 to Y.nc do for k:=1 to G.nr do if G.reg[k].dr=X.cuv[i]+' '+Y.cuv[j] then Z.Adauga(G.reg[k].st) end; procedure Closure(S: MultimeDeCuvinte; var C: MultimeDeCuvinte); var i: Integer; gata: Boolean; begin C:=S; repeat gata:=True; for i:=1 to G.nr do if EsteIn(G.reg[i].dr,C) then if not EsteIn(G.reg[i].st,C) then begin C.Adauga(G.reg[i].st); gata:=False end until gata end; procedure Gramatica.Citeste(nf: String); var f: TextFile; s: String; p: Byte; begin nr:=0; AssignFile(f,nf); Reset(f); while not eof(f) do begin nr:=nr+1; ReadLn(f,s); p:=Pos('->',s); reg[nr].st:=Copy(s,1,p-1); reg[nr].dr:=Copy(s,p+2,Length(s)-(p+1)) end; CloseFile(f) end; procedure Lookup(k: Integer; var L: MultimeDeCuvinte); var i: Integer; begin L.nc:=0; for i:=1 to D.nr do if D.reg[i].dr=Propoz[k] then begin L.nc:=L.nc+1; L.cuv[L.nc]:=D.reg[i].st

68

end end;

n fine, procedura urmtoare realizeaz analiza gramatical a frazei date (ss), pe baza algoritmului descris teoretic n primul paragraf.procedure Parseaza(ss: String); var i,j,k,kk: Integer; n: Integer; p: Byte; L,C,S: MultimeDeCuvinte; t: String; begin ss:=ss+' '; n:=0; while ss'' do begin p:=Pos(' ',ss); n:=n+1; Propoz[n]:=Copy(ss,1,p-1); Form1.StringGrid1.Cells[n,0]:=Propoz[n]; Str(n-1,t); Form1.StringGrid1.Cells[0,n]:=t; Delete(ss,1,p) end; Form1.StringGrid1.RowCount:=1+n; Form1.StringGrid1.ColCount:=1+n; Form1.StringGrid1.Show; for k:=1 to n do begin Lookup(k,L); Closure(L,C); chart[k-1,k]:=C; for i:=k-2 downto 0 do begin chart[i,k].nc:=0; for j:=k-1 downto i+1 do begin Star(chart[i,j],chart[j,k],S); for kk:=1 to S.nc do if not EsteIn(S.cuv[kk], chart[i,k]) then chart[i,k].Adauga(S.cuv[kk]) end; Closure(chart[i,k],C); chart[i,k]:=C end end; for i:=0 to n do

69

for j:=0 to n do DeseneazaChart(i,j); if EsteIn('S',chart[0,n]) then Form1.Label1.Caption:= 'Fraza acceptata.' else Form1.Label1.Caption:= 'Fraza rejectata.' end; procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin if Key=Chr(13) then Parseaza(Edit1.Text) end; procedure TForm1.FormCreate(Sender: TObject); begin Caption:='Basic CKY Parser'; StringGrid1.Hide; G.Citeste('gram.txt'); D.Citeste('lex.txt'); end; end.

Iat coninuturile celor dou fiiere (gramatica i dicionarul) folosite de noi n exemplele considerate: GRAM.TXTS->NP VP NP->Pron NP->N NP->Det N NP->NP AP AP->A AP->AP CP CP->C A VP->V VP VP->V NP

LEX.TXTDet->orice Det->fiecare Det->o Det->un Pron->el N->barbat N->femeie V->iubeste V->uraste A->frumoasa A->desteapta C->si C->sau

Atenie! Algoritmul funcioneaz doar dac n partea din dreapta a fiecrei reguli din gramatic sunt cel mult dou simboluri, deci va trebui s avei grij s rescriei gramaticile pe care le folosii astfel nct s ndeplineasc aceast restricie. 70

Aplicaia 7

AutoWeb - Creator de pagini web7.1. Prezentare generalNe propunem, n continuare, s realizm un program cu ajutorul cruia s realizm pagini web personale, dup un anumit format, redat n figura de mai jos:

Dup cum se poate observa n figur, o pagin web creat cu programul nostru, pe care l-am denumit AutoWeb, este compus din trei cadre (frames) i are urmtoarea structur: un cadru n partea de sus, neredimensionabil, n care este scris numele persoanei i deviza (motto-ul); un cadru n partea din stnga, redimensionabil, ce cuprinde hiperlegturi ctre diferite subiecte ce vor fi tratate n fiiere html separate i vor fi afiate n dreapta; 71

un cadru n partea din dreapta, n care vor fi afiate fiierele html la care se face referin din cadrul cuprinsului din cadrul stng. Structura fiierului principal index.html este urmtoarea:

Pagina mea web Aceasta pagina are cadre, dar exploratorul dumneavoastra nu le accepta.

Aadar, am definit dou trei cadre: sus avnd coninutul din fiierul sus.html; stg cu sursa luat din fiierul stanga.html; drp, care se ncarc, pentru nceput, cu fiierul sub1.html, referitor la subiectul 1. Coninutul fiierului sus.html este simplu:

sus Ioana Ionescu Si miine e o zi!

72

Cu excepia rndurilor subliniate, care reprezint numele persoanei i motto-ul su, toate celelalte linii ale fiierului vor fi generate prin program i rmn neschimbate. Totui, trebuie ca s existe un fiier sus.html creat aprioric. Acesta va fi ca cel descris anterior, n care n locurile subliniate apar dou texte sugestive: '(dati numele dumneavoastra aici)' i '(dati motto-ul dumneavoastra aici)'. Numele persoanei i motto-ul su vor fi introduse sau modificate n timpul execuiei aplicaiei AutoWeb, care va genera acest fiier. De asemenea, se presupune existena n directorul curent a unui fiier pentru realizarea fundalului, cu numele fond.jpg. Atenie! Pagina web creat va putea fi afiat doar n Internet Explorer (din cauza modului de definire a cadrelor, ca i din cauza faptului c se definesc cele dou csue de text defilant, cu ajutorul marcatorului marquee. Dac dorii s realizai o variant care s funcioneze i n Netscape Communicator, propunem s renunai de tot la cadrul sus, punnd coninutul acestuia n cadrul din stnga. Cadrul stg va conine ntotdeauna fiierul stg.html, care ar avea o structur de cuprins cu referiri la diferite fiiere html ce vor fi afiate n cadrul drp. De aceea va trebui s folosii atributul target n cadrul definirii hiperlegturilor. Astfel, atunci cnd se alege un subiect din cuprinsul din stnga, datorit faptului c inta este cadrul drp, trimiterea se va face ctre un fiier ce va fi afiat n partea din dreapta. Dac atributul target ar lipsi, noul fiier s-ar afia tot n cadrul din stnga. Meniul Cuprins:

  • Despre mine
  • Pasiunile mele
  • Familia mea

73

Cu excepia rndurilor subliniate, care vor fi introduse de utilizatorul aplicaiei AutoWeb, toate celelalte rnduri ale fiierului stanga.html de mai sus vor fi generate prin program. Corespunztor celor trei subiecte la care se face referin n cadrul lui stanga.html, vor exista trei fiiere sub1.html, sub2.html i sub3.html. Acestea vor conine fraze simple, neformatate, dar e posibil s existe i o imagine n interior. Dac ea exist, numele ei este precizat de ctre utilizatorul programului i imaginea va fi afiat naintea textului. De pild, n exemplul nostru, am folosit fiierul sub1.html cu urmtorul coninut, n care rndurile subliniate au fost introduse de la tastatur, iar restul au fost generate prin program: Despre mine Ma numesc Ioana Ionescu. Sint eleva in clasa a X-a, la Colegiul National "Ferdinand I" din Bacau. Sint nascuta in zodia Gemeni si am 17 ani.

Celelalte pagini (sub2.html i sub3.html) vor fi create asemntor. Dup cum am spus, toate aceste fiiere sunt scrise de programul AutoWeb, aplicaie pe care o vom prezenta mai jos. Excepie face fiierul index.html care va fi realizat de dumneavoastr manual i nu l vei modifica. Fiierele sub1.html, sub2.html i sub3.html vor fi i ele create anterior, dar vor fi modificate de ctre program. La nceput, ele vor arta ca mai jos (pstrai propoziiile scrise ntre parenteze rotunde, pentru c ele trebuie s se regseasc n acea procedur din textul programului care se ocup de salvarea ntregii pagini web).

74

(scrieti aici denumirea subiectului) (tratati aici pe larg acest subiect)

Pentru a le edita, putei folosi un editor de texte precum Notepad. n timpul execuiei, aplicaia AutoWeb arat ca n figura urmtoare. Aadar, exist o csu de text n care se introduce numele persoanei, una n care aceasta i scrie motto-ul, precum i trei tabulatori (controale de tip TTabControl), corespunztori celor trei subiecte. n cadrul fiecruia se va nscrie numele subiectului corespunztor, coninutul fiierului respectiv, adic textul, precum i numele fiierului n care se afl imaginea ce va aprea n acel fiier.

75

De pild, n exemplul considerat n figuri, subiectul 1 va figura n meniul din cadrul stng cu numele "Despre mine", va avea coninutul (textul) "M numesc Ioana Ionescu....", iar fiierul cu imagine va fi "fata.jpg". Firete, se presupune c exist pe disc aceste fiiere cu imagini, scanate. n figura urmtoare se observ cum arat forma aplicaiei n timpul proiectrii acesteia. Aadar, pe lng controalele descrise, exist un buton pentru salvarea fiierelor HTML create, adic pentru nscrierea pe disc a paginii web realizate. S remarcm i csua de introducere a numelui fiierului cu imagini, n fiecare din cei trei tabulatori. Exist i un control de tip TOpenDialog, care este apelat de ctre un buton, pentru a putea alege un fiier cu o imagine, n mod interactiv, prin intermediul unei ferestre de dialog de tip "deschidere de fiier".

76

7.2. Textul explicat al programuluin continuare, s vedem cum funcioneaz toate controalele din forma aplicaiei AutoWeb.unit web1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls; type TForm1 = class(TForm) Label1: TLabel; Edit1: TEdit; Label2: TLabel; Edit2: TEdit; TabControl1: TTabControl; Memo1: TMemo; Button1: TButton; Edit3: TEdit; Label3: TLabel; Button2: TButton; Edit4: TEdit; OpenDialog1: TOpenDialog; procedure TabControl1Change(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM}

77

var nr_sub_tratat: Integer; subiect: array[1..3] of String;

Procedura urmtoare realizeaz trecerea de la un tabulator la altul. Astfel, schimbndu-se subiectul curent, salvm datele din subiectul curent i apoi le ncrcm pe cele ale subiectului urmtor. Urmrii cu atenie comentariile din cadrul textului procedurii!procedure TForm1.TabControl1Change(Sender: TObject); var s: String; i: Integer; f: TextFile; begin { salvam ce este scris in subiectul curent } Str(nr_sub_tratat,s); subiect[nr_sub_tratat]:=Edit4.Text; AssignFile(f,'sub'+s+'.html'); Rewrite(f); WriteLn(f,''); WriteLn(f,Edit4.Text); WriteLn(f,''); WriteLn(f,''); if (Edit3.Text'(dati numele fisierului)') and (Edit3.Text'') then begin WriteLn(f,'') end; if Memo1.Lines.Count=0 then WriteLn(f,'(tratati aici subiectul'+ ' pe larg)') else for i:=0 to Memo1.Lines.Count-1 do WriteLn(f,''+Memo1.Lines[i]+''); WriteLn(f,''); WriteLn(f,''); CloseFile(f); { incarcam ce era scris in subiectul nou tratat } Memo1.Clear; Edit3.Clear; Edit4.Clear; nr_sub_tratat:=TabControl1.TabIndex+1; Str(nr_sub_tratat,s); AssignFile(f,'sub'+s+'.html'); Reset(f); ReadLn(f,s); {}

78

ReadLn(f,s); Edit4.Text:=s; subiect[nr_sub_tratat]:=Edit4.Text; ReadLn(f,s); {} ReadLn(f,s);{f,'} ReadLn(f,s); if Copy(s,1,4)='") fis_ob = Left(s, p - 1) + ".WMF" nume_ob = Right(s, Len(s) - p - 1) Load obiectiv(i) obiectiv(i).BorderStyle = 1 obiectiv(i).Stretch = True obiectiv(i).Left = lat * (j - 1) obiectiv(i).Top = has * (k - 1) obiectiv(i).Width = lat obiectiv(i).Height = has obiectiv(i).Tag = nume_ob obiectiv(i).Picture = LoadPicture(fis_ob) obiectiv(i).DragMode = 1 obiectiv(i).Visible = True Next k Next j Close #1 End Sub

Dac utilizatorul programului vrea s neleag ce reprezint fiecare din cele 45 de pictograme din legenda din stnga lui Form1, atunci el va aciona butonul din dreapta al mouse-ului, n dreptul obiectivului corespunztor. Acest lucru va avea ca efect apelarea subrutinei:Sub obiectiv_Click (Index As Integer) MsgBox obiectiv(Index).Tag, 64, "Ce reprezinta asta?" End Sub

Figura de mai jos prezint modul de afiare a semnificaiei pictogramei cu pachetul:

204

X_min

pictograma cu pachetul, care reprezint un magazin

Trasarea strzilor se face cu subrutina urmtoare, care ine cont de faptul c variabila desen s-a iniializat cu False, n Form_Load:Sub Form_MouseDown (Button As Integer, Shift As Integer, x As Single, y As Single) If desen Then Select Case Button Case 1: DrawWidth = 3 ForeColor = RGB(150, 200, 200) Case 2: DrawWidth = 8 ForeColor = RGB(200, 200, 50) End Select

205

If x < x_min Then x = x_min Line (first_x, first_y)-(x, y) ns = ns + 1 ReDim Preserve Strada(ns) Strada(ns).X1 = first_x: Strada(ns).X2 = x Strada(ns).Y1 = first_y: Strada(ns).Y2 = y Strada(ns).tip = Button desen = False MousePointer = 0 Else desen = True first_x = x: first_y = y MousePointer = 2 End If End Sub

tergerea tututor strzilor se realizeaz apelnd din meniu, comanda corespunztoare:Sub mnuClear_Click () ns = 0: ReDim Strada(0) Form_Paint End Sub

Iat i cum se realizeaz amplasarea obiectelor pe hart, prin drag and drop:Sub Form_DragDrop (source As Control, x As Single, y As Single) If x - source.Width \ 2 < x_min Then MsgBox "Nu se poate aseza aici !", 16, "Atentie!" Exit Sub End If n = n + 1 Load ob(n) ob(n).Width = source.Width ob(n).Height = source.Height ob(n).Stretch = True ob(n).Tag = source.Tag ' se va adauga si denumirea ! ob(n).Left = x - (ob(n).Width / 2) ob(n).Top = y - (ob(n).Height / 2) ob(n).BorderStyle = 0 ob(n).Picture = source.Picture ob(n).Visible = True ob(n).MousePointer = 10 Form1.Enabled = False 'Form1.Hide ' pentru a evita problemele

206

Form2.Caption = "Denumire " + ob(n).Tag Form2.Text1.SelStart = 0 Form2.Text1.SelLength = Len(Form2.Text1.Text) Form2.Show ' preia denumirea lui ob(n) Do DoEvents ' asteapta pana se termina lucrul in Form2 Loop Until Form1.Enabled = True ob(n).Tag = ob(n).Tag + " " + Form2.Text1.Text End Sub

Observai apelui celei de a doua forme (Form2) care preia denumirea obiectului amplasat. Ciclul:Do DoEvents ' asteapta pana se termina lucrul in Form2 Loop Until Form1.Enabled = True

are rolul de a bloca temporar execuia programului, la nivelul lui Form2. tergerea unui obiect, sau aflarea de informaii despre el se realizeaz cu subrutina urmtoare:Sub ob_MouseDown (Index As Integer, Button As Integer, Shift As Integer, x As Single, y As Single) Select Case Button Case 2 ' se sterge afisajul si obiectul CurrentX = ob(n).Left CurrentY = ob(n).Top - 200 ForeColor = QBColor(15) Print ob(n).Tag x = ob(n).Left: y = ob(n).Top ob(Index).Visible = False ob(Index) = ob(n) ob(Index).Left = x: ob(Index).Top = y ob(Index).Visible = True Unload ob(n) n = n - 1 Case 1 ' afisez informatii MsgBox ob(Index).Tag, 64, "Informatii" End Select End Sub

207

Iat i subrutina care redeseneaz, la nevoie, coninutul formei Form1. Ea redeseneaz (la noile proporii) legenda cu obiective din stnga formei, apoi strzile i obiectele de pe hart.Sub Form_Paint () Cls ' reafisez meniul cu obiective din stanga has = ScaleHeight \ 15 lat = has x_min_vechi = x_min 'pentru calcule ulterioare x_min = 3 * has + 10 For i = 1 To 45 obiectiv(i).Visible = False Next i For j = 1 To 3 For k = 1 To 15 i = 15 * (j - 1) + k obiectiv(i).Left = lat * (j - 1) obiectiv(i).Top = has * (k - 1) obiectiv(i).Width = lat obiectiv(i).Height = has obiectiv(i).Visible = True Next k Next j ' redesenez strazile rap_x=(ScaleWidth-x_min)/x_0: rap_y=ScaleHeight/y_0 x_0 = ScaleWidth - x_min: y_0 = ScaleHeight For i = 1 To ns Select Case Strada(i).tip Case 1: DrawWidth = 3 ForeColor = RGB(150, 200, 200) Case 2: DrawWidth = 8 ForeColor = RGB(200, 200, 50) End Select Strada(i).X1=x_min+rap_x*(Strada(i).X1-x_min_vechi) Strada(i).Y1 = rap_y * Strada(i).Y1 Strada(i).X2=x_min+rap_x*(Strada(i).X2-x_min_vechi) Strada(i).Y2 = rap_y * Strada(i).Y2 Line (Strada(i).X1, Strada(i).Y1)(Strada(i).X2, Strada(i).Y2) Next i ' sterg ob-urile, pentru a le reafisa la noile dimensiuni For i = 1 To n ob(i).Visible = False Next i For i = 1 To n ' calculez noile coordonate

208

ob(i).Left=(ob(i).Left-x_min_vechi)*rap_x+x_min ob(i).Top = ob(i).Top * rap_y ' calculez noile dimensiuni in functie de un obiectiv ob(i).Width = obiectiv(1).Width ob(i).Height = obiectiv(1).Height 'afisez din nou ob(i).Visible = True Next i End Sub

Form_Resize apeleaz, la rndu-i, subrutina Form_Paint descris anterior:Sub Form_Resize () Form_Paint End Sub

Restul subrutinelor prezentate mai jos:

(din

fiierul

HARTA.FRM)

sunt

Sub Form_Unload (Cancel As Integer) Unload Form2 ' ca sa se opreasca ! End Sub Sub mnuDespre_Click () s1 = "Acesta este un editor de harti!" NL = Chr$(13) + Chr$(10) s2 = "(C) 1998 B.P., tel. 092-738341" MsgBox s1 + NL + s2, 64, "Despre program" End Sub Sub mnuExit_Click () End End Sub Sub mnuHartaNoua_Click () For i = n To 1 Step -1 Unload ob(i) Next i n = 0 mnuClear_Click End Sub

209

Fiierul HARTA_D.FRM Acest fiier conine doar o singur subrutin, uor de neles, care acioneaz la finele introducererii unui text n caseta Text1:

Sub Text1_KeyPress (KeyAscii As Integer) If KeyAscii = 13 Then Form1.Enabled = True Form2.Hide End If End Sub

210

Bibliografie1. Bogdan Ptru - Aplicaii n Delphi, Editura Teora, Bucureti, 1998. 2. Bogdan Ptru - Aplicaii n Visual Basic, Editura Teora, Bucureti, 1998

* * *

Observaie. Sursele aplicaiilor din aceast carte au fost realizate, compilate i testate n mediile de programare Delphi 3 i Visual Basic 3. Adaptarea acestor aplicaii la versiuni ulterioare ale celor dou medii de programare rmne n seama cititorului. Orice adaptare la Delphi 6 sau Visual Basic 6 pe care o realizai o putei trimite prin e-mail la [email protected] sau [email protected].

211