* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Zaklady programovani v Turbo Pascalu (prepracovane druhe vydani) * * ====================================== * * sepsal Mircosoft (http://mircosoft.mzf.cz) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tento soubor doporucuji otevrit primo v Turbo Pascalu a pri cteni prubezne konzultovat napovedu (umistete kurzor na dane slovo a stisknete Ctrl+F1). Vsechno, co zde najdete, jsem minimalne jednou vyzkousel a funguje to. Obsah: 0 - Terminologie 1 - Struktura programu 2 - Datove typy 3 - Prikazy 4 - Procedury 5 - Funkce 6 - Struktura jednotky 7 - Vysvetleni nejpouzivanejsich standardnich procedur a funkci ****************************************************************************** 0 - Terminologie ****************************************************************************** Aby bylo jasno, o cem mluvim: identifikator: jmeno programu, jednotky, promenne, typu, konstanty, procedury, atd. Muze obsahovat velka i mala pismena, cislice (ne na zacatku) a nektere dalsi znaky, napr. '_'. Nesmi obsahovat: mezery, '@#$^*()-=+/.;, a podobne a nesmi se shodovat s jakymkoli klicovym slovem. Priklady: a, A (prekladac nerozlisuje velka a mala pismena), Stav_klaves, counter, MojeFunkce, _vx, str58, x6_2 apod. Nelze: 3Dcara, Obr3*3, sedmi-uhelnik, apod. klicove slovo: and,asm,array,begin,case,const,div,do,downto,else,end,file,for, function,goto,if,implementation,in,inline,interface,label, mod,nil,not,object,of,or,procedure,program,record,repeat,set, shl,shr,string,then,to,type,unit,until,uses,var,while,with,xor (a par dalsich) Pascal tato slova obvykle zvyraznuje bile. vyraz: cokoli, co dava nejakou hodnotu. Napr. a+b, a, b1>b2 (typ boolean, viz dale), sqrt(sqr(u[1])+sqr(u[2])), readkey, 50, 5*(a+2), 1+1, apod. zasobnik: cast pameti vyhrazena pro staticke promenne (viz dale), velka je obvykle kolem 16 kB. hromada: druha cast pameti vyhrazena pro dynamicke promenne. Miva kolem 640 kB. kompilace: preklad zdrojoveho kodu do EXE souboru operator: znamenko mezi dvema operandy (+,-,*,/,...) operand: to, na co zrovna pouzivame operator (napr.:A+B - operandy jsou A a B) ****************************************************************************** 1 - Struktura programu ****************************************************************************** Kazdy program ma vicemene presne danou strukturu. Vypada takto: program NAZEV_PROGRAMU; hlavicka [uses] seznam pouzitych jednotek \ [label] deklarace navesti \ [const] deklarace konstant \ deklaracni [type] deklarace typu / cast [var] deklarace promennych / [procedure] deklarace procedur... / [function] ...a funkci / begin zacatek kodu vlastniho programu \ prikazova [PRIKAZY] posloupnost prikazu / cast end. konec programu. / Jednotlive prvky si dale blize vysvetlime. Syntaxe zdrojoveho kodu je pomerne volna. Nezalezi na tom, kolik mezer mezi jednotliva slova vlozite nebo na kolik radku to roztahnete, prekladac prebytecne mezery a oddelovace radku ignoruje. Je ale dobre zvolit si nejakou jednotnou upravu a tu pak dodrzovat, program je pak o dost prehlednejsi. Hlavni zasada je: cokoli, co chcete v programu pouzivat, musi byt nekde predem definovane. Komentare se pisou do slozenych zavorek: {toto je komentar} nebo takto: (* toto je taky komentar *). Oba druhy jsou rovnocenne. Prekladac komentare ignoruje a nepreklada. Pouzivaji se jednak na psani poznamek do zdrojoveho kodu a jednak na rychle vyrazeni casti programu z provozu, aniz bychom ji museli vymazat. Pri ladeni delsich programu jsou obe funkce prakticky nezbytne. Ve slozenych zavorkach {} se pisi jeste tzv. direktivy prekladace, ale o tech nekdy jindy. Cisla se pisi normalne v desitkove soustave, pokud chcete napsat cislo v hexadecimalni (sestnactkove) soustave, napiste pred nej $ (napr. $AF50). Vyhodou hexa soustavy je, ze se dobre prevadi na dvojkovou. Jedna cifra jsou presne 4 bity. V hranatych zavorkach [] zde pisu prvky, ktere nejsou povinne. Do zdrojove- ho kodu je ovsem takto psat nemuzeme, tam maji jiny vyznam. Prekladac nerozlisuje velka a mala pismena. Tedy napr. WriteLn znamena totez co writeln, wrITELn nebo WRITELN. Apostrof (') se pise (na anglicke klavesnici) tou klavesou mezi strednikem a Enterem. Tohle ` (psano klavesou v levem hornim rohu klavesnice) neni ono. A ted uz k tem prvkum programu: program JMENO_PROGRAMU; ======================= Tomuhle se rika hlavicka programu. Timto klicovym slovem by mel zacinat kazdy zdrojovy kod, ze ktereho ma vznik- nout spustitelny program. Pisu "mel by", protoze se hlavicka u vetsiny prekladacu vubec psat nemusi, ale je to s ni prehlednejsi. Za slovem Program nasleduje identifikator programu (jmeno). V nekterych starsich programech se jeste v zavorce za jmenem udavaly jako parametry vsechny soubory, se kterymi program pracoval, napr.(input,output). To uz se ale nepouziva. Hlavicka je ukoncena strednikem. Zde napsane jmeno se nemusi shodovat se jmenem souboru, pod kterym program ukladate a kompilujete. Nevim, kolik pismen muze maximalne mit, ale asi hodne. Priklady: program Pokus; program Muj_prvni_program; [ uses JEDNOTKA1 [,JEDNOTKA2...] ; ] ==================================== Zde jsou deklarovany vsechny jednotky (unitky), ktere program pouziva. Pokud jich pouziva vice, oddeluji se carkou, za posledni se pise strednik. Jsou to v podstate knihovny, ktere si muze programator sam tvorit. Obsahuji definice typu, promennych, procedur atd. Budou podrobne popsany dale. Standardni jednotky jsou napr.: crt, graph, dos, a dalsi. Priklad: uses dos,crt,moje_jed; [ label NAVESTI1 [,NAVESTI2...] ; ] =================================== Usek deklarace navesti. Navesti se pouzivaji ke skokum z jednoho mista programu na jine (prikaz goto, viz dale). Kazde navesti se musi nejdriv zde definovat. Pokud jich je vic, oddeluji se opet carkou a za poslednim se pise strednik. Identifikator navesti muze byt i samotne cislo, starsi verze Pascalu dokonce ani nepovolovaly pismena. Priklad: label konec,1,loop5; [ const KONSTANTA1 [:TYP] = HODNOTA; [KONSTANTA2...] ] ====================================================== tedy napr: const pi=3.14; atd. Konstanty bez udaneho typu (viz maximalni_X=639; Typy) jsou prekladacem prelozeny na kod_Esc=#27; proste hodnoty. Pokud je konstanta adresa=$00FA; zadana jako vyraz (ktery musi byt BarvaTextu:byte=15; slozeny take ze samych konstant), Jmeno:string[10]='Jouza'; provede se vypocet hodnoty uz pri Stred_y = 480 div 2; prekladu a na rychlost programu to nema vliv. Hodnotu konstanty bez udaneho typu nelze za behu programu menit. Naproti tomu konstanta s udanym typem se chova jako promenna (viz dale), ktere se hned pri deklaraci priradi hodnota a tato hodnota muze byt kdykoli zmenena. Cislo napsane primo v programu se bere take jako konstanta. Konstanty vseho druhu se pouzivaji tam, kde pouzivame jednu hodnotu na vice mistech programu. Kdyz nas pak napadne ji zmenit, nemusime pracne prochazet cely zdrojak, hledat a prepisovat, ale staci zmenit jedno cislo na zacatku. Pokud definujete vic konstant, musi se psat kazda zvlast (jmeno=hodnota i jmeno:typ=hodnota) a za kazdou se pise strednik. [ type TYP1 = DEFINICE; [TYP2 = DEFINICE2;] ] ============================================================================= napr.: type RetezecNa8pismen=string[8]; atd. Kazda promenna (viz dale) musi Souradnice = record mit nejaky typ (viz dale). Nektere x,y:integer; jsou treba cela cisla, jine realna, barvaBodu:byte; pismena, mnoziny, pole, ukazatele, end; retezce znaku, zaznamy nebo objekty. UkazatelNaInt=^integer; V sekci type si muze programator MnozinaPismen=set of char; nadefinovat sve vlastni typy, kdyz uz standardni nestaci. Dela se to tak, ze napiseme identifikator typu, ktery chceme definovat, za nej napiseme znak = a pak nasleduje vlastni definice typu. Definice jednotlivych typu se oddeluji strednikem. [ var PROMENNA1 [,PROMENNA2] : TYP; [PROMENNA3...] ] ==================================================== napr.: var x1, y1, x2, y2 : word; Jeden ze zakladnich kamenu programovani. pPrvni:UkazatelNaInt; Promenne jsou mista v pameti, do kterych se textik:string; ukladaji ruzne hodnoty a pak se daji zase pole:array[1..10]of byte; precist nebo prepsat. Deklaruji se bud alfa,beta:real; v sekci VAR, nebo jako parametry procedur nebo funkci (viz dale). Pokud jsme promennou deklarovali, nema jeste prirazenou zadnou hodnotu. Vetsinou se tam sice objevi nula, ale prakticky by to mohlo byt cokoli. Proto je vzdy nutne promenne pred prvnim pouzitim nejakou hodnotu priradit. Toto se provadi PRIRAZOVACIM PRIKAZEM := . Vlevo napiseme promennou, vpravo hodnotu. V praxi to vypada takto: x1:=50; textik := 'Buhehe...'; alfa:= 3.00E-5; apod. Vsimnete si, ze nezalezi na tom, kolik mezer nebo entru vlozite mezi := a operandy, ale rozhodne nesmite napsat : = . Promenna se deklaruje tak, ze napiseme jeji identifikator, za nej dvojtecku, za ni identifikator typu a nakonec strednik. Typ muze byt definovan primo zde, podobne jako v sekci Type, tedy bud: type pismena = set of char; var p:pismena; nebo rovnou: var p:set of char; begin [PRIKAZ1;] [PRIKAZ2...] end. ======================= Klicove slovo begin zahajuje posloupnost prikazu, slovo end ji ukoncuje. Jednotlive prikazy se pisi mezi ne a oddeluji se stredniky (za begin strednik neni, za poslednim prikazem pred end byt nemusi, ale muze). Dalsi begin a end muzete pouzit prakticky kdekoli v programu, kdyz treba potrebujete napsat slozeny prikaz (viz Prikazy), ale kazde begin musi mit svoje end. Za end na konci programu se pise tecka, uvnitr programu strednik. O procedurach a funkcich si povime pozdeji. Jedine veci, ktere program musi nutne obsahovat je hlavicka, begin a end. Vsechno ostatni tam byt muze, ale nemusi. Poradi jednotlivych sekci v dekla- racni casti (const, var...) je lepe dodrzet kvuli prehlednosti, ale neni to nutne. Muzete i nekterou cast opakovat vickrat, coz se casto pouziva pri deleni zdrojoveho kodu do vice souboru. Dulezitym terminem je blok. Jedna se o cast zdrojoveho kodu, ktera zacina hlavickou, muze obsahovat sekce type, var, atd. a na konci ma posloupnost prikazu ohranicenou begin a end. Blokem je tedy cely program, ale i jednotlive procedury a funkce v nem definovane (vnorene) - viz dale. ****************************************************************************** 2 - Datove typy ****************************************************************************** Uz vime, ze kazda promenna musi mit definovan typ. Ten urcuje, jake hodnoty do ni muzeme vlozit a jak s nimi potom muzeme pracovat. Standardni typy se daji rozdelit do techto skupin: - cela cisla - realna cisla - logicke ano/ne - znaky - vyctove typy - mnoziny - intervaly - pole - retezce - zaznamy - ukazatele - soubory Popiseme si kazdy zvlast. Celociselne typy ================ Do takoveto promenne muzete ulozit prave jedno cele cislo. Jednotlive typy se lisi rozsahem, znamenkem a mistem, ktere zabiraji v pameti. jmeno rozsah velikost v bytech znamenko? ------------------------------------------------------------ byte 0..255 1 ne word 0..65535 2 ne shortint -128..127 1 ano integer -32768..32767 2 ano longint -2147483648..2147483647 4 ano ------------------------------------------------------------ Pak si take musite davat pozor, jake promenne co prirazujete. Pokud mame nadefinovano var i:integer; b:byte; w:word; s:shortint; l:longint;, pak vyrazy l:=i; l:=b; l:=s; i:=s; i:=b; w:=b; budou mit vzdy spravnou hodnotu, ale vyrazy b:=i; b:=s; b:=l; b:=w; w:=l; w:=i; s:=i; atd. mohou vyjit spatne, pokud se hodnota dostane mimo povoleny rozsah promenne. Povolene operace s celymi cisly jsou scitani, odcitani, nasobeni, celociselne deleni (div, mod) a logicke bitove operace (and, or, xor, not, shl, shr). Deleni funguje tak, ze A div B znamena A/B s odriznutym zbytkem. Zbytek po deleni je A mod B. Tedy napr.: writeln(' A:B=',A div B,' a zbytek ',A mod B); (prikaz writeln viz dale, jde o vypis neceho na obrazovku). Logicke operace se provadeji s kazdym bitem cisla zvlast jako s typem boolean (viz dale), 1 odpovida true, 0 false. Shl (shift left) a shr (shift right) posouvaji vsechny bity v cisle doleva nebo doprava, druhy operand urcuje, o kolik. Pokud mame napr. cislo 5, coz je ve dvojkove soustave 00000101, pak 5 shl 3 bude 00101000 (40) a 5 shr 1 bude 00000010 (4). Vysledek je normalni cislo v desitkove soustave. Pokud nejake jednicky presahnou okraj cisla (v prikladu jsme meli osmibitove cislo, typ byte), tak zmizi, a kdybyste je soupli zpet, budou tam uz jen nuly. Definovane je take porovnavani: <, >, <=, >=, <>. Realna cisla ============ Do techto promennych se daji ukladat cisla s pohyblivou desetinnou carkou. Cislo se da napsat napr. -155.255504E-22 , kde . je desetinna tecka a E-22 znamena krat 10 na minus dvacatou druhou, tj desetinna carka je o 22 mist vlevo. Cast s E je nepovinna. Opet pozor na kompatibilitu. Realne promenne muzeme priradit cele cislo, ale obracene bych to radsi nezkousel. Operace s realnymi cisly jsou o neco pomalejsi nez s celymi, takze se snazte radeji pouzivat cela cisla vsude, kde to jde. Zde jsou definovany operace +,-,*, normalni deleni (/) a porovnavani; div, mod ani logicke operace uz ne. Jednotlive typy jsou: jmeno rozsah velikost v bytech -------------------------------------------------------- real 2.9e-39..1.7e38 6 single 1.5e-45..3.4e38 4 double 5.0e-324..1.7e308 8 \ Pokud byste potrebovali extended 3.4e-4932..1.1e4932 10 \ z nejakeho duvodu pouzit comp -9.2e18..9.2e18 8 / takhle velka cisla, musite -------------------------------------------------- prepnout prekladac do rezimu 8087. Logicke ano / ne - typ Boolean =============================== Promenne tohoto typu mohou nabyvat hodnot TRUE (pravda) nebo FALSE (nepravda). V pameti zabiraji obvykle 1 byte. Daji se s nimi provadet tyto logicke operace: and (a), or (nebo), not (negace) a xor. Vyraz A and B plati, pokud A i B jsou pravdive (true), A or B plati, kdyz alespon jeden operand je pravdivy, A xor B je pravdive, jen pokud prave jeden z operandu je pravdivy. Not je unarni operator, not A je opacna hodnota k A. Tento typ je velmi uzitecny. Pouziva se k vetveni programu (if) a v ukonco- vacich podminkach cyklu (repeat, while), viz Prikazy. Vyraz typu boolean ovsem nemusi byt slozen jen z booleovskych promennych. Napr. vyrazy: x>y; keypressed and (readkey=#27); (x1>5) and (x2<=15) and not (b=c) vsechny davaji vyslednou hodnotu typu boolean. POZOR! Zapis A:=2 znamena, ze promenne A prirazujeme hodnotu 2, ale zapis A=2 je vyraz, ktery ma bud hodnotu true, pokud se A rovna dvema, nebo false, pokud se nerovna. Muzeme tedy psat: B:=(A=2); (B je promenna typu boolean) nebo treba C:=(B=(A=2)); (C je take boolean). Presvedcte se sami, ze to opravdu ma smysl. Znaky (pismena) - typ char =========================== Do techto promennych muzete ukladat znaky. Znak se pise mezi apostrofy (napr: 'A', 'x', ' ', '5', '*'), aby bylo jasne, ze nejde o identifikator nebo cislo. Pokud chcete napsat znak apostrof ('), musite ho zdvojit, jinak prekladac mysli, ze jde o konec znaku. Tedy ' = ''''. Znaky jsou usporadany v kodu ASCII. Kazdy znak ma tzv. ordinalni cislo, coz je cislo, ktere urcuje jeho polohu v ASCII tabulce. To umoznuje dalsi zpusob zapsani znaku: #X, kde X je jeho ordinalni cislo. Tedy napr. #5, #0, #65. Pozor ale, ze ne vsechny znaky jsou pismena nebo neco jineho citelneho. Existuji i tzv. ridici znaky (napr. #7), ktere, pokud je nechate napsat, nic nezobrazi, ale provede se nejaka akce. Ordinalni cislo znaku vraci funkce ord(ZNAK), znak z ordinalniho cisla vypocita funkce chr(CISLO). Vyctove typy ============= Jsou pripady, kdy potrebujeme nekam ulozit hodnoty, ktere nejsou cisla, pismena ani nic podobneho. Pak muzeme vytvorit tzv. vyctovy typ, coz je seznam vsech hodnot, kterych mohou promenne daneho typu nabyvat. Napr.: type DenVTydnu = (Po, Ut, St, Ct, Pa, So, Ne); var Den: denvtydnu; Promenne Den pak muzeme priradit hodnoty takto: Den:=Po; nebo Den:=Ut; atd. Typ boolean je takovy specialni pripad vyctoveho typu, ktery by se dal definovat jako type boolean = (false, true); . Vsechny celociselne typy, typy char a boolean a vyctove typy jsou takzvane ORDINALNI typy. To znamena, ze tvori posloupnost a kazdemu prvku je prirazeno ordinalni cislo. U vyctovych typu to je tak, ze prvni ma ord. cislo 0 a kazdy dalsi vzdy o 1 vetsi. Pro vsechny ordinalni typy jsou definovany funkce pred(x), succ(x) a ord(x). Prvni vraci prvek predchazejici x, druha prvek nasledujici a treti ordinalni cislo prvku x. Mnoziny ======== Predpokladam, ze pojem mnozina znate ze skoly, takze jen strucne. Je to souhrn nekolika (nebo zadnych) prvku, z nichz kazdy se v ni vyskytuje pouze jednou. Mnozina se deklaruje zapisem SET OF TYP; kde TYP je typ prvku. Napr.: var Pismena: set of char. Pokud vypisujete prvky mnozin, piste je mezi hranate zavorky ([]), jednotlive prvky oddelujte carkami. S mnozinami jsou definovany tyto operace: Prirazeni - napr Pismena:=['a','b','c']; nebo Pismena:=['a'..'z'];. Dve tecky (..) znamenaji "az". Ve druhem pripade bude tedy mnozina pismena obsahovat vsechny znaky od 'a' do 'z', v prvnim jen 'a','b' a 'c'. Sjednoceni (+) - vysledek obsahuje vsechny prvky, ktere obsahuji sjednocene mnoziny. Napr.: mame mnoziny a,b:set of integer. Priradime a:=[1,2,5,7]; b:=[10,-5,2,6,7]. Pak a+b=[1,2,5,7,10,-5,6]. Prunik (*) - ve vysledne mnozine budou jen prvky, ktere maji spolecne. Tedy a*b=[2,7]. Rozdil (-) - z jedne mnoziny odstrani prvky, ktere najde i v druhe mnozine. a-b=[1,5,7]. A asi nejpouzivanejsi operace - test, jestli je dany prvek v dane mnozine. To se zapisuje PRVEK in MNOZINA a vysledek je typu boolean. Napr.: Cislo in [1,2,5,7]; Cislo in a; 'X' in pismena; atd. Mnozina muze mit maximalne 256 prvku. typ interval ============ Typ interval definujeme takto: type NAZEV_TYPU = DOLNI_MEZ .. HORNI_MEZ; Da se pouzit pro vsechny ordinalni typy a pouziva se, kdyz je potreba nejak omezit hodnoty, kterych muze promenna tohoto typu nabyvat. Kdyz ji zkusite priradit hodnotu, ktera se do intervalu nevejde, skonci to bud hlaskou "Constant out of range" pri kompilaci nebo prerusenim programu a necim podobnym, pokud mate zapnutou kontrolu rozsahu (range checking). Pokud je kontrola vypnuta, program hodnotu zkusi priradit, ale vysledek bude chybny. Se standardnimi celociselnymi typy je to vlastne podobne, jako s intervaly. Napr. typ byte by sel definovat takto: type byte=0..255;. Pozor, neplette si interval s mnozinou! Promenna typu interval obsahuje jednu hodnotu z toho intervalu, mnozina obsahuje nekolik prvku! Pole - typ array ================= Jde o radu nekolika prvku, pricemz kazdemu je prirazeno cislo - index. Typ prvku je libovolny (treba i dalsi pole, pak vznikaji pole vicerozmerna), jen musi byt pro vsechny prvky stejny. Pocet prvku je omezen prakticky jen velikosti pameti a maximalni velikosti promenne (tedy celeho pole) - 64 kB. Deklarace: var A : array [ PRVNI .. POSLEDNI ] of TYP_PRVKU; (napr Pole: array[0..15] of word;) PRVNI je index prvniho prvku v poli, POSLEDNI je index posledniho. Takto si rychle a jednoduse nadefinujete POSLEDNI-PRVNI promennych. Pristup k jednotlivym prvkum se pak provadi takto: (napr.) A[5]:=neco; promenna:=A[16]; Kdyz chcete udelat treba dvojrozmerne pole (matici), muzete to napsat jako var pole: array[1..10] of array[1..12] of integer; nebo zkracene jako var pole: array[1..10,1..12] of integer. Pak k prvkum pristupujeme obdobne: pole[2,5]:=hodnota; neco:=pole[1,1]. Pocet rozmeru neni omezen, jen je pak trochu slozitejsi si to predstavit (4 rozmery a vic) :-). Pole jsou velmi silny nastroj v kombinaci s FOR cyklem (viz dale). Retezce - typ string ===================== Typ retezec je v podstate pole znaku: array[0..255] of char. V nultem znaku je ulozena delka retezce (vzhledem k tomu, ze cely retezec je z prvku typu char, tak delku urcuje ordinalni cislo nulteho znaku), v ostatnich pak vlastni text. Pokud napisete var Retezec:string; , pak se pouzije vychozi delka retezce 255 znaku. To je vetsinou zbytecne moc, takze se da napsat: var Retezec:string[25]; pak vznikne retezec o zadane delce. Retezec se pise mezi apostrofy (jako znaky), napr.: 'Ahoj!' , 'textik 1', apod. Dalsi moznost je opet pres ordinalni cisla: #23#72#15. S retezci jsou definovany operace scitani (+), kde vysledkem je napojeni retezcu ('ahoj'+'covece' + '!' = 'ahojcovece!', vsimnete si, ze s retezci lze scitat i jednotlive znaky), operace porovnani (< , >, =, <>), kde vysledek je typu boolean. Retezce se rovnaji, pokud obsahuji uplne stejny text (vcetne velkych a malych pismen), vetsi nebo mensi se definuje tak, ze vetsi je ten, ktery je druhy, pokud je seradime podle abecedy (resp. ASCII kodu). To se moc casto nepouziva, dulezita je hlavne rovnost. Pr.: ('Ahoj'='Ahoj')=true, ('Bob'<>'bob')=true, ('ABC'<'BC')=true. Retezce se daji skladat i pomoci procedury concat(), vysledek je uplne stejny jako pri pouziti znamenka plus. Retezec nesmi byt rozdelen enterem na vic radku. Kdyz potrebujete napsat tak dlouhy retezec, ze se nevejde na radek, musite ho napsat jako soucet nekolika kratsich retezcu (napr.: 'Tady zacina hrozne dlouhy text, ktery se mi '+ 'nevejde na jeden radek.'). Pozor, ze obsah retezc je presne to, co napisete mezi apostrofy, tedy i mezery. Retezec 'pp' tedy obsahuje jen dve pismena, ale ' pp ' mezeru, pp a na konci druhou mezeru. Vzhledem k tomu, ze retezce se chovaji jako pole, daji se z nich jednotlive znaky cist pomoci indexu: pokud mame var ret:string; pak ret[5] znamena paty znak v retezci. Takto je mozne z retezce jak cist, tak do nej zapisovat. Prazdny retezec se znaci ''. Pokud chcete v retezci napsat apostrof, musite ho opet zdvojit. Tedy 'Mc Donald''s' znamena text Mc Donald's. Pokud byste napsali apostrof jeden, prekladac by to pochopil tak, ze za pismenem 'd' retezec konci, a kdyz pak za nim narazi na dalsi pismena, hlasi chybu. Delku retezce vraci funkce length(RETEZEC). Zaznam - typ record ==================== Pole muze byt slozeno jen z prvku jednoho typu. Co ale delat, kdyz potrebu- jeme vytvorit promennou, ktera obsahuje vice polozek ruznych typu? Pouzijeme zaznam. Definuje se takto: type NECO = record POLOZKA1:TYP1; POLOZKA2:TYP2; ... end; Jednotlive polozky mohou byt promenne jakehokoli typu. K jednotlivym polozkam se dostaneme pomoci tecky. Ukazu to na prikladu. Nadefinujeme si typ kruh: type kruh = record stred_x,stred_y:integer; polomer:word; barva:byte; jmeno:string[16]; end; a promennou: var k1:kruh; Nyni priradime hodnoty: k1.stred_x:=320; k1.stred_y:=240; k1.barva:=14; k1.polomer:=50; k1.jmeno:='Muj kruh'. Zapis se da zkratit pouzitim prikazu WITH: with k1 do begin Takto do promenne k1 vstoupime stred_x:=320; stred_y:=240; jen jednou a jednotlive polozky polomer:=50; barva:=14; muzeme psat bez jakehokoli oznaceni. jmeno:='muj kruh'; Ovsem pozor. Kdyby existovala end; nejaka globalni nebo jina promenna se stejnym jmenem jako jedna z polozek, pak byste se na ni uvnitr prikazu with nedostali. (lokalne definovane veci maji prednost - viz dale) Proto si davejte pozor, co vsechno do prikazu with pisete. Polozka typu zaznam muze byt i typu zaznam. Potom se k polozkam takove po- lozky dostaneme stejnym zpusobem: ZAZNAM.POLOZKA_TYPU_ZAZNAM.POLOZKA_POLOZKY; Specialnim pripadem zaznamu jsou objekty, o tech si prectete v jinem navodu. Typ zaznam v kombinaci s typem ukazatel je velmi uzitecny pri vytvareni dynamickych struktur, ale o tom take jinde. Typ ukazatel - POINTER nebo ^TYP ================================ Promenna typu ukazatel obsahuje adresu neceho v pameti. Ukazatele mohou byt definovany jako ukazatele na typ, pak mohou ukazovat jen na promenne jednoho konkretniho typu, nebo jako beztypove. Prvni typ se definuje takto: type UKAZATEL = ^TYP; napr. UkNaInt = ^integer; a pak treba: var u1:uknaint; Druha varianta se napise jako typ pointer: var PROMENNA: pointer; Rozdil je ten, ze na vytvareni a ruseni dynamickych promennych pomoci typovych ukazatelu pouzivame prikazy new(), dispose(), mark() a release(), kdezto u beztypovych si musime vystacit s prikazy getmem() a freemem(), u kterych musime zadat i velikost v bytech. Ukazatel, ktery neukazuje na nic, ma hodnotu NIL. Kdyz mame deklarovanou promennou typu ukazatel (napr. U) a v programu se chceme dostat k datum, na ktera ukazuje, piseme U^. Kdyz napiseme samotne U, znamena to, ze pracujeme jen s tim ukazatelem. Priklad: var p,q:^integer; begin new(p); {vytvoreni dynamicke promenne a nastaveni p tak, aby na ni ukazovalo} p^:=100; {prirazeni hodnoty cislu, na ktere p ukazuje} q:=p; {q ted ukazuje na to same cislo jako p, p^=q^=100} q^:=200; {p^=q^=200} dispose(p); {zruseni dynamicke promenne p^, neplatna je tim padem i hodnota q^} q:=nil; {promenna q predtim stale jeste ukazovala do mista, kde byvala end. dynamicka promenna. Ted uz ne.} Pouziti ukazatelu nema cenu vysvetlovat obecne, lepe to jde na konkretnich prikladech a navodech. Podrobne se o nich rozepisu v navodu na tvorbu dynamickych struktur (viz soubor UKAZ.TXT). Tady trochu odbocim. Normalni promenne deklarovane v sekci VAR se nazyvaji staticke. V pameti (zasobniku) se vytvori v okamziku, kdy jsou deklarovany a odstrani se na konci bloku, ve kterem byly deklarovany. Prace s nimi je rychla, protoze jejich adresy jsou pevne dane. Ale vsechny musi byt definovany behem psani programu. Casto se ale stane, ze potrebujeme vytvorit promennou za chodu programu (napr. tvorba seznamu apod.). Tady pouzijeme ty dynamicke promenne. Poznamka: ve starsich publikacich se misto ^ pise sipka. Nenechte se zmast, znamena to totez. Typy soubor - FILE, FILE OF, TEXT ================================== Kdyz chcete zapsat data na disk, zapisujete je do souboru. Stejne je pak zase ctete. Tady popisu zakladni ukony prace se soubory. Popisu tu i cinnost potrebnych procedur, takze pokud jeste nevite, co procedura je, prectete si nejdriv kapitolu Procedury. Typy souboru jsou: 1) Typovy soubor. Deklaruje se takto: var f : file of TYP; kde TYP je jakykoli typ krome souboru nebo objektu. Do tohoto souboru lze velmi jednoduse psat pomoci procedury Write() a cist procedurou Read(). Nevyhodou je, ze mohou obsahovat pouze data jednoho typu. 2) Netypovy soubor. Deklarace: var f : file; Do nej lze zapsat prakticky cokoli, ale musime nejdriv presne vedet, jak je to cokoli velike (v bytech). Zde pouzivame procedury Blockwrite a Blockread. 3) Textovy soubor. Deklarace: var f : text; Toto je specialni pripad typoveho souboru. Je to vlastne file of char, ale ma nekolik specifickych vlastnosti. Krome procedur Read() a Write() se do nej da psat i procedurou Writeln() a cist pomoci Readln(). Nejdulezitejsi operace, ktere se daji se soubory provadet, jsou tyto: * Prirazeni fyzickeho souboru promenne typu soubor. Pouziva se procedura Assign(F,CESTA), kde F je promenna typu soubor a CESTA je jmeno souboru na disku (typ retezec). Pokud neni ve stejnem adresari jako program, tak vcetne cesty. Tato operace je nutna, jinak je vam promenna typu soubor na nic. Jeden z dusledku je, ze pomoci jedne promenne muzeme postupne obslouzit vic souboru (samozrejme ne najednou). * Otevreni souboru pro cteni. Procedura Reset(F [,VELIKOST] ). F je promenna typu soubor, ktera uz ma prirazeny fyzicky soubor. Druhy parametr VELIKOST se pouziva jen u netypovych souboru a urcuje velikost bloku dat, ktere se ze souboru ctou. U typovych a textovych souboru se o takove veci starat nemusite, tam to za vas udela program sam na zaklade udaneho typu. Procedura otevre soubor a "kurzor" nastavi na zacatek. * Otevreni souboru pro zapis. Procedura Rewrite(F [,VELIKOST] ). Parametry funguji stejne jako pri otvirani pro cteni. Prikaz Rewrite vymaze cely obsah souboru (Pozor!) a "kurzor" nastavi na zacatek. * Otevreni souboru pro pripisovani na konec. Procedura Append(F). F je promenna typu text (textovy soubor), na jine to nejde. Obsah souboru zustane zachovan a "kurzor" se nastavi za posledni znak v souboru. * Zavreni souboru. Procedura Close(F), F je promenna typu soubor. Timto zavrete otevreny soubor. Toto je nezbytne nutne. Pascal sice automaticky vsechny otevrene soubory pri skonceni programu zavira, ale nespolehal bych na to a hlavne, kdyz mate napr. soubor otevreny pro cteni, neco z nej prectete a pak ho chcete prepsat, musite ho nejdriv zavrit a pak teprve otevrit pro zapis. Dalsi duvod je ten, ze pocet najednou otevrenych souboru je omezen. * Cteni ze souboru. Z typovych souboru cteme pomoci procedury Read(F,KAM); kde F je promenna typu soubor, otevrena pro cteni procedurou Reset a KAM je promenna stejneho typu, jako obsah souboru, do ktere se nacte jedna hodnota ze souboru. Po precteni hodnoty se "kurzor" posune o jednu pozici v souboru dal. Z textovych souboru cteme stejne, ale muzeme cist jak znaky, tak i retezce a cisla. Funguje to uplne stejne, jako kdyz neco ctete z klavesnice (ktera se v podstate chova jako textovy soubor), jenom musite jako prvni parametr pro- cedury uvest dany soubor a az jako druhy promennou, do ktere se ma prectena hodnota ulozit. Z netypovych souboru cteme pomoci Blockread(F,KAM,POCET). F je promenna typu file, KAM je promenna, do ktere se ze souboru cte a POCET je pocet bloku, ktere se maji precist. POCET je typu word. Velikost bloku jste definovali pri otevirani rouboru, takze VELIKOST * POCET = velikost promenne KAM v bytech. Procedure Blockread muzete zadat jeste ctvrty parametr (promennou typu word), do ktereho vraci pocet bloku, ktere se skutecne precetly. Pokud neni na konci operace stejny jako parametr POCET, je tu chyba. * Zapis do souboru. Do typovych souboru piseme takto: Write(F,CO); CO je hodnota prislusneho typu, kterou do souboru zapisujeme. Do textovych souboru muzeme krome toho psat i procedurou Writeln(F,CO), rozdil je jen v tom, ze po zapsani hodnoty CO zapise jeste znak konce radku. Je to stejne, jako vypis na obrazovku v textovem rezimu, ktera se vlastne take chova jako textovy soubor. Do netypovych souboru piseme procedurou Blockwrite(F,CO,POCET), kde CO je neco, co chceme do souboru zapsat a pocet je opet pocet bloku, takze celkem se zapise POCET * VELIKOST bytu. Hodnota CO by mela mit prave takovou velikost. Take zde muzeme zadat jeste ctvrty parametr, ktery rika, kolik bloku bylo doopravdy zapsano. * Prejmenovani souboru. Procedura Rename(F,JMENO), F je promenna typu jakykoli soubor (s prirazenym fyzickym souborem) a JMENO je typu retezec a udava nove jmeno fyzickeho souboru. Promenna F zustane prirazena prejmenovanemu souboru. * Smazani souboru. Procedura Erase(F), F je to same jako minule. Fyzicky soubor prirazeny promenne F je smazan z disku. Mazany soubor nesmi byt otevreny. Tak, to je asi vsechno. Na kopirovani souboru zadny standardni prikaz neni, ten si musite napsat sami. Doporucuji otevrit napovedu k prikazu Blockwrite, zkopirovat si priklad, a je to :-). ****************************************************************************** 3 - Prikazy ****************************************************************************** Nejdulezitejsi zakladni kameny kazdeho programu. Prikaz znamena instrukci nebo posloupnost instrukci, ktere ma pocitac provest. Muze byt jednoduchy (napr. p:=1;), slozeny (napr. begin a:=5; x1:=62 end;) nebo i jinak struktu- rovany. Tady si popiseme nejdulezitejsi prikazy, ktere budete urcite potrebovat. Vsechny prikazy se v programu pisi az mezi BEGIN a END, ne v deklaracnich sekcich. Za kazdym prikazem nasleduje strednik. Existuje i prazdny prikaz, coz znamena, ze proste nenapisete nic. Je potreba vedet, ze to existuje. Nekdy chcete treba jen pockat na stisk klavesy. Napisete repeat until keypressed; (cyklus repeat - viz dale) a vysledek bude, ze se nebude delat nic, dokud se nestiskne nejaka klavesa. Prikaz prirazeni (:=) uz byl vysvetlen v sekci Promenne, takze uz se k nemu vracet nebudu. Snad jen dodam, ze oba operandy museji byt stejneho nebo alespon kompatibilniho typu. [Takhle] znacim ty casti prikazu, ktere muzou byt vynechany. Prikazy vetveni ================ Casto se stane, ze potrebujeme na zaklade nejake podminky rozhodnout, co se ma stat dal. Zde pouzijeme Prikaz IF ---------- Syntaxe: if PODMINKA then PRIKAZ1 [ else PRIKAZ2 ]; Funguje to tak, ze za behu programu se otestuje PODMINKA, coz je libovolny vyraz typu boolean, a v pripade, ze ma hodnotu true (pravda), provede se prikaz PRIKAZ1. Pokud PODMINKA neni pravdiva (false) a byl uveden dodatek else, pak se provede PRIKAZ2, pokud uveden nebyl, neprovede se nic. Pr.: if a''; Nebo: ... var o:char; ... o:='x'; repeat Tohle bude pipat tak dlouho, dokud sound(random(1000)+20); nestisknete Esc. delay(300); if keypressed then o:=readkey; until o=#27; repeat Tohle jenom ceka repeat Priklad neko- until keypressed; na stisk klavesy. until false; necne smycky. (tohle doma nezkousejte :-) ) Cyklus WHILE ------------- while PODMINKA do PRIKAZ; PODMINKA je opet vyraz typu boolean. PRIKAZ se na rozdil od cyklu repeat opakuje tak dlouho, dokud PODMINKA plati. Dalsi rozdil je v tom, ze mezi repeat a until muzete psat kolik prikazu chcete, u while se da napsat jen jeden, takze kdyz jich potrebujete napsat vic, musite pouzit slozeny prikaz (begin a end). Poznamka: u cyklu repeat se prikazy vzdy aspon jednou provedou, pak se teprve kontroluje podminka. U while se NEJDRIV kontroluje podminka, a kdyz neplati, tak se prikaz nemusi provest ani jednou. Priklady: ... var ch:char; ... while keypressed do ch:=readkey; Dokud je stisknuta nejaka klavesa, tak ji cte. Kdyz ne, konci. ... var r:string; i:integer; ... readln(r); i:=0; Tohle necha z klavesnice zadat retezec. while length(r)<30 do begin Pokud je kratsi nez 30 znaku, pripisuje r:=r+' '; k nemu mezery tak dlouho, dokud neni i:=i+1; presne 30 znaku dlouhy. Za kazdou pripsanou end; mezeru pak o 1 zvysi hodnotu promenne i. Cyklus FOR ----------- 1) for PROMENNA := MIN to MAX do PRIKAZ; Kdyz vite, kolikrat presne 2) for PROMENNA := MAX downto MIN do PRIKAZ; chcete cyklus opakovat, je for cyklus spravna volba. PROMENNA je tzv. ridici promenna cyklu. Muze mit libovolny ordinalni typ. Cyklus funguje tak (v pripade 1), ze nejdriv se ridici promenne priradi hodnota MIN a provede se PRIKAZ. Potom se hodnota PROMENNE o 1 zvysi (resp. priradi se nasledujici prvek u neciselnych typu) a PRIKAZ se provede znovu. Naposledy se PRIKAZ provede pro PROMENNOU rovnou MAX. Pokud MIN = MAX, pak se cyklus projede jen jednou, pokud MIN > MAX, je to chyba. Kdyz z nejakeho duvodu potrebujete, aby hodnota PROMENNE misto stoupani klesala, misto TO napiste DOWNTO (pripad 2), pak se jede od MAX do MIN. Ridici promenna se velmi casto nejak vyuziva uvnitr PRIKAZU. Jenom radeji nezkousejte menit behem provadeni cyklu jeji hodnotu, mohlo by to vest k chybam. Priklady: ... var i:integer; ... for i:=0 to 15 do begin Tohle postupne meni i od 0 do textcolor(i); 15. Pro kazdou hodnotu nastavi writeln('Barva ',i); odpovidajici barvu textu a vypise end; na obrazovku tou barvou slovo Barva a za nej aktualni hodnotu i. var z:char; ... for z:='Z' downto 'A' do write(z); Tohle jen napise abecedu pozpatku. var a:array[1..40] of boolean; For cyklus je velmi uzitecny ... a vykonny v kombinaci s typem for i:=1 to 40 do if a[i] then neco_proved; pole (array). Vic typu cyklu nastesti neni. Jeste mala poznamka na zaver: prave prova- deny cyklus se da okamzite ukoncit prikazem Break;. Ten zpusobi skok na prvni prikaz, ktery v programu nasleduje za cyklem. Nedoporucuje se ale pouzivat ho prilis casto, protoze jednak zhorsuje prehlednost programu a jednak skakani neni z hlediska hladkeho chodu programu zrovna idealni (dela neporadek v zasobniku a podobne). Prikaz WITH ============ Umoznuje jednodussi zapis operaci s polozkami zaznamu, Hodi se hlavne ve chvili, kdyz jich je mnoho. Byl popsan v sekci Datove typy, u typu zaznam. Prikaz skoku - GOTO ==================== label NAVESTI; Prikaz goto umoznuje skocit na dane navesti. Vsechna ... navesti musi byt nejdriv deklarovana v sekci label. goto NAVESTI; Do programu se navesti vklada tak, ze se napise ... pred nejaky prikaz a oddeli se od nej dvojteckou. NAVESTI: PRIKAZ; Kdyz program narazi za behu na navesti, nic se nedeje a prikaz za nim se normalne provede. Kdyz dostane povel ke skoku na toto navesti, tak na nej skoci a PRIKAZ provede. Jednoduche a ucinne. V cem je hacek? Program rychle ztraci na prehlednosti a pro ostatni lidi byva jeho cteni hlavolamem. Proto byste meli skoky pouzivat co nejmene a radeji se snazit vsechno napsat pomoci vyse uvedenych strukturovanych prikazu. Jedno nepsane pravidlo rika, ze slusny programator nepouziva navesti vubec. Skakat muzete dopredu i dozadu, ale jen v jednom bloku (tj. neda se treba vyskocit z procedury do hlavniho programu). A o hladkosti chodu programu plati totez, co pro Break: fuj! Kazdy slozeny prikaz si na zacatku ulozi nejake hodnoty na zasobnik a na konci je zase zrusi (treba pozici v programu, na kterou se ma procesor vratit po dokonceni prikazu) a kdyz z takoveho prikazu vyskocite pomoci Goto, zasobnik se nevyklidi a po nejake dobe chodu takoveho programu se pak muze i zaplnit - tech 16 kB neni moc. Prikaz volani procedury ======================== Procedura se vola tak, ze se jeji jmeno proste napise jako prikaz. Viz dale. ****************************************************************************** 4 - Procedury ****************************************************************************** Dalsi pilir, na kterem Pascal stoji. Procedura je v podstate podprogram se vsim vsudy - hlavicka, deklaracni cast a prikazy. Hlavni vyznam procedur je v tom, ze si ji jednou nadefinujete a pak ji muzete pouzit kdekoli a kolikrat chcete misto toho, abyste celou tu hromadu prikazu psali vzdy znova. Deklarace: procedure JMENO [ ( SEZNAM PARAMETRU ) ]; [label, const, type, var, procedure, function - normalni deklaracni cast] begin [ PRIKAZ; PRIKAZ; ... ] end; Prvni radek je tzv. hlavicka. Zacina klicovym slovem PROCEDURE, ktere znamena, ze se bude definovat procedura. Za nim nasleduje identifikator procedury (JMENO), ktere slouzi k jejimu vyvolani v programu. Na konci hlavicky muzou byt v zavorce uvedeny parametry. Po hlavicce nasleduje bezna deklaracni cast, stejna jako ta v normalnim programu. Rozdil je v tom, ze tady neni cast USES a ze vsechno, co definujeme v procedure, je definovano lokalne. To znamena, ze to existuje jen od chvile volani procedury do chvile, kdy procedura skonci. (kdyz je neco definovano v hlavnim programu, rikame, ze je to definovano globalne) Pokud se jmeno cehokoli lokalne definovaneho shoduje se jmenem neceho definovaneho globalne, pak pokud tento identifikator v procedure pouzijete, mysli se jim vzdy ten lokalni vyznam. Pak nasleduje slovo begin a za nim posloupnost prikazu, pro kterou plati stejna pravidla jako pro hlavni program. Na konci je end, ale neni za nim tecka jako na konci programu, ale jen strednik. Tady napisu priklad procedury, na ktere vsechno vysvetlim: procedure WriteXY (x,y:word; barva:byte; textik:string; var VysloTo:boolean); const cerna=0; {definice lokalnich konstant - barvy} seda=7; maxx=80; {maximalni hodnota x-ove souradnice} begin vysloto:=(x+length(textik) <= maxx); {kontrola, jestli textik nepresahuje pres okraj obrazovky} if barva=cerna then barva:=seda; {tohle zajisti, aby se text nepsal cerne na cerne pozadi} textcolor(barva); {nastaveni barvy textu} if not vysloto then x:=maxx-length(textik); {pokud textik precuhuje, posune ho tohle doleva} gotoxy(x,y); {posun kurzoru na dane souradnice na obrazovce} write(textik); {napsani textiku} end; {konec procedury WriteXY} A priklad pouziti (zkuste si ho spustit): program pokus; {hlavicka programu} var b:boolean; {nadefinujeme si par globalnich promennych} tx:word; x:word; begin {zacatek programu} tx:=77; {zadani hodnoty promenne tx} writexy(tx,10,4,'Ahoj!',b); {volani procedury Writexy} if not b then begin {zuzitkovani vysledku ulozeneho v promenne b} gotoxy(0,0); write('(text se musel posunout)'); end; repeat until keypressed; {a pockame na stisk klavesy, abychom si vysledek stacili precist} end. {konec programu} Prvni, co nas prasti do oci, je zavorka v hlavicce. V ni jsou uvedeny tzv. formalni parametry. Pomoci parametru procedure zadavate hodnoty, se kterymi ma pracovat, ve chvili, kdy ji volate. U formalniho parametru musi byt vzdy uveden typ. Pokud je vice parametru stejneho typu, muzete typ uvest jen jednou, v takovem pripade jednotlive parametry oddelime carkou (viz parametry x,y:word). Kdyz potrebujete pripsat parametr jineho typu, udelate za predchozim parametrem strednik a napisete dalsi (viz parametry barva:byte; textik:string). (pozn.: vsimnete si, ze nemuzeme parametr Textik pojmenovat Text, protoze to je identifikator typu textovy soubor) Do takto definovanych formalnich parametru v okamziku volani procedury vlozite nejakou hodnotu - skutecny parametr. Muze to byt primo zadana hodnota, konstanta, volani funkce, promenna nebo jiny vyraz. Formalni parametr se uvnitr procedury chova jako lokalni promenna a jako s promennou s nim zde lze take zachazet. Dulezite je, ze pokud vlozite jako skutecny parametr promennou, jeji hodnota se vlozi do prislusneho formalniho parametru, ale dalsi operace s parametrem hodnotu teto promenne neovlivni. V nasem priklade tedy zmena hodnoty formalniho parametru x nema vliv na hodnotu promenne tx. Take globalni promenna x zustane nezmenena, protoze lokalne definovana promenna "ma vzdy prednost", pokud se na ni v bloku, kde je definovana, odvolavame. Uplne jina situace nastava u parametru, pred ktere napiseme klicove slovo VAR. Jako skutecne parametry pak muzeme uvadet pouze promenne. Ale hlavne: tady operace s formalnim parametrem PRIMO MENI HODNOTU PROMENNE! V prikladu je takto zadan parametr VAR vysloto:boolean. Tady jako skutecny parametr nestaci zadat nejakou konstantu nebo vyraz, musi to byt jedine promenna typu boolean. Kdyz v procedure priradime formalnimu parametru VysloTo hodnotu, zmeni se take hodnota globalni promenne b. Pokud chceme jako parametr zadat soubor, pak to musi byt vzdy VAR parametr. Proceduru muzeme volat i z ni same - rekurzivne. Napriklad odkryvani policek ve zname hre Hledani min. Mame treba proceduru OdkryjPolicko(x,y:byte); kde x a y jsou jeho souradnice. Take jsme nekde definovali proceduru VykresliPolicko(x,y:byte), ktera umi policko nakreslit a herni plan 30*30 po- licek: var Pole:array[1..30,1..30] of byte. Hodnoty policek pak jsou: 0 - nic, 1..8 - cislo, 9 - mina. Kod odkryvaci procedury muze vypadat treba takto: procedure OdkryjPolicko(x,y: byte); begin case Pole[x,y] of 0: begin VykresliPolicko(x,y); OdkryjPolicko(x-1,y-1); {Pokud kolem policka neni} OdkryjPolicko(x,y-1); {ani jedna mina, odkryji } OdkryjPolicko(x+1,y-1); {se automaticky vsechna } OdkryjPolicko(x-1,y); {policka v okoli. } OdkryjPolicko(x+1,y); OdkryjPolicko(x-1,y+1); OdkryjPolicko(x,y+1); OdkryjPolicko(x+1,y+1); end; 1..8: vykreslipolicko(x,y);{nekde v okoli policka jsou miny} 9: begin {prave jste slapli na minu} vykreslipolicko(x,y); ZobrazHlasku('Game Over!'); end; end; end; Jen si davejte pozor, abyste se nedostali nejakou nezvladnutou smyckou do nekonecne rekurze. To zpusobi preteceni zasobniku a spadnuti programu. Napr. v teto ukazce bychom museli provest s odkrytym polickem jeste neco, aby uz neslo odkryt podruhe, dejme tomu, ze procedura VykresliPolicko by policku priradila treba hodnotu 10. Jinak by se stalo, ze odkryti jednoho policka zpusobi odkryti druheho policka, ktere opet odkryje prvni policko a tak porad dokola. Pokud z nejakeho duvodu v programu definujete dve procedury, ktere se volaji jedna z druhe navzajem, musite nejdriv nejak obejit pravidlo, ze vsechno se musi pred prvnim pouzitim definovat. To se dela pomoci direktivy FORWARD. Priklad: Procedura2(x:byte); forward; Cela hlavicka procedury, ktera je definovana az za procedurou, ve ktere Procedura1; uz se pouziva, se napise pred ni. begin Za ni se pripise forward;. A je to. ... procedura2(neco); ... end; Procedura2(x:byte); begin ... procedura1; ... end; Jeste drobnost na zaver: prave provadenou proceduru lze okamzite ukoncit prikazem EXIT. Ten zaridi zruseni vsech lokalnich zalezitosti definovanych v teto procedure a skok na prvni prikaz za ni. Obcas se hodi, zvlaste u dlouhych a slozite rozvetvenych procedur, ktere potrebujete ukoncit z nekolika ruznych mist. ****************************************************************************** 5 - Funkce ****************************************************************************** Funkce jsou podobne utvary jako procedury, s jednim rozdilem: zatimco proceduru volame jako prikaz, funkci volame jako hodnotu. To znamena toto: muzeme napsat writeln('Cau'); . To je procedura. Ale nemuzeme napsat sin(x);. To je totiz funkce. Misto toho piseme napr. a:=sin(x); Volani funkce se tedy povazuje za vyraz. (naopak napsat textik:=readln(neco); nejde, readln je procedura) Deklarace funkce je podobna, jen na konci hlavicky jeste musime uvest, jaky typ vysledne hodnoty funkce vraci a nekde v prikazove casti funkce uvest prikaz, ktery ji priradi nejakou hodnotu. Jinak pro parametry a podobne veci plati vsechna pravidla uvedena pro procedury. Priklad: function tg(x:real):real; {funkce ma jeden vstupni parametr x a vraci begin hodnotu typu real} tg:=sin(x)/cos(x); {prikaz, ktery priradi funkci hodnotu} end; Funkce samozrejme mohou byt daleko komplikovanejsi, mit hromadu lokalnich definic atd. Nekdy jsou naopak jednoduche nebo ani nemaji parametry (napr. funkce readkey, keypressed, ioresult a dalsi). Typ vysledne hodnoty funkce nesmi byt nic sloziteho, tedy array, record, file, object apod. Jinak celkem cokoli (treba char,string,integer,pointer...) I funkce lze volat rekurzivne a definovat s direktivou Forward (viz procedury). Vzhledem k tomu, ze se procedury a funkce chovaji jako male programy, muzeme si v nich lokalne nadefinovat i cele dalsi procedury nebo funkce (tomu se rika vnoreni): procedure neco; Vzhledem k tomu, ze dlouhe function cti; {lokalne definovana funkce} lokalni definice zhorsuji begin prehlednost, doporucuji u ... kazdeho Begin a End napsat end; komentar, ke ktere procedure begin {zacatek procedury Neco} patri. Take se hodi celou cast ... lokalnich definic nejak zvyraznit, cti; treba odsazenim nebo pripsanim ... prazdnych komentarovych zavorek end; {konec procedury Neco} pred kazdy radek... jak chcete. Vnoreni muze byt i vicenasobne (v lokalni procedure definovana "jeste lokalnejsi" procedura). Prikaz Exit funguje i u funkci. ****************************************************************************** 6 - Struktura jednotky ****************************************************************************** Urcite procedury, typy apod. casto pouzivame ve vice programech. Bylo by neprakticke definovat vse v kazdem programu znovu, proto existuji tzv. jednotky (unity). Struktura vypada takhle: unit JMENO; interface [uses, const, type, var, procedure, function...] implementation [uses, const, type, var, procedure, function...] [begin] [PRIKAZ...] end. unit JMENO ----------- Hlavicka jednotky. Na rozdil od programu se JMENO musi shodovat se jmenem vysledneho souboru, a tedy smi mit maximalne 8 znaku. interface ---------- Timto klicovym slovem zacina verejna deklaracni cast jednotky. Vypada stejne jako deklaracni cast obycejneho programu, jenom misto procedur a funkci se zde uvadeji pouze jejich hlavicky. V programu staci za klicove slovo USES uvest jmeno jednotky, kterou ma program pouzivat, a veskere veci definovane ve verejne casti jednotky budou v programu pristupne, jako by byly definovany primo v nem. implementation --------------- Zde nasleduje neverejna cast jednotky. Cokoli definujete tady, zustava pristupne jen v teto jednotce a zadny program, ktery ji pouziva, se k tomu nedostane. K cemu to je? Setri se pamet, zabranuje se kolizim nazvu a podobne. Take jsou zde vypsany cele procedury a funkce, jejichz hlavicky jste uvedli ve verejne casti (i s hlavickou). begin ... end. --------------- Tady je nepovinna inicializacni cast jednotky. Pisou se do ni normalni prikazy, jako do programu. Vsechny se provedou automaticky ve chvili, kdy spoustime program, ktery jednotku pouziva. Tato cast neni nutna, misto ni se muze napsat pouze end. a zadne instrukce se neprovedou. Pokud ma program v sekci USES uvedeno vice jednotek, ktere maji v iniciali- zacni casti nejake prikazy, provadi se postupne v poradi, v jakem jsou jednotlive jednotky za USES vypsany. Jednotka muze pouzivat jinou jednotku. Programovy kod pouzivane jednotky se pri startu programu provadi take, i kdyz tuto jednotku program primo nepouziva. Pokud jednu jednotku pouziva primo program i jina jednotka, kterou program pouziva take, provede se jeji inicializacni cast pouze jednou, a to v ramci jednotky, ktera ji pouziva (kdyz jde o presnost, cestina jde stranou :-) ). Kdyz v jednotce do casti uses napisete nejakou dalsi jednotku, neznamena to, ze ji bude pouzivat i program, ani kdyz je napsana ve verejne casti. Priklad: unit Pokus; {jednotku nesmime ulozit pod jinym jmenem nez POKUS.PAS} interface {zacatek verejne deklaracni casti} uses dos; {v teto jednotce je definovan typ pathstr=string[79], ktery je pouzit uz ve verejne casti} var i:integer; {tato promenna bude ve vsech programech pouzivajicich jednotku Pokus pristupna, jako bychom ji v nich definovali} function ExistujeSoubor(s:pathstr):boolean; {hlavicka funkce, ktera bude v programech pristupna. Vlastni deklarace funkce nasleduje az v implementacni casti} implementation {zacatek neverejne casti} uses crt; {tuto jednotku nebylo nutne uvadet ve verejne casti, protoze tam se nevyskytovalo nic, co by ji potrebovalo} const x=2; {tyto konstanty nebudou v programech pristupne, muzou je y=10; pouzivat jen procedury, funkce a inicializacni cast v teto jednotce} procedure VypisHlaseni(hl:string); {neverejna procedura, ktera slouzi jen begin uvnitr jednotky Pokus} gotoxy(x,y); writeln(hl); end; function ExistujeSoubor(s:pathstr):boolean; {a konecne definice cele funkce ExistujeSoubor} var f:file; {lokalni promenne, ktere jsou pristupne jen uvnitr vPoradku:boolean; teto funkce, jsou v pameti vytvoreny v okamziku volani funkce a po jejim skonceni jsou odstraneny} begin {zacatek prikazove casti funkce} {$I-} {direktiva prekladace, ktera vypina automatickou kontrolu operaci vstupu a vystupu. Vypnuti je nutne pro spravnou praci funkce ioresult} assign(f,s); reset(f); {viz kapitolu Datove typy, cast Soubory} close(f); vporadku:=(ioresult=0); {pokud ioresult=0, tak se soubor podarilo otevrit i zavrit, a tudiz existuje. Pokud ioresult<>0, tak se to nepovedlo a soubor neexistuje.} if vporadku then vypishlaseni('Soubor '+s+' existuje.') else vypishlaseni('Soubor '+s+' neexistuje.'); end; {konec funkce Existujesoubor} BEGIN {priklad na pouziti inicializacni sekce} clrscr; writeln('Jednotka Pokus se hlasi!'); END. Pouziti jednotky: program Uvidime_jestli_to_funguje; uses pokus, {program pouziva jednotku Pokus} crt; {tahle jednotka je tu kvuli proceduram Sound, Delay a Keypressed} BEGIN if existujesoubor('TURBO.EXE') then begin sound(500); delay(300); nosound; end; {ukazka pouziti procedury z jednotky} repeat until keypressed; {pockani na stisk klavesy} END. Po spusteni programu se na obrazovce objevi napis Jednotka Pokus se hlasi!, pak se nekde uprostred obrazovky vypise hlaseni funkce ExistujeSoubor a pokud soubor existuje, tak program jeste navic zapipa.Po stisknuti klavesy se konci. ****************************************************************************** 7 - Vysvetleni nejpouzivanejsich standardnich procedur a funkci ****************************************************************************** Napisu vzdy zjednodusenou hlavicku dane veci a pak vysvetlim, jak to pracuje. Vstup z klavesnice -------------------- * function KeyPressed : boolean; (z jednotky Crt ) Kdykoli stiskneme klavesu na klavesnici (mimo Shift, Ctrl, Alt a Locky), ulozi se jeji kod do vyrovnavaci pameti klavesnice ve forme znaku - char. Funkce Keypressed vraci hodnotu true v pripade, ze tu nejaky znak najde. Kdyz delsi dobu klavesnici nekontrolujete, muze se stat, ze tam bude nastra- dano znaku vic. * function ReadKey : char; (z jednotky Crt ) Tato funkce precte jeden znak z vyrovnavaci pameti klavesnice a zaroven ho z ni vymaze. Kdyz tam nejaky je (keypressed=true), pak je precten okamzite, pokud ne (keypressed=false), pak se na stisk klavesy ceka. Pozor, ze specialni klavesy (F-neco, sipky a cudliky pro pohyb kurzoru) nedavaji jeden znak, ale dva: znak #0 a po nem kod prislusne klavesy. * procedure Read ( [var soubor: file of neco;] var X [, X2...] ); Univerzalni procedura pro cteni z typovych souboru. Klavesnice se chova jako textovy soubor a je ji standardne prirazen vstupni soubor Input. X je typu char, string nebo nejake cislo. Funguje tak, ze pocka, az na klavesnici neco napisete a stisknete enter. To, co jste tam napsali, se ulozi do promenne X. Muzete napsat i vic parametru a oddelit je carkami. To se hodi hlavne pri cteni ze souboru, kdyz ctete vic veci po sobe (pri cteni ze souboru musite jako prvni parametr uvest soubor). (Viz take Datove typy - typove soubory) * procedure ReadLn ( [var soubor: text;]var X [,X2...] ); To same s tim rozdilem, ze pote, co stisknete enter, se kurzor nastavi na zacatek noveho radku. Readln napsane jen s parametrem soubor pouze skoci na zacatek noveho radku v souboru, Readln napsane uplne bez parametru znamena cekani na stisk klavesy enter. (Viz take Datove typy - textove soubory) Vystup na obrazovku v textovem rezimu ----------------------------------------------------- * procedure GoToXY (x,y:byte); (z jednotky Crt ) Umisti textovy kurzor na dane souradnice na obrazovce (nic nepise). Levy horni roh obrazovky ma souradnice 1,1, pravy dolni obvykle 80,25. * procedure Write ([var soubor: file of neco;] X [, X2...] ); Univerzalni procedura pro zapis do typovych souboru. Obrazovka se chova jako textovy soubor a je ji standardne prirazen vystupni soubor Output. Procedura Write vypise obsah parametru X na aktualni pozici kurzoru na obrazovce. Kdyz se text nevejde na radek, pokracuje se na dalsim. Kurzor zustane za poslednim napsanym znakem. X je typu char, string, boolean nebo nejake cislo. Kdyz na- pisete vic parametru a oddelite je carkami, vypisi se postupne vsechny. (Viz take Datove typy - typove soubory) * procedure WriteLn ([var soubor: text;] X [, X2...]); To same, ale po napsani X se skoci na zacatek noveho radku (kdyz je vic parametru, napisi se vsechny a az potom se ukonci radek). Writeln napsane bez parametru pouze ukonci radek a nic nenapise. (Viz take Datove typy - textove soubory) * procedure TextColor (barva:byte); (z jednotky Crt ) Nastavi aktualni barvu textu. Vsechno, co od teto chvile na obrazovku napi- sete, bude mit tuto barvu. Barvy jsou v rozsahu 0..15, vychozi je 7 (seda). Pokud napisete TextColor(NECO+128) nebo (NECO+Blink), bude text blikat. * procedure TextBackground (barva:byte); (z jednotky Crt ) Nastavi aktualni barvu pozadi textu. Kazdy dalsi napsany znak bude mit pod sebou pozadi teto barvy. Barvy pozadi jsou 0..7, vychozi je 0 (cerna). * procedure ClrScr; (z jednotky Crt ) Vymaze celou obrazovku a nastavi kurzor do leveho horniho rohu. Cela obrazovka bude mit barvu podle aktualni barvy pozadi. * function WhereX : byte; function WhereY : byte; (z jednotky Crt ) Vraci aktualni x-ovou a y-ovou souradnici kurzoru. Vydavani zvuku (jednotka CRT) ----------------------------- * procedure Sound (FR: word); Spusti na internal PC speakeru (alias pipatku) ton o frekvenci FR (v Hz). * procedure NoSound; Vypne pipatko. Pouzivani zvukove karty zvladaji jen velmi zkuseni programatori. (ja napriklad ne :-) ) Operace se soubory ------------------- * function IOresult : integer; Funguje jenom pokud je vypnuta automaticka kontrola operaci vstupu a vystupu ( direktiva {$I-} ). Temito operacemi se mysli otevirani a zavirani souboru, cteni z nich a zapis do nich. V pripade uspesne operace vraci ioresult nulu, jinak nenulove cislo, ktere vyjadruje, k jake chybe doslo. Pokud funkci volate po jedne I/O operaci vickrat, podruhe uz spravny vysledek neda, takze ji volejte jen jednou. Pokud pri jedne I/O operaci nastane chyba a nezavolate IOresult, vsechny dalsi I/O operace se ignoruji (Pozor!). Po zavolani IOresultu se zase vsechno dal provadi normalne. * function FileSize (var F) : longint; Vraci velikost souboru F v bytech. Nefunguje pro textove soubory. Soubor musi byt otevreny. Kdyz chcete zapisovat do beztypovych souboru hodnoty ruznych typu, otevrete soubor napr. takto: Reset(f,1). Tak nastavite, ze budete cist po blocich o velikosti 1 byte. Kdyz pak chcete zapsat treba hodnotu typu word (zabira 2 byty), napisete BlockWrite(f,HODNOTA,2). Pokud do techto souboru chcete ukladat neco, co ma vsechno stejnou velikost, ale nejde to ulozit do typoveho souboru (napr. obrazek ziskany procedurou getimage, viz dale), je lepsi zjistit velikost dane hodnoty, soubor otevrit s touto velikosti ( reset(f,VELIKOST); ) a pak psat po jednom bloku, ktery ma presne tuto velikost: blockwrite(f,NECO,1). Vsechno ostatni bylo popsano v kapitole Datove typy, typ soubor. Vstup z mysi ------------- Zadne standardni prikazy na to neexistuji, musite si napsat vlastni nebo je nekde sehnat (pro zacatek muzu doporucit napr. moji jednotku MYS). S mysi se komunikuje pomoci sluzeb DOSu, pres preruseni $33. Graficky vystup (jednotka Graph) ---------------- * procedure DetectGraph (var OVLADAC, REZIM: integer); Do prvni promenne ulozi cislo nalezeneho grafickeho ovladace (obvykle 9 - VGA) a do druhe optimalni dostupny graficky rezim (obvykle 2 - 640*480, 16 barev). * procedure InitGraph (var OVLADAC, REZIM: integer); Spusti graficky rezim dany parametry OVLADAC a REZIM. Bohuzel nejdou zadat jen hodnoty, musi to byt promenne. Jejich hodnoty nastavite bud rucne, nebo procedurou DetectGraph, a nebo tak, ze promenne ovladac zadate hodnotu 0 a autodetekce pak probehne automaticky. * procedure CloseGraph; Ukonci graficky rezim a vrati se do textoveho. Je dobre to uvest na konci programu. Vsechny nasledujici procedury funguji pouze v grafickem rezimu: * procedure ClearDevice; Vymaze obrazovku (resp. vyplni ji barvou 0) a nastavi graficky kurzor do leveho horniho rohu. * procedure SetColor (BARVA: word); Nastavi aktualni barvu, kterou se bude kreslit. Barvy jsou obvykle 0..15. * procedure SetBkColor (BARVA: word); Nastavi barvu pozadi. Prakticky to funguje tak, ze barva cislo 0 (obvykle cerna) se v palete zmeni na hodnotu BARVA. Barvy jsou obvykle 0..15. * procedure SetFillStyle (STYL, BARVA: word); Nastavi vzorek a barvu vyplne, kterymi se budou kreslit vyplnene prvky. Cisla STYLU si najdete v napovede Pascalu nebo zkousenim. Vysledek vypada tak, ze na barve pozadi se vykresli barvou BARVA nejaky vzor. * procedure SetFillPattern (VZOREK: fillpatterntype; BARVA: word); Umoznuje nastavit vlastni vzorek vyplne. VZOREK je pole osmi bytu, ktere si spise predstavte jako pole 8*8 bitu. Vysledny vzorek bude vypadat tak, ze bity 1 se kresli BARVOU a bity 0 barvou pozadi (zkratka podobne jako u set- fillstyle, ale misto cisla zadavate rovnou vzorek). * procedure SetPalette (CISLO: word; BARVA: shortint); Zmeni barvu CISLO na barvu BARVA. Zmena se okamzite projevi na obrazovce. Nejsem si uplne jist spravnou funkci teto procedury, stalo se mi, ze napr. barva 15 prestehovana na pozici 1 byla pak namodrala, 14 na 2 byla skoro bila a podobne, jestli chcete jistotu, pouzijte SetRGBPalette: * procedure SetRGBPalette (CISLO, R, G, B: integer); Umozni namichat si vlastni barvy. CISLO je cislo barvy, R,G a B jsou cervena, zelena a modra slozka vysledne barvy. Jsou od 0 do 63. Pozor, ze CISLO neodpovida normalnimu cislovani barev (0..15), viz napovedu, priklad 2 (VGA). * procedure MoveTo (x, y: integer); Nastavi graficky kurzor na dane souradnice. Graficky kurzor na rozdil od textoveho neni videt. Levy horni roh obrazovky ma souradnice 0,0 a pravy dolni obvykle 639,479. Tyto hodnoty vraci take funkce GetMaxX a GetMaxY. MoveTo je vlastne obdoba textoveho GoToXY. * function GetX:integer; * function GetY:integer; Vraci aktualni polohu grafickeho kurzoru (obdoba textoveho WhereX a WhereY). Vsechny nasledujici procedury kresli barvou nastavenou procedurou Setcolor: * procedure LineTo (x,y: integer); Udela caru z aktualni pozice kurzoru do pozice x,y a kurzor do tohoto mista presune. * procedure LineRel (oX, oY: integer); To same, ale souradnice se pocitaji relativne od aktualni pozice kurzoru. * procedure Line (x1,y1,x2,y2: integer); Nakresli caru z bodu x1,y1 do bodu x2,y2 nezavisle na poloze kurzoru, jeho polohu take nemeni. * procedure Circle (X,Y: integer; POLOMER: word); Nakresli kruznici se stredem v bode X,Y a polomerem POLOMER. * procedure Rectangle (x1,y1,x2,y2: integer); Nakresli prazdny obdelnik s jednim rohem v x1,y1 a protilehlym v x2,y2. Neza- lezi na tom, jestli jsou to levy horni a pravy dolni, jen musi byt protilehle. * procedure DrawPoly (POCET_VRCHOLU: word; var SEZNAM); Nakresli mnohouhelnik. POCET_VRCHOLU snad nemusim vysvetlovat, SEZNAM je array[1..POCET_VRCHOLU] of PointType, PointType je record x,y:integer; end; a je definovany primo v jednotce Graph. V jednotlivych polozkach pole jsou souradnice jednotlivych vrcholu. Nejdriv je nutne deklarovat pole SEZNAM a zadat do nej vrcholy, a az potom muzeme volat Drawpoly. * procedure Ellipse(X,Y: integer; POCATECNI_UHEL, KONCOVY_UHEL: word; POLOOSA_X, POLOOSA_Y: word); Nakresli elipticky oblouk. X,Y je stred, POLOOSA_X je delka vodorovne poloosy, POLOOSA_Y je delka svisle poloosy. Uhly se zadavaji ve stupnich, 0 je ve smeru doprava, uhel roste proti smeru hodinovych rucicek. * procedure Arc (x,y:integer; pocatecni_uhel,koncovy_uhel,polomer:word); To same, ale kresli kruhovy oblouk. * procedure SetTextStyle (font, smer, velikost: word); Nastavi parametry textu. Font je 0..10, smer 0..1 (vodorovne, svisle) a velikost 1..hodne, kde 1 je vychozi a ostatni jsou zvetseniny. * procedure SetTextJustify (vodorovne, svisle: word); Nastavi zarovnani textu, tj v jake poloze vzhledem k zadanym souradnicim se napise. Vychozi je Lefttext, Toptext, tj. na levy horni roh. * procedure OutText (TEXTIK: string); Na aktualni pozici kurzoru vypise retezec TEXTIK. Kurzor se posune podobne jako pri psani v textovem rezimu. * procedure OutTextXY (x,y:integer; textik: string); Pise text nezavisle na pozici kurzoru a nemeni ji. * function TextWidth (TEXTIK: string) : word; * function TextHeight (TEXTIK: string) : word; Vraci sirku a vysku retezce TEXTIK v pixelech pri aktualnim nastaveni pisma. * procedure SetWriteMode (JAKY: integer); Nastavi rezim kresleni car. 0 (normalput) - cary se kresli normalni barvou, 1 (xorput) - cary se kresli stylem XOR, tzn., ze kdyz caru nakreslite dvakrat na stejne misto, tak zmizi. Funguje pro procedury Line, Lineto, Linerel, Rectangle a DrawPoly, pro krivky a texty ne. Nasledujici procedury kresli utvary vyplnene podle aktualniho nastaveni procedurou setfillstyle: * procedure Bar (x1,y1,x2,y2:integer); Nakresli vyplneny obdelnik (bez obrysu), parametry stejne jako u rectangle. * procedure FillEllipse (SX,SY: integer; POL_X, POL_Y: word); Nakresli vyplnenou elipsu (s obrysem v aktualni barve nastavene pres setcolor). SX,SY je stred, POL_X a POL_Y jsou delky poloos. * procedure Sector (X,Y: integer; POCATECNI_UHEL, KONCOVY_UHEL: word; POLOOSA_X, POLOOSA_Y: word); Nakresli vyplnenou eliptickou vysec, parametry jsou stejne jako pro Ellipse. * procedure FillPoly (pocetvrcholu: word; var seznam); To same jako drawpoly, ale tenhle je vyplneny. Obrys v barve nastavene pres Setcolor. * procedure FloodFill (X,Y: integer; BARVA_HRANICE: word); Vyplni uzavrenou oblast ohranicenou barvou BARVA_HRANICE. X,Y je bod nekde uvnitr teto oblasti. Pro velmi slozite a velke tvary je nutne nastavit vetsi grafickou pamet (procedura setgraphbufsize). * procedure SetLineStyle (STYL, VZOREK, TLOUSTKA: word); Nastavi styl kresleni vsech car. Parametrem STYL si muzete vybrat z nekolika preddefinovanych vzorku nebo rict, ze pouzijete vlastni. VZOREK se uplatni jen pokud je STYL na hodnote Vlastni (4). Je to cislo, ktere vznikne, kdyz vzorek vyjadreny ve dvojkove soustave (16 barevnych nebo prazdnych bodu) prevedete do normalni nebo sestnactkove soustavy. TLOUSTKA je bud 1 (1 pixel) nebo 3 (3 pixely). * procedure PutPixel (x,y: integer; BARVA: word); Na souradnice x,y nakresli bod (pixel) barvou BARVA. * function GetPixel (x,y: integer) : word; Vraci barvu bodu (pixelu) na souradnicich x,y. * function GetColor : word; Vraci aktualni barvu nastavenou pomoci Setcolor. * function GetBkColor : word; Vraci aktualni barvu pozadi nastavenou pres Setbkcolor. Nacitani a zobrazovani obrazku z obrazovky (jednotka Graph) ------------------------------------------------------------ 1) vytvoreni mista v pameti pro nacteni obrazku -Deklarujeme promennou typu pointer (napr. var p:pointer). -Rozhodneme se, jak bude obrazek velky a urcime souradnice leveho horniho (x1,y1) a praveho dolniho (x2,y2) rohu. Pozor, ze do pameti se vejde obvykle jen asi tretina obrazovky (v rezimu 640*480*16). -Zjistime velikost potrebneho mista v bytech pomoci funkce imagesize (napr. VELIKOST:=imagesize(x1,y1,x2,y2). Pokud funkce vrati nulu, znamena to, ze jsme velikost obrazku prehnali. Je dobre jeste otestovat, jestli je v pameti opravdu misto (if VELIKOST<=maxavail then je_to_dobry). (funkce maxavail vraci velikost nejvetsiho souvisleho volneho bloku pameti) -Pomoci deklarovaneho ukazatele a procedury Getmem vytvorime dynamickou promennou potrebne velikosti ( getmem(p,VELIKOST); ). 2) nacteni obrazku - getimage(x1,y1,x2,y2,p^);. Pozor, ze ho neukladame do promenne p (ukazatel), ale do p^ (vyhrazene misto v pameti, na ktere p ukazuje). 3) zobrazeni obrazku - putimage(x,y,p^,JAK); x,y je levy horni roh, p^ je v pameti nacteny obrazek a JAK je cislo, ktere urcuje zpusob interakce obrazku s pozadim: 0 (Normalput) - proste se vykresli a prepise vsechno pod sebou, 1 (XORput) - s kazdym pixelem obrazku a prislusnym pixelem pozadi se provede logicka operace XOR. Kdyz pak stejnym zpusobem zobrazite na tomto miste obrazek podruhe, vsechno se vyrusi a zustane tu zase puvodni pozadi. 2,3,4 - dalsi, ale uz ne tak pouzivane moznosti. Viz napovedu Pascalu. 4) zruseni obrazku v pameti -Kdyz praci s obrazkem ukoncite, je treba vyklidit pamet. Zruseni dynamicke promenne se provede takto: freemem(p,VELIKOST);. (tady uz se nepise p^) Na konci programu se sice pamet uvolnuje automaticky, ale jestli chcete jeste predtim vytvorit dalsi obrazek, musite mu nejdriv udelat misto (nutne je to tedy jen v tom pripade, kdyz uz se dalsi obrazek do pameti nevejde, ale doporucuji uklizet prubezne). Kazde nacteni obrazku (getimage) prepise puvodni obsah p^. Nepokousejte se zobrazit obrazek, ktery jste jeste nenacetli. Dela to smouhy pres pul obrazovky, zpomaluje to program a obcas se i kousne nebo spadne. Kdyz chcete nacteny obrazek ulozit do souboru, pouzijte netypovy soubor, otevrete ho prikazem rewrite(soubor,VELIKOST); a obrazek ulozte takto: blockwrite(soubor,p^,1); nebo muzete soubor otevrit rewrite(soubor,1) a pak zapisovat blockwrite(soubor,p^,VELIKOST). Je to univerzalnejsi, ale pomalejsi. Precist obrazek ze souboru muzete podobne, napr.: reset(soubor,VELIKOST); blockread(soubor,p^,1). Samozrejme musite mit predem vytvorenou dynamickou promennou p^. (getmem(p,VELIKOST);) Rychle ukonceni programu ------------------------- * procedure Halt [ (KOD: word) ]; Ukonci program. Parametr KOD vubec nemusite zadavet, slouzi jenom jako zprava o zpusobu ukonceni programu pro DOS (systemova promenna ERRORLEVEL). Pouziti: napr. v inicializacni casti nektere jednotky, ktera ukonci program pokud napr. nenajde grafickou kartu. Cekani (z jednotky Crt ) ------- * procedure Delay (DOBA: word); Parametr DOBA je v milisekundach. Tady stoji za zminku skutecnost, ze nektere verze TP7 mely v jednotce Crt chybne napsanou inicializaci teto procedury. Programy potom na pocitacich rychlejsich nez cca 200 MHz nahlasily chybu "Error 200: Division by zero." a okamzite spadly. Pokud jste zrovna vy ti stastni, kterym se tato chyba projevuje, nechal jsem pro vas na svych strankach ke stazeni opraveny TP. Jinak staci chvili hledat na netu a najdete ruznych patchu spoustu. ****************************************************************************** Ufff... to je k zakladum Pascalu asi tak vsechno, uzijte si to ve zdravi. V pripade, ze by vas zajimalo neco dalsiho, napiste mi. Mircosoft Dokonceno 26.7.2004 Upraveno 12.5.2005 (Mircosoft@centrum.cz) ******************************************************************************