Pascal
Programming Practices
Power
Programming with Pascal
Görbe Mihály
2008-2009
Bevezető
Korunk
egyik legizgalmasabb technikai eszköze a számítógép. Széleskörű felhasználása
révén mindennapjaink nélkülözhetetlen segítőjévé vált. Használatát már
kisgyermekkorban megkezdjük, megszokjuk viselkedését. Örülünk, ha segít nekünk,
bánkódunk, ha cserben hagy bennünket. Ez a feladatgyűjtemény arra próbál példát
mutatni, hogyan lehet minél hamarabb egy programozási nyelv rejtelmeibe
betekintést nyerni. Készült e könyv mindazoknak, akik előítélet nélkül, el
tudnak fogadni egy koncepciót, és azt saját tanulásuk közben merik alkalmazni.
De azok is haszonnal forgathatják, akik csak algoritmusokat, gépi megoldásokat
keresnek egy-egy problémára. A könyv nem programozási kézikönyv. Nem
tartalmazza a Pascal nyelv valamennyi részletét. A fő cél: a gép legfontosabb
perifériáinak a kezelése programban. Ezek a következők: billentyűzet, képernyő,
egér és a lemezes egységek. Nagy hangsúlyt kapnak még a különböző
adatszerkezetek is: úgymint a tömb, a rekord, a fájl valamint a különböző
listák.
A
programkészítés lépései:
1.
Tervezés
2.
A programnyelv
kiválasztása
3.
Kódolás
4.
A program
tesztelése
5.
Dokumentálás.
Programnyelvek
generációi:
1. Gépi kódú programozási nyelvek, csak egy géptípusra
(processzorra) alkalmazhatók, azaz gépfüggő nyelvek.
2. Assembly nyelv, amely lényegében szintén gépi kódú
programnyelv, csak az utasításkódok helyett emlékeztető (angol) rövidítéseket
használ, valamint címkéket és változókat is tud kezelni
3. Magas szintű programozási nyelvek, algoritmikus
nyelvek, (Algol, Cobol, Fortran, PL1, Logo, C, C++, Basic, Java, Pascal)
amelyben valamely beszélt nyelvhez (angol) közeli formában írhatók le a
programok utasításai, nagymértékben gépfüggetlen formában.
4. 4. Generációs nyelvek, grafikus felületű
programfejlesztői rendszerek (4GL, pl.: DELPHI, mely a Pascal nyelv vizuális
bővítése).
Turbo Pascal 7.0
A Turbo Pascal 7.0 egy magas szintű programozási
nyelv, mely támogatja az objektum orientált programozást, DOS-os (karakteres),
valamint Windows-s felületen is használható.
Lényegében minden programkészítési lépés
elvégezhető a nyelv Integrált Fejlesztői Környezetével (Integrated Development
Environment: azaz az IDE-vel), amely a Turbo, a Tpx, a Bp vagy a Bpw programmal
indítható attól függően, hogy a nyelv milyen interpretációjával rendelkezünk illetve akarunk használni. Az utóbbi a
Windows-s változatát futtatja. Ez a könyv csak a DOS-os verzióval és
programozásával foglalkozik. A könyv programjai a Bp környezetében készültek.
Hálózati
beállítások:
Ha a számítógépünk hálózatban van, és egy
hálózati meghajtón van a Home könyvtárunk, akkor következő tevékenységeket kell
végrehajtani:
1. Pascal könyvtár létrehozása a Serveren a Home
könyvtárban.
2. A Home könyvtárhoz hálózati meghajtót kell
rendelni, esetleg parancsikonok létrehozása az asztalon (Home könyvtárra,
illetve az IDE-re). Ha a következő bejelentkezéskor ez a meghajtó nem létezik,
akkor újra létre kell hozni.
3. Futtatás után az IDE-ben: Change Dir …, majd a Home könyvtárban lévő Pascal könyvtár
beállítása. Ha az IDE indítását az operációs rendszerre szeretnénk bízni, akkor
a pas kiterjesztésű állományokat a
Turbo Pascal IDE-jével kell társítani. Ekkor az aktuális könyvtár az indítási
hely lesz, a kimentés automatikusan ide történik.
Az IDE
menürendszere:
1.
File (file műveletek: új file létrehozása, betöltés,
mentés, mentés másként, könyvtárváltás, nyomtatás)
2.
Edit (programlista szerkesztése, másolás, kivágás,
beillesztés, visszavonás, vágólap megtekintése)
3.
Search (keresés a programlistában, szövegrész cseréje)
4.
Run (futtatás, lépésenkénti futtatás, futtatás a kurzor
helyéig)
5.
Compile (fordítás, információ a fordítás eredményéről)
6.
Debug (programbelövés, nyomkövetés)
7.
Tools (eszközök)
8.
Options (beállítások, környezeti beállítások)
9.
Window (programlisták képernyőn való megjelenítésének
beállítása)
10. Help
(segítség)
Menüválasztás: egérrel vagy Alt+HotKey vagy F10, majd
pl. cursor vezérlő billentyűk, újra HotKey vagy újra egér.
Programablak: kék téglalap, fehér kettősvonalú
kerettel. Részei: felső sora a címke sor, bal szélén zöld téglalap alakú bezáró
ikonnal, középen a program DOS nevével, ha noname00.pas, akkor még nem volt
kimentve lemezre. A programlisták DOS neve *.pas
kiterjesztésűek, a korábbi állapotú neve *.bak, melyből átnevezéssel
visszaállítható a *.pas állomány. A futtatáskor, vagy külön kérésre a lemezen
létrejön egy, az IDE-től teljesen független *.exe futtatható állomány is. A
címke sor jobb szélén van egy ablaksorszám, amely segítségével az ablakra át
lehet váltani: Alt+Sorszám (max. 9). Egy program több ablakban is meg lehet
nyitni. Ekkor a kereten a neve után kettőspont és a megnyitási sorszám jelenik
meg. Általában nincs szükség arra, hogy egy lista két ablakban is megjelenjen,
talán csak akkor, ha egy hosszú lista egymástól távoli részeit egyszerre
szeretnénk látni a képernyőn. Ekkor a megjelenítő ablakokat csökkentett méretre
kell beállítani, és úgy elhelyezni, hogy a számunkra fontos részek egymást ne
takarják. Az IDE minden programablaknak két állapotát jegyzi meg, egyik a
maximális méret, a másik egy kisebbített. A két állapot között az ablak jobb
felső részén lévő felfelé, vagy le-fel nyíl alakú ikonnal, vagy F5 segítségével
válthatunk. Ha a programablakot egérrel a címke soránál megfogjuk, akkor
mozgathatjuk. Az ablak jobb alsó sarkát megfogva, az ablakot méretezhetjük. Az
ablak alsó sorában, bal oldalt a kereten, ha csillag látható, akkor a lista az
utolsó mentés óta már változott. Kicsit beljebb két szám van, mely az író cursor
helyét mutatja a programlistában, első a sor, második az oszlop. A keret jobb
oldalán, illetve alul görgető sávok találhatók, arra az esetre, ha a
programlista nem látható teljesen a képernyőn.
Alapok
1.) Írjunk programot, amely az üres kék színű képernyő közepén egy
sárga színnel írt szöveget villogtat.
Minden
Pascal program legalább három sorból áll:
Program
Elso;
End.
A lista kövéren
írt szavai lefoglalt szavak a Pascalban, a képernyőn fehéren jelennek meg. A
lefoglalt szavakat csak a nyelv által meghatározott szerepben használhatjuk. A Program szó azt jelzi, hogy a
következőkben egy program listáját írjuk le. A Program szó után következik a program DOS neve kiterjesztés nélkül.
A sort pontosvessző zárja. A pontosvesszőt nagyon sok esetben használni kell.
Szerepe: utasítás elválasztó, valamint üres utasítás. Csak néhány sor végére
nem tesszük ki. Van olyan eset, amikor megjelenése nem befolyásolja a listát,
van olyan, amikor megváltozik a program jelentése, van olyan eset is, amikor
szintaktikai hibát jelent egy fölöslegesen írt pontosvessző. Tehát ez a jel
külön figyelmet érdemel. A programunk listájának kétféle helyességnek kell
eleget tenni: szintaktikai és szemantikai. Az első: helyesírási vagy
nyelvhelyességi, míg a második tartalmi helyességet jelent. Az IDE minden szintaktikai
hibát felfedez, a tartalmi helyesség megvalósítása a programozó feladata. A Begin a programlista kezdetét jelzi,
míg az End. a
lista végét. A program utasításait, eljárásait, függvényeit a Begin és End. közé kell írni. Jó tanács:
programírás közben ügyelni kell arra, hogy a lista állapota a lehető
legközelebb legyen a futtatható állapothoz. Így, ha leírunk egy Begin-t, akkor azonnal írjunk End-et is. Az End. a Begin strukturált párja. A Pascal ugyanis egy strukturált
programozási nyelv, melyet a lista megjelenése is tükröz. A strukturált
kulcsszó-párokat úgy kell a listában elhelyezni, hogy azok azonos oszlopban
kezdődjenek és az első két betűjük közzé, ne írjunk semmit, bekezdésesen írjuk
a lista azon részét, mely a két kulcsszó között van. Gyakorlatilag a programot
mindig beszúrással a belsejében bővítjük. Azaz pl. kinyitjuk a Begin-End-et és két Space után, írjuk a program utasításait.
Program
Elso;
Write(’Ez az első programunk’);
End.
Ez a program már egy utasítást (vagy eljárást) is tartalmaz,
amely talán az egyik legfontosabb, ez pedig: a Write. Ebben a programban a
képernyőn való megjelenítésre használjuk. A kiírandó szöveget az eljárásnév és
zárójel után idézőjelben kell megadni. Az idézőjelet és zárójelet is be kell
zárni és a sor végére ;-t kell tenni. Ezt a programot
már érdemes futtatni, hiszen van benne végrehajtható utasítás. A futtatást,
abban az esetben, ha még az adott állapotban még nem volt lefuttatva a program,
fordítási művelet előzi meg. Akkor, ha csak azt szeretnénk tudni, hogy helyes-e
a programlista, kérhetjük az IDE-től, hogy csak fordítást végezzen. Erre
szolgál az F9 billentyű. A fordítás eredményeként egy ablakot látunk, mely a
lefordított sorok számát tartalmazza. Bármely billentyűre eltűnik. Ha a
listában a fordító hibát talál, azt egy pirosan írt sorban jelzi. Az Error szó
mellett a hiba kódját látjuk, majd angolul leírva a hiba jellege. Az egyik
leggyakoribb hiba: Expected - valami hiányzik, mégpedig az, amit az idézőjelek
közé írt. A másik: Unknown Identifier - ismeretlen azonosító a cursor helyén. A
programot futtathatjuk a Ctrl+F9 billentyű kombinációval. Ha ezt az Elso programmal megtettük, egy
villanáson kívül semmit nem látunk az eredményből. Az IDE futása alatt a
képernyőt megkettőzve kell elképzelni. Az egyiket teljesen uralja az IDE, a
másik a kimenti képernyő, melyre futás közben, a futás idejére, a gép átvált.
Programunk oly gyorsan végrehajtódik, hogy a kimeneti képernyőt nem láthatjuk.
A kimeneti képernyő megtekintése: Alt+F5 –el lehetséges. Bármely billentyűre
visszajutunk az IDE-be. A kimeneti képernyőn látható a programfutás eredménye,
valamely sorban látható a szöveg: Ez az első programunk. Ahányszor lefuttatjuk
a kis programunkat, annyiszor jelenik meg a szöveg, mindig ott folytatva az
írást, ahol előzőleg abbahagyta. Ha a kimeneti képernyőt a program futása
közben szeretnénk látni, azaz hogy ne kelljen mindig átváltani Alt+F5-el, az End elé írjuk be a ReadLn; utasítást:
Program
Elso;
Write(’Ez az első programunk’);
ReadLn;
End.
A ReadLn; eljárás ebben a szerepben arra való, hogy
mindaddig olvas a billentyűzetről, ameddig Enter-t nem nyomunk. Így a kimenti
képernyőt, tetszőleges ideig nézegethetjük. Az IDE-be tehát csak Enter
billentyűvel juthatunk vissza.
Jó dolog lenne, ha csak a program által kért szöveg
jelenne meg a képernyőn, más nem. Ehhez a kiírás előtt le kell törölni a
képernyőt. A listába tehát nem mindegy, hová írjuk a képernyőtörlő utasítást. A
program utasításait ugyanis a gép olvasási sorrendben
hajtja végre, azaz balról jobbra, fentről lefelé, ez a szekvencia.
Program
Elso;
ClrScr;
Write(’Ez az első programunk’);
ReadLn;
End.
Az új eljárás tehát a ClrScr; azaz a Clear Screen,
vagyis képernyőtörlés. Ha futtatni szeretnénk a programot, akkor ezt az
eljárásnevet a fordító nem érti. Ez azért van így, mert a Pascal nyelv egy
nagyon összetett, univerzális programnyelv. Így a részfeladatok mindegyikének
végrehajtására alapértelmezésben nem képes. A részterületek eljárásait külön,
un. Unit-okban (Egység-ekben) találhatjuk, melyet a programnak, ha szükséges,
használatba kell venni. Erre való a Uses lefoglalt szó. A képernyőkezelés
és egyéb fontos eljárások a Crt Unitban találhatók. Használata a következő:
Program
Elso;
Uses
Crt;
ClrScr;
Write(’Ez az első programunk’);
ReadLn;
End.
Most már lassú gépeken lefut a program. Ha gépünk
órajele nagyobb 233 MHz-nél, akkor még egy teendőnk van. Használatba kell venni
a Crt javító Unit-ját, a NewDelayt is, mégpedig a Crt előtt. Ha számítógépünk a
karakteres kimeneti képernyője megjelenítésekor 50 sort használ, akkor első
utasításként a 25 soros beállításra kell utasítani a gépet a TextMode
eljárással, mely szintén a Crt Unit-ban van deklarálva.
A ClrScr törli a képernyőt, a kurzort a bal felső
sarokba állítja. Oldjuk meg azt, hogy a szöveg a képernyő közepén jelenjen meg.
Ehhez nem a bal felső sarokban kellene a kurzornak lenni, hanem a képernyő
közepe táján. A kurzor áthelyezésére szolgál a GoToXY eljárás (szintén a Crt
Unit eljárása). Ennek két paramétere van, melyet a neve után, zárójelbe,
vesszővel elválasztva kell beírni. Az első paraméter a cursor X koordinátája,
mely 1-80 intervallumban változhat (balról jobbra), a második az Y koordináta,
mely 1-25 intervallumból való (fentről lefelé). A kiírandó szöveg hosszának a
felét kivonjuk 40-ből, itt kezdődik a szöveg, és válasszuk a 12. Sort. Ekkor a
lista így néz ki:
Program
Elso;
Uses
NewDelay, Crt;
TextMode(CO80);
ClrScr;
GoToXY(29,12);
Write(’Ez az első programunk’);
ReadLn;
End.
Állítsuk be a képernyő, azaz a háttér és az írás szint
is. Erre való a TextBackGround és a TextColor (Crt) eljárások, amelyeket a
CrlScr illetve a Write eljárás előtt kell a listában elhelyezni.
Program
Elso;
Uses
NewDelay, Crt;
TextMode(CO80);
TextBackGround(Blue);
TextColor(Yellow);
ClrScr;
GoToXY(29,12);
Write(’Ez az első programunk’);
GoToXY(1,25);
ReadLn;
End.
A programot futtatva, a kék képernyő közepén sárga
színnel jelenik meg a szöveg. A Write utáni GoToXY(1,25)
a kurzort a képernyő bal alsó sarkába, kevésbé látható helyre helyezi. Utolsó
lépésként változtassuk meg úgy a programot, hogy a kiírt szöveg villogjon.
Ennek a feladatnak a kapcsán nézzük meg, hogyan kaphatunk segítséget a
munkánkhoz az IDE-től. Ha F1 billentyűt nyomunk, Help képernyőt kapunk. Igaz
angol nyelvű, de az eljárások és függvények alkalmazását bemutatja,
mintaprogramokat is tartalmaz, valamint az egymással rokon részeket együtt
láthatjuk, így könnyen bővíthetjük egy adott program lehetőségeit. Ha valamely
eljárás vagy függvény nevét ismerjük, vagy valamilyen rögzített szót ismerünk,
könnyen kérhetünk olyan Helpet, amely közvetlen a keresett szóhoz kapcsolódik.
Ez a helyzet érzékeny Help. Ehhez álljunk a programlistán a kérdéses szóra,
pl.: Blue-ra és nyomjuk meg a Ctrl+F1-et. Ekkor a képernyő és írás színek
lehetséges értékeit olvashatjuk le a zöldes színű ablakból. Ha azt szeretnénk,
hogy maximális legyen a mérete, nyomjunk F5-öt. A háttér színeket és írás
színeket kétféleképpen adhatjuk meg, vagy a szín angol nevével, vagy kódokkal.
Az angol név és a kód a Helpből kiolvasható. A kódok értéke háttérszínnél: 0-7,
karakterszínnél: 0-15. Különböző értékeket írva az eljárásokba, a hatását a
színek vonatkozásában, a képernyőn megfigyelhetjük. Arra kell vigyázni, hogy a
háttér színe és az írás színe ne egyezzen meg, mert akkor nem látszik a szöveg.
Visszatérve utolsó részfeladatunkhoz: ha az írásszínhez hozzáadunk egy
Blink-et, azaz 128-at, akkor a szöveg, a megadott színnel villogni fog. Kész
programunk tehát így fog kinézni:
Program
Elso;
Uses
NewDelay, Crt;
TextMode(CO80);
TextBackGround(Blue);
TextColor(Yellow+Blink);
ClrScr;
GoToXY(29,12);
Write(’Ez az első programunk’);
GoToXY(1,25);
ReadLn;
End.
Az első programunk végére értünk. A programok beírását
mindig a fejlesztési lépések figyelembe vételével kell, a bemutatott lépéseknek
megfelelően végrehajtani. Arra kell törekednünk, hogy a program szinte minden
újabb utasítás beírása után futtatható legyen, egyre jobban megközelítve a
végső állapotot. Ez azt eredményezi, hogy mindig a változtatást tesztelhetjük,
kialakíthatjuk a legjobb megoldást, s eközben megfelelően megismerhetjük a kérdéses
eljárást vagy függvényt.
Ha azt szeretnénk, hogy az IDE-ből való kilépés után a
program listáját újra megtaláljuk, akkor azt ki kell menteni egy
háttértárolóra. Erre figyelmeztet a bal alsó kereten lévő * is. Kimentést
F2-vel kezdeményezhetünk. Ha már ki volt mentve a lista, akkor a folyamat
nagyon rövid idő alatt lejátszódik, semmit nem kell közben tenni, a csillag is
eltűnik a keretről. Ha még nem volt kimentve, nem volt általunk adott neve,
akkor egy párbeszédablak jelenik meg, a Save As. Itt beírjuk a program nevét: Elso, majd Enter-t nyomunk, vagy OK-ra
kattintunk. A keret közepén megjelenik az Elso.pas ami a program DOS neve.
Az IDE-t legkönnyebben Alt+x-el hagyhatjuk el. Ha újra indítjuk az IDE-t, és
szeretnénk megtekinteni az Elso.pas,
vagy valamely más program listáját, akkor azt F3-al kezdeményezhetjük, ez az Open azaz megnyitás. A megnyitandó file nevére egérrel
kétszer kattintva, az betöltődik, majd javíthatjuk, fordíthatjuk, futtathatjuk.
Az első program kapcsán nagyon sok fontos, gyakran
végrehajtandó dolgot kellett megtanulni. A további programoknál ezekről már nem
lesz szó (programlistába való beszúrás, lista kimentése, betöltése, javítása,
Help kérése, fordítás, futtatás).
2.) Írjunk
programot, mely a fekete képernyőn megjelenít egy kis piros téglalapot.
Ennek a programnak a megírásához egy új eljárást kell
megismernünk: a Window-t, mely a ClrScr-hez hasonlóan a Crt Unit része. A
Window ablakot jelent. A teljes képernyő is egy ablak, melyet ezzel az
eljárással kisebbíthetünk, vagy újra maximálissá tehetünk. A Window eljárásnak
négy paramétere van. Egy téglalapot a képernyőn azonosíthatja pl.: a bal felső
illetve jobb alsó csúcsának két-két koordinátája. Lássuk a listát.
Program
Teglalap;
Uses
NewDelay, Crt;
TextMode(CO80);
TextBackGround(0);
ClrScr;
TextBackGround(Red);
Window(10,5,20,8);
ClrScr;
ReadLn;
End.
A képernyő fekete színéért a TextBackGround(0);
és ClrScr; sorok a felelősek. A háttérszín beállítását célszerű annak ellenére
külön is beírni a listába, hogy a fekete az alapértelmezett, mert ha nem lépünk
ki az IDE-ből két program futtatása közben, akkor az először futtatott program
által beállított háttérszín lesz az első érvényes háttérszín az újabb
programban. A vörös téglalapot, az ezeket követő három sor hozza létre. A
ReadLn; megállítja a program futását. A Window eljárás négy paraméterének megállapításánál
a következőkre kell figyelni: 1. paraméter: a bal felső X, 2. paraméter: a bal
felső Y, 3. paraméter: a jobb alsó X és a 4. paraméter: a jobb alsó Y
koordináta. A méretkorlátok a GoToXY-nál említettekkel megegyező. Azaz az X-ek
1-80, az Y-ok 1-25 között lehetnek. A másik talán még fontosabb dolog, hogy
külön az X-eknek és az Y-oknak nagyság szerint növekedően kell szerepelnie. Az
eljárás ugyanis csak akkor definiál új ablakot, ha a korlátozások mellett, a
nagyságrend szerinti megállapítás is teljesül. Nem véletlen tehát, hogy a
programunkban a paramétereknél 10 < 20 és 5 <
3.) Írjunk programot, amely egy magyar zászlót jelenít meg kék színű képernyőn,
a zászlónak barna rúdja legyen, a fehér területre írjuk ki feketével:
MAGYARORSZÁG.
A listánkat a szokásos sorokkal kezdjük, majd a megfelelő
színeket TextBackGround és ClrScr alkalmazásával hozzuk létre. A színezendő
területek a Window eljárással állítjuk be.
Program
Zaszlo;
Uses
NewDelay, Crt;
Begin
TextMode(CO80);
TextBackGround(Blue);
ClrScr;
TextBackGround(Red);
Window(18,3,62,5);
ClrScr;
TextBackGround(White);
Window(18,6,62,8);
ClrScr;
TextBackGround(Green);
Window(18,9,62,11);
ClrScr;
TextBackGround(Brown);
Window(17,3,17,24);
ClrScr;
TextBackGround(White);
TextColor(Black);
Window(1,1,80,25);
GoToXY(35,7);
Write('MAGYARORSZÁG');
GoToXY(1,25);
ReadLn;
End.
Az első két sor a háttér kék szint állítja, aztán 3
soronként egy-egy szín kerül a képernyőre, majd a barna színű, egy karakter
széles rúd. A Window(1,1,80,25); eljárás visszaállítja
a képernyő alaphelyzetét, vagyis beállítódik a legnagyobb ablak. A zászló
színeit adó téglalapok magassága 3 (3,4,5 – 6,7,8 – 9,10,11), így lehet a
MAGYARORSZÁG-ot a fehér színű téglalap középre írni (5 magasságú már aránytalan
lenne). Írás előtt be kell állítani a háttér és
karakterszíneket is, valamint a kurzort a (35,7)-re állítani, ami a fehér szín
közepét jelenti.
4.) Írjunk programot, amely egy vöröskeresztes zászlót jelenít meg.
Fehér alapon, vastag szárú vörös + jel. Törekedjünk az eljárások számának
minimalizálására.
A szokásos sorok után csak két terület kijelölésével a
feladat megoldható, mintha egy széles ecsettel egy függőleges és egy vízszintes
csíkot festettünk volna.
Program
VorosX;
Uses
NewDelay, Crt;
Begin
TextMode(CO80);
TextBackGround(White);
ClrScr;
TextBackGround(Red);
Window(35,5,45,21);
ClrScr;
Window(22,11,58,15);
ClrScr;
Window(1,1,80,25);
GoToXY(1,25);
ReadLn;
End.
A VorosX program könnyedén és egyértelműen
értelmezhető a Zaszlo program
alapján, ezért nem elemezzük.
Gyakorló programozási feladatok:
F.1.: Írjunk programot, amely egy úttesten elhelyezkedő gyalogos
átkelőhelyet rajzol a képernyőre. A kép alsó részén az út egyik oldala, tetején
a másik oldala létható, a kettő között pedig a zebra.
F2.: Írjunk programot, amely egy lépcsőt rajzol a képernyőre
oldalnézetből, azaz csak a keresztmetszetét ábrázolva.
F3.: Írj programot, amely a képernyőn egy házat jelenít meg,
sematikusan - a karakteres képernyő lehetőségei szerinti részletekkel.
F4:
Írj programot, amely képeslapot jelenít meg a képernyőn. A felirata: Kellemes
Karácsonyi Ünnepeket. A képeslapon egy asztal és két oldalán egy-egy szék
helyezkedik el. Az asztalon egy monitor és egy karácsonyfa látható, a
karácsonyfán néhány csillagszóró villog.
5.) Írjunk
programot, mely kiírja az összes ASCII karaktert a kódjával együtt.
Gyakran előfordul ugyanis, hogy a képernyőn való
megjelenítés egyetlen eszköze csak az lehet, ha a karaktereket kódjuk
segítségével visszük a listába, hiszen nincs minden karakterhez billentyű,
gondoljunk csak a kereteket megjelenítő karakterekre. A kódok megismerésében
lesz segítségünkre ez a program. A feladatot megvalósító rövid program több
újdonságot tartalmaz.
Program
Karakter;
Uses
NewDelay, Crt;
Var I: Byte;
Begin
TextMode(CO80);
ClrScr;
For
I:= 0 To 255 Do
Write(I:3,':
',Chr(I),' ');
ReadLn;
End.
Mivel a karakterkészlet
a 0-255 kódokkal hívható, a feladatban 256-szor kellene kiíró művelet
végrehajtani. Ezt nyilván nem lenne célszerű ennyiszer a listába beírni. Van
olyan kódolási megoldás, amelynél a program egy része többször is
végrehajtódik. Ezzel elérhetjük, hogy kevés kóddal, nagyon sok lépésre
utasítjuk a gépet. Ezek a módszerek az iterációk. A Pascal nyelv három
iterációt ismer, amely közül most a For
ciklust alkalmaztuk. A For ciklus
alkalmazásának feltétele: véges sok és jól meghatározott alkalommal kell egy
utasítást végrehajtani. Ez az ismétlő eljárás elől tesztelő, tehát a ciklus
magja lehet, hogy egyetlen egyszer sem hajtódik végre. Kulcsszavai For … To … Do. Az I a ciklusváltozó. A Pascal nyelvben a változókat a program
elején, a program fejében deklarálni kell, azaz le kell írni. Vagyis, meg kell
adni a nevét (azonosítóját) és a típusát. Erre való a Var kulcsszó. A Var után
vesszővel elválasztva fel kell sorolni a változók nevét és kettőspont után a
típusát. A programban az I Byte típusú, ami 0-255 közötti egész számot jelent.
Az újabb típusú változókat pontosvesszővel kell elválasztani egymástól. Majd
egy olyan későbbi programban, amelyben több változó is lesz, megfigyelhetjük
ennek a szintakszisát. Az I:= 0 programrészlet az I változó értékét 0-ra állítja.
Ez az értékadó utasítás. Így olvasandó: I legyen egyenlő 0. Ez az I
ciklusváltozó kezdő értéke. A To
után álló
A lista Write
eljárásában is sok az újdonság. Eddig csak szöveget írattunk ki vele, itt
viszont egy változó és egy függvény értékét is. Ezek aktuális értékét illetve
aktuális visszaadott értékét írja ki az utasítás. A változó az I ciklusváltozó.
Az I:3 alakkal azt érjük el, hogy 0-255 szám mindegyike a képernyőn 3 helyet
foglaljon el. Ez a táblázatos kialakításhoz elengedhetetlen, hiszen az
intervallum számai 1,2 ill. 3 jegyűek, és ez elrontaná
az azonos szélességű kiírást. A másik szembetűnő dolog Write-ban, hogy
egyszerre több dolog is kiírható vele. Az egyes részeket vesszővel elválasztva
kell felsorolni. Ebben a Write-ban 4 szakasz figyelhető meg. 1.: az I kiírása három karakteren, 2.: egy kettőspont és egy
Space, tehát két karakteren, 3.: a Chr(I), amely az I kódhoz tartozó karaktert
jelenti egy képernyő helyen, 4.: két db. Space, ami ugye két karakter. Ha az
egyszerre kiírandó karakterek számát összeszámoljuk, akkor nyolcat kapunk. Ez
nem véletlen. A képernyő egy sorába 80 karakter fér, így egy sorba pontosan 10
karakter foglal majd helyet. Ez összesen 2600 képernyőhely lenne, ami azt
mutatja, hogy ez biztosan nem fér el, lévén a képernyő 2000 karakteres. Azért,
hogy a karakterek elejét is láthassuk és értelmezhessük, legalább egy futtatás
idejére a lista 255 értékét csökkentsük 200-ra. A karaktertábla elején több
olyan karakter is van, melyet Write utasítással még Chr függvény segítségével
sem lehet a képernyőre írni. Ezek a képernyőkezelő vezérlő karakterek, amelyek
kiírása a vezérlés végrehajtását jelenti, pl.: soremelés, kocsi vissza,
BackSpace, Tab, vagy a Chr(7), amely hangot ad.
Ismerkedjünk meg a karaktertábla
kódtartományaival:
0-31:
vezérlő karakterek,
32-47:
írásjelek,
48-57:
számjegyek,
58-64:
írásjelek, (64-es a @),
65-90:
az angol ABC nagy betűi,
91-96:
írásjelek,
97-122:
az angol abc kis betűi,
123-128:
írásjelek,
129-175:
nemzetközi karakterkészlet,
176-178:
kitöltő karakterek,
179-220:
grafikus jelek keretek rajzolásához,
221-255:
egyéb speciális karakterek és írásjelek.
További programjainkban
az egyvonalas keretek kódjaira szükség lesz. Célszerű ezt a program
segítségével kigyűjteni, és egy rajzon rögzíteni:
218 194 191
196 179 |
|
195 |
197 180 |
192 193 217
Az ábrán a
Gyakorló programozási feladatok:
F.5.: Írj programot,
amely 3x4-es méretben pálcika-emberkét rajzol a képernyőre. Keressünk a
karakterkészletből olyan karaktereket, hogy a figura minél jobban élethű
legyen.
F.6.: Írj programot,
amely a képernyőre egy hangjegyfüzethez hasonló 5-ös vonalrendszert rajzol. Két
vonal között maradjon egy üres sor, az 5-ös vonalsorok között legalább 3 sor.
F.7.: Írj programot,
amely bemutatja a következő vezérlő karakterek hatását a képernyőre írás
közben: #7, #8, #9, #10 és #13.
6.) Készítsünk
programot, amely egy 20 x 5 méretű keretet rajzol a képernyő bal felső sarkába.
A
szokásos kezdősorok után a karaktereket For
ciklus segítségével helyezzük a képernyőre. Eltekintünk a sarkok pontos
kezelésétől, akár többször is kirajzoljuk, csak a végeredményre koncentráljunk.
Program Keret;
Uses NewDelay, Crt;
Var I: Byte;
Begin
TextMode(CO80);
ClrScr;
For
I:= 1 To 20 Do
Write(Chr(196));
GoToXY(1,1);
For I:= 1 To 5 Do
WriteLn(Chr(179));
ReadLn;
End.
A ClrScr; biztosítja,
hogy a képernyőn csak a mi rajzunk lesz, valamint azt, hogy a rajzolást a bal
felső sarokban kezdjük. Az első For
ciklus egy 20 karakter hosszú vízszintes vonalat rajzol a képernyőre. A bal
szélső, függőleges oldal megrajzolását a második For ciklus végzi. Ha a GoToXY eljárást kihagyjuk, akkor a
függőleges keretelemeket a jobb felső sarokban kezdi el rajzolni. A második
Write sem a szokásos. WriteLn-nek írtuk. Eddigi Write-ok az író kurzor helyét
ott tartották, ahol az írás befejeződött. A WriteLn az írás után egy soremelés
+ kocsi vissza (ugrás a sor elejére) lépést is végrehajt, így minden kiírás új
sor elején kezdődik. Ez biztosítja, hogy a függőleges elemek egy oszlopba
kerülnek és összeáll belőle a keret bal széle. Rajzoljunk tovább:
Program
Keret;
Uses
NewDelay, Crt;
Var I: Byte;
Begin
TextMode(CO80);
ClrScr;
For
I:= 1 To 20 Do
Write(Chr(196));
GoToXY(1,1);
For I:= 1 To 5 Do
WriteLn(Chr(179));
GoToXY(1,5);
For I:= 1 To
20 Do
Write(Chr(196));
ReadLn;
End.
Ez az állapot már az
alsó vízszintes oldalt is megrajzolta. De hogyan rajzoljuk meg a jobb oldali
függőleges vonalat. Gondoljuk csak meg: ha csak Write-ot használunk, akkor a
függőleges elemek egymás mellé kerülnek, ha WriteLn-t, akkor legfeljebb csak az
első elem kerül a helyére, a többi biztosan a sor elejére, azaz a már
megrajzolt oldalra, és nem a 20. oszlopba. Úgy néz ki, hogy a Do után nemcsak rajzolni kell, hanem
mindig azt is meg kell mondani, hogy hova, azaz előbb vezérelni a kurzort. Ez
két teljesen különböző utasítás. A Do
után viszont csak egy utasítás állhat ciklusmagként. A megoldás az összetett
utasítás, amelyet a következő listában látunk.
Program
Keret;
Uses
NewDelay, Crt;
Var I: Byte;
Begin
TextMode(CO80);
ClrScr;
For
I:= 1 To 20 Do
Write(Chr(196));
GoToXY(1,1);
For I:= 1 To 5 Do
WriteLn(Chr(179));
GoToXY(1,5);
For I:= 1 To
20 Do
Write(Chr(196));
For
I:= 1 To 5 Do
Begin
GoToXY(20,I);
Write(Chr(179));
End;
ReadLn;
End.
A GoToXY(20,I)
biztosítja, hogy mindig a 20. oszlopba ugrik a kurzor, és ahogy az I nő, úgy
mindig eggyel lejjebb lévő sorba, azaz összeáll a jobb szélső oldal. Tehát a
második, 5-ig menő For ciklus után
egy új szerkezeti elemet találunk, az összetett utasítást. A program bármely,
de általában tartalmilag összetartozó, egymás után elhelyezkedő sorát Begin … End;-ba zárhatjuk. A programnak ezt a
részét összetett utasításnak nevezzük, amely a fordító számára egyetlen
utasításnak számít, teljesen mindegy, hogy egyébként hány tényleges utasítást,
esetleg további összetett utasítást is tartalmaz. Figyeljük meg, hogy ezen
összetett utasítás végén lévő End
után nem pont van, mint a program végén, hanem pontosvessző. Valamint azt is
vegyük észre, hogy a lista megjelenése itt is tükrözi a strukturáltságot, az
összetett utasítás belső utasításait még beljebb írtuk. Ha most futtatjuk
programunkat, láthatjuk, hogy az oldalak már készen vannak, de a négy csúcsa
még nem zárt, oda a megfelelő sarokelemeket még ki kell rajzolni. Ez már nem
jelenthet gondot:
Program
Keret;
Uses
NewDelay, Crt;
Var I: Byte;
Begin
TextMode(CO80);
ClrScr;
For
I:= 1 To 20 Do
Write(Chr(196));
GoToXY(1,1);
For I:= 1 To 5 Do
WriteLn(Chr(179));
GoToXY(1,5);
For I:= 1 To
20 Do
Write(Chr(196));
For
I:= 1 To 5 Do
Begin
GoToXY(20,I);
Write(Chr(179));
End;
GoToXY(1,1);
Write(Chr(218));
GoToXY(1,5);
Write(Chr(192));
GoToXY(20,1);
Write(Chr(191));
GoToXY(20,5);
Write(Chr(217));
ReadLn;
End.
Ezzel a keretrajzoló
programunkat befejeztük. Ha fokozatosan írtuk be, akkor láthattuk a
kialakulásának menetét is. Mentsük ki, mert tanulságos programot írtunk.
7.) Írjunk programot,
amely egy boríték látványát adja a képernyőn, kb. olyat, mint amit a rajz
mutat, majd írjunk rá címzést is.
Mielőtt a programíráshoz
kezdenénk, nézzük csak meg okával, mi is az, amit meg kellene valósítani. Az
ábrán van 7 db keret és 6 db vízszintes vonal. Az előző program egyetlen,
speciális helyzetű keretet rajzol, és 23 sorban sikerült megoldani. Ha az előző
program tapasztalatait felhasználva, új módszer nélkül szeretnénk megoldást
adni, bizony lehet, hogy 200 sornyi programot is kellene írni. De van jobb
megoldás. A hét téglalap rajzolása lényegében ugyanolyan jellegű sorokat
jelentene, csak a képernyő helyeket megadó paraméterekben különböznének. Ha a
programnyelvben egy bizonyos, többször ismétlődő feladatra nincs eljárás, akkor
az lenne a jó, ha magunk is írhatnánk ilyeneket, és ezt a Pascal nyelv lehetővé
is teszi. Az eljárásokat a program elején, a deklarációs részben kell leírni.
Az eljárások csak akkor hajtódnak végre, ha a főprogramban meghívjuk,
használjuk őket. Nézzük, milyen eljárásokat tudnánk használni: a képernyő adott
helyére való írást, vízszintes vonalrajzolót, függőleges vonalrajzolót,
keretrajzolót. Első lépésként ezen eljárások fejét kell megírni. A pascal
nyelvben az eljárás neve: Procedure.
Formailag ugyanúgy néz ki, mint a program, csak magában a programban, annak
deklarációs részében foglal helyet. Ezen eljárások neve legyen: WriteXY,
VVonal, FVonal és Keret.
Program
Boritek;
Uses
NewDelay, Crt;
Procedure
WriteXY;
Begin
End;
Procedure
VVonal;
Begin
End;
Procedure
FVonal;
Begin
End;
Procedure
Keret;
Begin
End;
Begin
End.
Figyeljük meg, hogy
minden eljárást a Procedure
lefoglalt szó vezet be, mindegyiknek van Begin .. End;
-je. A főprogram még nem tartalmaz egyetlen utasítást sem. A már deklarált
eljárásokat pedig már hívhatná is, csakhogy azok végrehajtó része üres, így
semmit sem tennének. Az egész lista csak egy keret, amelyet ezután töltünk meg
tartalommal. De mit is tudjanak ezek az eljárások? A WriteXY eljárás tudjon
megadott helyre egy szöveget kiírni. Azt, hogy hova és mit, azt a híváskor
paraméterként kellene megkapni, így bárhova, bármilyen szöveget vagy karaktert
kiírna. Nézzük csak az eljárást:
Procedure WriteXY(X,Y: Byte; Sz: String);
Begin
GoToXY(X,Y);
Write(Sz);
End;
Az eljárás hívásához
szükséges paramétereket típusával együtt az eljárás neve után, zárójelben kell
felsorolni. A sorrend is számít, mert ugyanilyen sorrendben kell a híváskor a
paramétereket használni. Ebben az eljárásban egy új típust is találunk, amely
mint típusnév, lefoglalt szó: String.
Karakterláncot, vagy magyarosabban szöveget jelent, melynek hossza 0-255 lehet,
és tetszőleges karaktereket tartalmazhat. Érdekes módon a String lefoglalt szó. Az eljárás végrehajtó része magáért beszél.
Ezt az eljárást a következőképpen használhatjuk: WriteXY(40,12,’A’); aminek hatására a képernyő közepére egy „A” betű
kiíródik. A VVonal feladata az, hogy a képernyő kezdő X koordinátájától vég X
koordinátájáig az Y sorba vonalat húzzon. Ez három paramétert jelent, és
használjuk a most megírt WriteXY-t. Az eljárás:
Procedure VVonal(Xk,Xv,Y: Byte);
Var I: Byte;
Begin
For
I:= Xk To Xv Do
WriteXY(I,Y,Chr(196));
End;
Mint látjuk az
eljárásnak magának is lehet változója. Ez az úgynevezett lokális változó. Erről
egy másik eljárás nem tud, csak ez az eljárás használhatja, még a főprogram
sem. A Program kulcsszót követően, a
program globális változóit deklarálhatjuk, mint ahogy azt az eddigi
főprogramjainkban tettük, amelyeket az eljárások és a főprogram is használhat.
Az FVonal feladata az,
hogy függőleges vonalat húzzon az X oszlopba, Y kezdő értéktől, Y vég értékig.
Az eljárás:
Procedure FVonal(X,Yk,Yv: Byte);
Var I: Byte;
Begin
For
I:= Yk To Yv Do
WriteXY(X,I,Chr(179));
End;
Az utóbbi két eljárás
használata: VVonal(20,60,8); illetve FVonal(55,3,22);
az első egy vízszintes vonalat húz a 8. Sorba 20-60 X koordináták között, a
második az 55. Oszlopba függőleges vonalat húz a 3-22 Y koordináták között. Milyen
paraméterek kellenének a Keret eljáráshoz? A válasz: ugyanazok, mint a
Window-hoz. A keretet a bal felső csúcsa és a jobb alsó csúcsa két-két
koordinátája egyértelműen megadja. A megvalósító eljárás:
Procedure Keret(Bfx,Bfy,Jax,Jay: Byte);
Begin
VVonal(Bfx+1,Jax-1,Bfy);
VVonal(Bfx+1,Jax-1,Jay);
FVonal(Bfx,Bfy+1,Jay-1);
FVonal(Jax,Bfy+1,Jay-1);
WriteXY(Bfx,Bfy,Chr(218));
WriteXY(Jax,Bfy,Chr(191));
WriteXY(Jax,Jay,Chr(217));
WriteXY(Bfx,Jay,Chr(192));
End;
Ezt az eljárást Keret(1,1,20,5); paraméterekkel használva a Keret nevű programban megrajzolt
téglalapot kapjuk. Természetesen bármely jól megállapított paraméterekkel
alkalmazhatjuk, ugyanaz vonatkozik a paramétereire, mint a Window eljárásnak.
Nézzük
ezután a teljes Boríték programot:
Program
Boritek;
Uses
NewDelay, Crt;
Procedure WriteXY(X,Y: Byte; Sz: String);
Begin
GoToXY(X,Y);
Write(Sz);
End;
Procedure VVonal(Xk,Xv,Y: Byte);
Var I: Byte;
Begin
For
I:= Xk To Xv Do
WriteXY(I,Y,Chr(196));
End;
Procedure FVonal(X,Yk,Yv: Byte);
Var I: Byte;
Begin
For
I:= Yk To Yv Do
WriteXY(X,I,Chr(179));
End;
Procedure Keret(Bfx,Bfy,Jax,Jay: Byte);
Begin
VVonal(Bfx+1,Jax-1,Bfy);
VVonal(Bfx+1,Jax-1,Jay);
FVonal(Bfx,Bfy+1,Jay-1);
FVonal(Jax,Bfy+1,Jay-1);
WriteXY(Bfx,Bfy,Chr(218));
WriteXY(Jax,Bfy,Chr(191));
WriteXY(Jax,Jay,Chr(217));
WriteXY(Bfx,Jay,Chr(192));
End;
Begin
TextMode(CO80);
ClrScr;
Keret(1,1,80,24);
Keret(69,2,78,6);
Keret(4,17,15,19);
Keret(55,21,57,23);
Keret(59,21,61,23);
Keret(63,21,65,23);
Keret(67,21,69,23);
VVonal(7,30,3);
VVonal(7,25,5);
VVonal(20,60,12);
VVonal(55,76,17);
VVonal(55,74,19);
WriteXY(2,2,'F.a.:');
WriteXY(6,18,'AJÁNLOTT');
WriteXY(71,4,'BÉLYEG');
GotoXY(1,25);
ReadLn;
End.
A teljes lista kb. 50
sorból áll, azaz jóval kevesebb, mint a számított
Megemlítjük még, hogy az
első keret eljárás nem véletlenül tartalmaz 24-et és nem 25-öt. A maximális
méretű keret rajzolására ez az eljárás nem alkalmas. Ez a benne rejlő Write
eljárás tulajdonságaira vezethető vissza. A legnagyobb keret készítése ugyanis
azt igényelné, hogy Write-al írjunk a képernyő utolsó helyére. Ekkor azonban a
kurzor az írás utáni helyre kell, hogy ugorjon. Mivel ilyen nincs (nem úgy,
mint a fentebbi soroknál, ahol ott van a következő sor első helye), ezért a gép
automatikusan soremelést hajt végre, aminek következtében az első sor (azaz a
felső keretvonal) eltűnik. Van rá megoldás, hogy ez ne következzen be, de ilyen
lehetőségekkel majd egy későbbi program kapcsán fogunk megismerni. További
érdekessége még a keret eljárásnak, hogy hibás nagysági-sorrenddel rendelkező
paraméterekkel is rajzol, sarokelemeket mindenképp, oldalakat viszont nem, a
benne rejlő For ciklus visszafelé
nem működik (mármint nagyobb kezdő értéktől a kisebb felé). Akkor sem kapunk
keretet, ha az X értékek, vagy Y értékek megegyeznek (nem úgy a Window
eljárásnál, ott „egy” szélességű vagy magasságú ablak is létrejöhet).
A lista, mint minden
Pascal lista, három fő részből áll, melyek elnevezése: Program és a Uses sora : programfej, Procedure
…End; : deklarációs rész
(lehetne benne Var és egyéb eddig
még nem használt dolog is), Begin … End. : főprogram.
Gyakorló programozási feladatok:
F.8: Írjunk programot, amely az előzőekben
bemutatott, a téglalap rajzolásához szükséges karaktereket és kódjukat jeleníti
meg a képernyőn. (Hasonlóan az előzőekben bemutatott ábrához.)
F.9.: Írjunk programot,
mely egy kocka kiterített felszínét rajzolja a képernyőre. Használjuk a Boritek program keretrajzoló eljárását.
F.10.: Írjunk
programot, mely a nyakas játék játékmezőit rajzolja a képernyőre. Aki nem
ismeri: 8 négyzetből áll, 3 egyes négyzet, majd egy kettős négyzet, majd egy
négyzet (ez a nyak), majd újra 2 négyzet, mindez 6 négyzet magasan, és a kettős
négyzetek egymás mellett vannak az ábra hossztengelyére szimmetrikusan.
F.11: Írjunk programot, amely egy monitor képét
rajzolja a képernyőre. Igyekezzünk a karakteres képernyő lehetőségeit minél
jobban kihasználni az élethű megvalósítása érdekében. A monitoron legyen írás,
esetleg színes, kettős kerete (közte más színnel), legyenek kezelő gombok,
legyen lába (tartója) stb.
8.) Írjunk Unit-ot, mely tartalmazza a Boritek program eljárásait.
Ha jól megnézzük, a Boritek programban deklarált
eljárásokat, azok bizony olyanok, hogy több programban is használhatónak
látszanak. Hogyan lehetne azt elérni, hogy minden program elejére ne kelljen
újra és újra ezeket az eljárásokat leírni, de használni mégis lehessen őket.
Erre találták ki a Pascal fejlesztői a Unit-okat. Erről már a Crt unit kapcsán szó volt, de nemcsak a
fejlesztők által megírt unitok létezhetnek, mi magunk is írhatunk unitokat. Ez
lesz számunkra a kód-újrafelhasználás leggyakoribb példája. Nézzük, hogyan néz
ki egy Unit felépítése:
Unit
CrtPlus;
InterFace
Uses
NewDelay, Crt;
Implementation
End.
A unit neve most CrtPlus,
mely kötelezően meg kell, hogy egyezzen a DOS nevével. A névválasztás arra
utal, hogy a standard Crt Unit kiegészítését célozza. Az InterFace kulcsszó
után kell beírni a Unit-ban használt unitok nevét, valamint a Unit azon eljárásainak a nevét, amelyet a használó programból el
szeretnénk érni. Az Implementation
szó után kell elhelyezni az eljárások kifejtését. Ezt mutatja a teljes lista:
Unit
CrtPlus;
InterFace
Uses
NewDelay, Crt;
Procedure
WriteXY(X,Y: Byte; Sz: String);
Procedure
VVonal(Xk,Xv,Y: Byte);
Procedure
FVonal(X,Yk,Yv: Byte);
Procedure
Keret(Bfx,Bfy,Jax,Jay: Byte);
Implementation
Procedure WriteXY(X,Y: Byte; Sz: String);
Begin
GoToXY(X,Y);
Write(Sz);
End;
Procedure VVonal(Xk,Xv,Y: Byte);
Var I: Byte;
Begin
For
i:= Xk To Xv Do
WriteXY(I,Y,Chr(196));
End;
Procedure FVonal(X,Yk,Yv: Byte);
Var I: Byte;
Begin
For
I:= Yk To Yv Do
WriteXY(X,I,Chr(179));
End;
Procedure Keret(Bfx,Bfy,Jax,Jay: Byte);
Begin
VVonal(Bfx+1,Jax-1,Bfy);
VVonal(Bfx+1,Jax-1,Jay);
FVonal(Bfx,Bfy+1,Jay-1);
FVonal(Jax,Bfy+1,Jay-1);
WriteXY(Bfx,Bfy,Chr(218));
WriteXY(Jax,Bfy,Chr(191));
WriteXY(Jax,Jay,Chr(217));
WriteXY(Bfx,Jay,Chr(192));
End;
End.
Mint látható, a listát
két End zárja, egyik az utolsónak
leirt eljárás End-je, a másik a Unit End-je. Unit csak önállóan szerkeszthető, programon belül nem. Használata
előtt még le kell fordítani, méghozzá lemezre. Ezt a Compile menü Destination
almenüpontjában állíthatjuk be. A lemezen nem *.exe,
hanem *.tpu állomány jön létre. (TPU: Turbo Pascal Unit).
A meglévő Unit-unkat
bővítsük még a következőkkel: gyakran kell a háttér és a betűszint beállítani,
lehessen ezt egy Szinek(HSzin,KSzin) eljárással
megadni.
Procedure Szinek(HSzin,KSzin: Byte);
Begin
TextBackGround(HSzin);
TextColor(KSzin);
End;
Illesszük a Szinek eljárást a
Unitba első eljárásként:
Unit
CrtPlus;
InterFace
Uses
NewDelay, Crt;
Procedure Szinek(HSzin,KSzin: Byte);
Procedure
WriteXY(X,Y: Byte; Sz: String);
Procedure
VVonal(Xk,Xv,Y: Byte);
Procedure
FVonal(X,Yk,Yv: Byte);
Procedure
Keret(Bfx,Bfy,Jax,Jay: Byte);
Implementation
Procedure Szinek(HSzin,KSzin: Byte);
Begin
TextBackGround(HSzin);
TextColor(KSzin);
End;
...
End.
A továbbiakban, ha olyan
eljárást írunk, amely több programban is használható, újra így járjunk el. Ne
felejtsük újra lemezre lefordítani a Unit-ot. Nézzük
meg, a CrtPlus segítségével hogyan néz ki a Boritek
listája:
Program
Boritek;
Uses
NewDealay, Crt, CrtPlus;
Begin
TextMode(CO80);
Szinek(Blue,Yellow);
ClrScr;
Keret(1,1,80,24);
Keret(69,2,78,6);
Keret(4,17,15,19);
Keret(55,21,57,23);
Keret(59,21,61,23);
Keret(63,21,65,23);
Keret(67,21,69,23);
VVonal(7,30,3);
VVonal(7,25,5);
VVonal(20,60,12);
VVonal(55,76,17);
VVonal(55,74,19);
WriteXY(2,2,'F.a.:');
WriteXY(6,18,'AJÁNLOTT');
WriteXY(71,4,'BÉLYEG');
GotoXY(1,25);
ReadLn;
End.
Unit-unk eljárásait
tehát csak akkor használhatjuk, ha magát a Unit-ot
használatba vettük. Ez történt a program második sorában: Uses Crt, CrtPlus;.
9.)
Irjunk programot, melyet futtatva a gép véletlen méretű és szinű keretes,
cimkés, árnyékos ablakokat rajzol a képernyőre, közben változó magasságú hangot
ad. A program futása bármely billentyű megnyomására álljon le.
Gyakran fordul elő
felhasználói programokban, hogy a képernyőn keretes ablak jelenik meg, melyben
a gép valamire figyelmeztet, esetleg valamilyen választást kínál fel, vagy
menüt. Szépen megírt programjainkban nekünk is szükségünk lehet ilyen ablakokra
többször is, így célszerű az ablak eljárást a CrtPlus Unit-unkban megírni.
Hogyan is néz ki egy ablak? Már rajzoltunk téglalapot is, keretet is. Ha ezeket
„egymásra” helyezzük, akkor keretes ablakot kapunk, legyen az ablaknak címkéje,
és igény szerint árnyéka is. Helyezzük ezt az eljárást utolsó helyre a
CrtPlus-ban.
Unit
CrtPlus;
InterFace
Uses
NewDelay, Crt;
...
Procedure
Ablak(HSz,KSz,Bfx,Bfy,Jax,Jay: Byte; Arny: Boolean; C:
String);
Implementation
...
Procedure Ablak(HSz,KSz,Bfx,Bfy,Jax,Jay: Byte; Arny: Boolean; C: String);
Var Px,Py: Byte;
Begin
If
Arny Then
Begin
Px:= Jax+2;
Py:= Jay+1;
If
Px>80 Then
Px:= 80;
If
Py>25 Then
Py:= 25;
Window(Bfx+2,Bfy+1,Px,Py);
Szinek(Black,Black);
ClrScr;
End;
Window(Bfx,Bfy,Jax,Jay);
Szinek(HSz,KSz);
ClrScr;
Window(1,1,80,25);
Keret(Bfx+1,Bfy,Jax-1,Jay);
If
C<>'' Then
WriteXY(Round(Bfx+(Jax-Bfx-Length(C))/2-1),Bfy,' '+C+' ');
End;
End.
Az Ablak eljárás készítésekor szükség van egy tesztprogramra, melyet
minden módosítás után futtathatunk, és így láthatjuk a kialakítás helyes
menetét.
Program
AblTeszt;
Uses
NewDelay, Crt, CrtPlus;
Begin
TextMode(CO80);
Szinek(Cyan,White);
ClrScr;
Ablak(15,0,
20,5,60,15, True, ’Ablak’);
GoToXY(1,25);
ReadLn;
End.
Az Ablak eljárás számos új dolgot tartalmaz. Az első mindjárt az Arny: Boolean deklaráció. A feladat azt kéri, hogy lehessen az
ablaknak árnyéka is, azaz, az eljárást ilyen szempontból lehessen kétféleképpen
meghívni, árnyékkal és árnyék nélkül is. Ezt úgy érhetjük el, hogy az eljárás
paraméterei közé felveszünk egy logikai változót, ez az Arny, melyet a Pascal Boolean típusnak nevez. Egy logikai változó
két értéket kaphat, illetve vehet fel, ezek: True vagy False, azaz
Igaz vagy Hamis. Az eljárásunknak biztosan lesz egy olyan szakasza, melyet a
szerint kell vagy nem végrehajtani, hogy kell-e árnyék vagy nem. Mivel az
árnyék egy, az ablakhoz képest jobbra és lefelé eltolt fekete téglalap, ezért
ezt kell hamarabb megrajzoltatni az eljárásban. Az eljárás tehát ezzel
kezdődik, és itt a második új dolog az If … Then … Else szerkezetű programszakasz. A lista
utasításainak végrehajtási sorrendjét (a szekvenciát), eddig a For ciklus (iteráció)
változtatta meg. De az If
…Then … szerkezet, vagyis a szelekció
egyik fajtája is meghatározhatja. Az If
azt jelenti: ha, a Then: akkor. Az If-fel kezdődő programrészletet így
olvashatjuk: Ha igaz, hogy kell árnyék, akkor a következőt tedd: Begin … End;. A Then is csak egy utasításra vonatkozik, mint a Do, ezért, ha több mindent kell tenni, akkor összetett utasítást
kell alkalmaznunk. Az Else, ami
egyébként-et jelent itt nem alkalmaztuk, mert nem volt rá szükség, az árnyék
helyett nem kellett valami mást rajzolni. Lesz majd a későbbiekben olyan
program, amelyben szükség lesz rá. Maga az árnyékrajzolás nagyon egyszerű,
kiolvasható a jobbra kettővel, lefelé eggyel való ablakeltolás, a fekete
háttérszín és írásszín beállítása. (A későbbiekben lehet, hogy ezt nem árt
pontosítani, megvizsgálni, hogy az így keletkezett Window ablak megnyitható-e,
mert ha nem, akkor a ClrScr másra vonatkozhat. De most ezzel nem bonyolítjuk az
eljárásunkat.) Az eljárás további része az ablakot rajzolja. Először megnyitja
a megfelelő ablakot, és a megadott színnel törli, majd visszaállítja a teljes
képernyőt és a megnyitott ablak területre egy szűkebb keretet rajzol (+1 és –1
értékek), így lesz keretes ablak a képernyőn. Még az utolsó sor is tartogat
újdonságokat. Ez csak akkor hajtódik végre, ha a C címke nem üres szöveg. A
címkét a keretre, annak felső részére, sőt középre illik helyezni. Ezt a
pozíciót határozza meg a WriteXY első paraméterében leírt kifejezés. A kiírás
helye az ablak (közepe-címke hossza)/2. A C címke hosszát a Length függvény
határozza meg, mely természetesen bármely szöveges változóra alkalmazható. (A
szöveges változókra vonatkozó műveletekkel, eljárásokkal és függvényekkel egy
külön szakasz foglalkozk.) A kettővel való osztás a változók típusát valósra
állítja, a WriteXY viszont Byte-ot, azaz egészet vár, ezért a Round függvény,
mely a benne lévő kifejezést kerekíti és egész
típusúra változtatja. Azért, hogy a címke betűjéhez a keretvonal ne érjen hozzá
előtte és utána még egy Space-t is írtunk, ez eggyel csökkenti a kiírás X
koordinátáját. A kiírandó szöveget összeadással, a String típusú változók
között értelmezett egyetlen művelettel oldottuk meg. Elkészült az ablak
eljárásunk, most már nézhetjük a kitűzött feladatot. A véletlen számok
előállításának megismerésére, először csak véletlen számokat (például
lottószámokat) kiíró programot fogunk írni.
Program
Ablakok;
Uses
NewDelay, Crt, CrtPlus;
Begin
TextMode(CO80);
ClrScr;
Repeat
Write(Random(90)+1:3);
Delay(300);
Until
KeyPressed;
End.
Megfigyelhetjük, hogy
Randomize nélkül minden gép, mindig ugyanazon számokat adja. A +
Program
Ablakok;
Uses
NewDelay, Crt, CrtPlus;
Begin
TextMode(CO80);
Repeat
Ablak(Random(8),
Random(16), Random(80)+1, Random(25)+1,
Random(80)+1,
Random(25)+1, true, ’’);
Sound(100*Random(80));
Delay(150);
Until
KeyPressed;
NoSound;
End.
A program természetesen
használja a Crt és CrtPlus unitot is. Azt, hogy egy programrészletet
akárhányszor, azaz bizonytalan sokszor ismételjen a program, nem lehet (vagy
nem célszerű) a már ismert ismétlő eljárással, a For ciklussal megoldani. Olyan ismétlő eljárás kellene, amely
leállító feltétele tőlünk, egy programon kívüli tevékenységtől függ. Ilyen
ismétlő eljárás a Repeat
… Until …. Repeat: ismételd, Until: mindaddig, míg nem. Az ismétlésre szánt programrészletet a
két kulcsszó közé, természetesen bekezdésesen kell leírni. Az ismétlő eljárás
leállító feltételét az Until után
kell írni. Az ismétlés mindaddig folytatódik, ameddig a feltétel igazzá nem
válik. Mivel a feltétel az ismételendő programrészlet után van, vagyis ez egy
hátul tesztelő ciklus, így a ciklusmag legalább egyszer végrehajtódik. A
feltétel valamilyen logikai kifejezés, vagy függvény, esetleg konstans. Most a
leállítás a billentyűzeten való írás, ezért olyan logikai függvény kell, amely
hamis, ha nem nyomtak meg billentyűt, (azaz a billentyűzet puffer üres), és
igaz ellenkező esetben. Ez a logikai függvény a KeyPressed (= kulcs megnyomva).
Az ismétlés három
eljárás hívására vonatkozik: Ablak, Sound és Delay. Mindhárom tartalmaz
ismeretlen dolgokat. Az Ablak paramétereinek véletlen értékeket kell
tartalmaznia. Véletlen számok előállítására a Random függvény alkalmas.
Paraméteresen használva: Random(n), a paramétere
egész, és visszaadott értéke 0 és n-1 közötti egész szám. Paraméter nélkül a
visszaadott érték 0 és 1 közötti valós szám. Ahhoz tehát, hogy 1 és 80 közötti
számot kapjunk a Random(80)-hoz még hozzá kell adni
1-et. (Ha 50 és 60 közötti véletlen számot akarunk, akkor Random(60-50+1)+
Gondolhatnánk, hogy
ezzel a feladatot megoldottuk. De azért ez nem teljesen van így. Ha jól
megnézzük a képernyőt futás közben, bizony furcsa dolgokat látunk, pl.:
változik a hang, a képernyő viszont nem. Ez hogy lehet? Miért nem rajzol néha a
program. Hát azért nem, mert az Ablak eljárást vizsgálat nélküli véletlen
paraméterekkel hívtuk meg. Így előfordul, hogy nem tudja a gép az ablakot
felrajzolni. A következő változat ezen próbál segíteni. Azt kellene elérni,
hogy a véletlen értékek nagyságrendje megfeleljen a hívási feltételeknek. Ezért
a választás után még meg is kell vizsgálni. Ez csak úgy lehetséges, ha az
értékeket változókba mentjük, sőt a cseréhez még egy ötödik változó is kell, ez
a Puf nevű. A másik gond az, hogy így mindig ugyanazon értéksor szerint jönnek
létre az ablakok, akárhányszor indítjuk el a programot, sőt akármelyik gépen.
Azért, hogy a véletlen, valóban véletlen legyen, a véletlen függvény meghívása
előtt meg kell hívni a Randomize eljárást. Ezt láthatjuk a Repeat előtt.
Program
Ablakok;
Uses
NewDelay, Crt, CrtPlus;
Var Bfx,Bfy,Jax,Jay,Puf: Byte;
Begin
TextMode(CO80);
Randomize;
Repeat
Bfx:= Random(80)+1;
Bfy:= Random(25)+1;
Jax:= Random(80)+1;
Jay:= Random(25)+1;
If
Bfx>Jax Then
Begin
Puf:= Bfx;
Bfx:= Jax;
Jax:= Puf;
End;
If Bfy>Jay Then
Begin
Puf:= Bfy;
Bfy:= Jay;
Jay:= Puf;
End;
Ablak(Random(8),Random(16),Bfx,Bfy,Jax,Jay,
true, ’’);
Sound(100*Bfx);
Delay(150);
Until
KeyPressed;
NoSound;
End.
A véletlen értékek tehát
a Bfx, Bfy, Jax, Jay változókba kerültek. Külön teljesülni kell, hogy Bfx<Jax és Bfy<Jay. Ha ez nem így van, akkor a program a két If utáni összetett utasításban az értékekeket felcseréli. A cserét úgynevezett ciklikus
cserével oldja meg. A Puf változó a
valódiak ideiglenes tárolására lettek deklarálva. Vegyük figyelembe azt
is, hogy a Bfx, Bfy maximális értéke kisebb mint 80 illetve kisebb mint
Program
Ablakok;
Uses
NewDelay, Crt, CrtPlus;
Var Bfx,Bfy,Jax,Jay,Puf: Byte;
I: Integer;
Sz:String;
Begin
TextMode(CO80);
Randomize;
Repeat
Inc(I);
Bfx:= Random(76)+1;
Bfy:= Random(22)+1;
Jax:=
Random(78)+1;
Jay:= Random(23)+1;
If
Bfx>Jax Then
Begin
Puf:= Bfx;
Bfx:= Jax;
Jax:= Puf;
End;
If
Bfy>Jay Then
Begin
Puf:= Bfy;
Bfy:= Jay;
Jay:= Puf;
End;
Str(I,Sz);
Ablak(Random(8),Random(16),Bfx,Bfy,Jax,Jay,True,Sz);
Sound(100*Bfx);
Delay(150);
Until
KeyPressed;
NoSound;
End.
Most is látunk
újdonságot. Az I típusa: Integer, azaz egész. Értéke -32768 –től +32767-ig
változhat most azért, hogy lehetőségünk legyen akár több száz, vagy ezer
ablakot is a képernyőre rajzolni, illetve eddig számolni. A következő az Inc
eljárás, melyet I-re alkalmazva annyit tesz, hogy értékét 1-el növeli, azaz
számol. Az I változóban az ablak sorszáma lesz tárolva, tehát ezt kell
szövegként az ablak eljárásnak átadni, és itt az utolsó újdonság, a számot String-é kell alakítani. Ezt végzi az
Str eljárás, melynek első paramétere egy szám, második paramétere az a String, amelybe a számot String-ként írja, itt Sz. A keltett hangot, az egyébként is véletlenül létrejövő Bfx
segítségével határoztuk meg. Ezzel a feladatot maradéktalanul megoldottuk.
10.) Írjunk programot,
amely az 1-10 szorzótáblát irja a képernyőre.
Ismét olyan feladatunk
van, amelyben alkalmazhatjuk a CrtPlus rajzoló eljárásait. A program futása
végén ismét el kell tüntetni a kurzort és meg kell állni a programnak, hogy az
eredményt szemügyre vehessük. Ezekre a feladatokra célszerű újabb eljárásokat
írni. Az eddig alkalmazott GoToXY(1,25) csökkentett
képernyő ablakban nem használható, mert lehet, hogy ilyen hely nincs is a
képernyőn. A ReadLn-al pedig az a gond, hogy írhatunk közben a képernyőre,
elrontva a látványt. Legyen az első eljárás neve, mely félreállítja a kurzort:
Tunj;
Procedure
Tunj;
Begin
GoToXY(1,Hi(WindMax)-Hi(WindMin)+1);
End;
Ennek kapcsán egy új
változótípussal kell megismerkednünk, a Word típussal. Mint tudjuk az 1 byte=8
bit, mely 0-255 egészet jelent. Ismerkedjünk meg a 16-os vagy hexadecimális
számrendszerrel. Ennek számjegyei: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E
és F, azaz 16 számjegy, melyből az első tíz a tízes számrendszer jegyei, a
további hat az angol ABC első hat betűje. (A=10, B=11, C=12, D=13, E=14 és
F=15). Az F a 16-os számrendszer kilenceseként viselkedik, ha 1-et hozzáadunk a
legkisebb kétjegyű számot kapunk: 10-át (olv.: egy, nulla-t). A legnagyobb
egyjegyű 16-os számrendszerbeli szám tehát az F=15, a legnagyobb kétjegyű: FF=16*16-1=255, a legnagyobb 4 jegyű FFFF=256*256-1=65535.
Az F kettes számrendszerbeli alakja: F=1111, azaz 4 bit, így a byte (0-FF)
valóban 8 bit, míg a 0-FFFF két byte (azaz 16 bit). Az Integer típust már
megismertük, melyet 2 Byte-on (azaz 16 biten) a gép úgy ábrázol, hogy az első
bit jelenti az előjelet, 0=pozitiv, 1=negativ-at jelent. Ezért lehet az egész
értékhatára –32768-tól +32767-ig. Most térünk át egy új típusra: a 0-FFFF, azaz
0-65535 intervallumba eső egész számok Word típusúak. Ennek szokták
megkülönböztetni alsó és felső byte-ját. Néha egy Word típusú változóban tárol
a gép két adatot (Byte-ot), melyeket a Lo és Hi függvényekkel lehet egyszerűen
lekérdezni. Ezt látjuk a Tunj eljárásban is. Az, amiben a gép most két adatot
tárol, az a WindMin és a WindMax előre definiált és lefoglalt változók. Amikor
a Window eljárást meghívjuk, lényegében ezekbe a változókba írunk olyan
értékeket, amellyel kialakulnak az aktuális ablakkoordináták. (Külön is érdekes
lehet megvizsgálni, milyen értékek jelentik az alapképernyő beállítást,
egyszerűen írassuk ki a két értéket!). A WindMin tartalmazza a bal felső, a
WindMax a jobb alsó csúcs két koordinátáját, Y-X sorrendben, azaz Lo(WindMin)+1 jelenti a bal felső csúcs X koordinátáját
(azaz az alsó byte), míg Hi(WindMax)+1 jelenti a jobb alsó csúcs Y
koordinátáját (azaz a felső byte). E két koordináta adja az aktuális ablak bal
alsó csúcs két koordinátáját. Így alakult ki a GoToXY eljárás két paramétere.
A
következő két eljárás a ReadLn-t váltja ki:
Procedure
KeyEmpty;
Begin
While
KeyPressed Do ReadKey;
End;
Procedure
Varj;
Begin
Repeat
Until KeyPressed;
KeyEmpty;
End;
Nézzük először a Varj
(várj) eljárást. Ismerős ismétlő eljárást találunk benne, csak az ismételendő
eljárások hiányzanak, így semmit nem tesz, csak várakozik arra, hogy a
KeyPressed igazzá váljon. Ez akkor következik be, ha megnyomjuk valamelyik
billentyűt. De mi az a KeyEmpty és mire szolgál? Ha a Varj ismétlő eljárását
leállítottuk, a tevékenységünknek az a következménye, hogy a billentyűzet
pufferbe bekerül a billentyű kódja (illetve kódjai, ha kettőskódúak, pl.: a
funkció billentyűk). Ennek eredményeképpen, ha csak ebből állna a Varj,
legközelebb eredménytelen lenne, hiszen a billentyűzet pufferben az előző
várakozás miatt már van valami, így nem állna meg a program. Ezt megelőzendő, a
billentyűzet puffert ki kell üríteni. Ezt teszi a KeyEmpty
(=billentyűzet-ürítő) eljárás. De ebben is ismeretlen dolgot látunk. Itt az
ideje megismerkedni a harmadik és egyben utolsó ismétlő eljárással, a While … Do –val. Ez egy elől tesztelő ismétlő
eljárás, a két kulcsszava közé írt logikai kifejezés, függvény vagy konstans
logikai értékétől függően hajtja végre a Do
utáni egyetlen utasítást (de lehet az összetett is!). Ha a logikai érték igaz,
akkor végrehajtja, ha nem, akkor nem. Így példánkban mindaddig, amíg a
billentyűzet puffer ki nem ürül. Nyilván a Do
utáni eljárás végzi a tényleges ürítést. Azaz a ReadKey, mely egy függvény,
melyet most eljárásként hívtunk meg, mert a visszaadott értékre nincs
szükségünk (Függvényként így kellene használni: Ch:= ReadKey; ekkor a
billentyűzet pufferből egy karakter a Ch változóba kerülne.) Ezzel mindhárom
eljárást megismertük. Illesszük CrtPlus Unit-unkba a következő sorrend szerint.
Unit
CrtPlus;
InterFace
Uses
NewDelay, Crt;
Procedure
KeyEmpty;
Procedure
Varj;
Procedure
Tunj;
Procedure
Szinek(HSz,KSz: Byte);
Procedure
WriteXY(X,Y: Byte; Sz: String);
Procedure
VVonal(Xk,Xv,Y: Byte);
Procedure
FVonal(X,Yk,Yv: Byte);
Procedure
Keret(Bfx,Bfy,Jax,Jay: Byte);
Procedure Ablak(HSz,KSz,Bfx,Bfy,Jax,Jay:
Byte; Arny: Boolean; C: String);
Implementation
Procedure
KeyEmpty;
Begin
While
KeyPressed Do ReadKey;
End;
Procedure
Varj;
Begin
Repeat
Until KeyPressed;
KeyEmpty;
End;
Procedure
Tunj;
Begin
GoToXY(1,Hi(WindMax)-Hi(WindMin)+1);
End;
. . .
End.
A SzorzoTb nevű programunk is tartogat néhány újdonságot. Az első
mindjárt az, hogy végre nem hajtandó, magyarázó sorokat tartalmaz. Ha egy
program részletéhez, vagy az egészhez magyarázó szöveget szeretnénk elhelyezni
magában a program listájában, akkor azt kétféleképpen tehetjük meg. Vagy az End. után
írjuk, vagy az eljárások közé. Ha az előző megoldást választjuk, akkor nincs
semmi megkötés a megjegyzés, magyarázat formájára, azt írunk, amit akarunk. Ha
a listába szeretnénk elhelyezni, akkor viszont speciális határoló-jelek közé
kell tenni, ez pedig vagy a kapcsos nyitó és záró zárójel, vagy – amint az a
listából is látszik – gömbölyű zárójel és csillag együttese. Helyére
vonatkozóan az a megkötés, hogy úgy kell beírni, mintha a megjegyzés is egy
eljárás, vagy függvény vagy annak hívása volna (nem
helyezhető pl.: valamely lefoglalt szó belsejébe).
Program
SzorzoTb;
Uses
NewDelay, Crt, CrtPlus;
Var I,J: Integer;
Begin
TextMode(CO80);
Szinek(1,14);
ClrScr;
WriteXY(35,1,'Szorzótábla');
WriteXY(13,3,'*');
(* A négyzetrács megrajzolása: *)
Keret(15,4,65,24);
For
I:= 1 To 10 Do FVonal(5*I+10,3,23);
For
I:= 1 To 10 Do VVonal(11,64,2*I+2);
For
I:= 1 To 10 Do For J:= 1 To 10 Do
WriteXY(5*I+10,2*J+2,Chr(197));
For
I:= 1 To 9 Do WriteXY(5*I+15,24,Chr(193));
For
I:= 1 To 9 Do WriteXY(65,2*I+4,Chr(180));
(* Oszlopfej és sorfej kiírása: *)
For
i:=1 To 10 Do
Begin
GoToXY(5*I+12,3);
Write(I:2);
GoToXY(12,2*I+3);
Write(I:2);
End;
(* A táblázat belsejének kiírása: *)
For
I:= 1 To 10 Do For J:= 1 To 10 Do
Begin
GotoXY(5*I+11,2*J+3);
Write(I*J:3);
End;
Tunj;
Varj;
End.
A következő újdonság az,
hogy itt látunk először egymásba ágyazott For
ciklusokat. Ehhez két ciklusváltozó szükséges. Az először leirt ciklus a külső,
a második a belső. Futás közben a belső ciklusváltozó változik minden lépésben,
a külső csak akkor, amikor egy belső teljesen lejátszódik, ekkor viszont a
belső újra indul. A kétszeres For
ciklus például kétdimenziós táblázatok készítésére használhatjuk, vagy mint azt
a program is mutatja négyzetrácsos papírlap mintázatát
rajzolhatjuk a képernyőre. Egymásba ágyazott For ciklus rajzolja meg a vonalak találkozását, valamint írja ki a
szorzat értékeit a négyzetekbe. A For
ciklusok belsejében, az I és a J változók segítségével számítjuk ki a képernyő
helyeket, figyelembe véve, hogy milyen messze kell lenni az egyes helyeknek
egymáshoz képest (ez lesz a ciklusváltozó szorzótényezője, a pontos kezdést a
hozzáadott érték szolgáltatja). Adatok táblázatos megjelenítésére gyakran lehet
szükség, ezért célszerű megjegyezni a most alkalmazott módszert. A program
utolsó két utasítása a fentebb ismertetett Tunj és Varj.
A most elkészített
programban szintén van egy olyan szakasz, amelyet több későbbi programban is
hasznosítani lehetne. Ez pedig, a négyzetrács megrajzolása. Gyakran előfordulhat
ugyanis, hogy adatainkat táblázatosan jelenítjük meg, és ennek mintegy keretét
adja az említett rács. Gondolkozzunk el rajta, hogy egy általános rács
eljárásnak milyen paraméterekkel kellene rendelkeznie. Meg kellene adni a bal
felső csúcs két koordinátáját, azt, hogy x és y irányban milyen legyen egy
cella belső mérete, valamint azt, hogy x és y irányban hány cellát tartalmazzon
a rács. Így a paraméterek:
Bfx:
bal felső csúcs x koordináta,
Bfy:
bal felső csúcs y koordináta,
Bx:
a cellák x irányú belső mérete,
By:
a cellák y irányú belső mérete,
Nx:
a cellák száma x irányban,
Ny:
a cellák száma y irányban.
Lesz
még két lokális változó:
Sx:
jobb alsó csúcs kiszámított x koordinátája,
Sy:
jobb alsó csúcs kiszámított y koordinátája.
Az eljárás neve legyen Racs. Helyezzük a keret eljárás után a
CrtPlus-ba. Azért ide, mert a rács eljárást meghívhatjuk olyan paraméterekkel,
hogy az csak keretet rajzoljon, tehát speciális esetként a Keret eljárást lefedi.
Unit
CrtPlus;
InterFace
Uses
NewDelay, Crt;
. . .
Procedure Keret(Bfx,Bfy,Jax,Jay:
Byte);
Procedure
Racs(Bfx,Bfy,Bx,By,Nx,Ny: Byte);
. . .
Implementation
. . .
Procedure Racs(Bfx,Bfy,Bx,By,Nx,Ny: Byte);
Var I,J,Sx,Sy: Byte;
Begin
If
Nx*Ny=0 Then Exit;
Sx:=Bfx+Nx*(Bx+1);
Sy:=Bfy+Ny*(By+1);
Keret(Bfx,Bfy,Sx,Sy);
I:= Bfx+Bx+1;
While
I<Sx Do
Begin
WriteXY(I,Bfy,Chr(194));
WriteXY(I,Sy,Chr(193));
FVonal(I,Bfy+1,Sy-1);
Inc(I,Bx+1);
End;
J:= Bfy+By+1;
While
J<Sy Do
Begin
WriteXY(Bfx,J,Chr(195));
WriteXY(Sx,J,Chr(180));
VVonal(Bfx+1,Sx-1,J);
Inc(J,By+1);
End;
For
I:= 1 To Nx-1 Do For J:= 1 To Ny-1 Do
WriteXY(Bfx+I*(Bx+1),Bfy+J*(By+1),Chr(197));
End;
. . .
End.
A
következő kis program a most megírt Racs
eljárást teszteli:
Program
RacsTest;
Uses NewDelay,
Crt, CrtPlus;
Begin
TextMode(CO80);
ClrScr;
Racs(10,5,3,2,10,5);
Tunj;
Varj;
End.
Ha a későbbiek során rácsra lesz szükségünk,
akkor a CrtPlus-ban a rendelkezésünkre áll. A RacsTest névadás némi magyarázatra szorul: miért nem írtuk ki
teljesen magyarul a Teszt szót? Azért, mert így a fájlnév hossza nem több mint
8 karakter, az IDE viszont ennél hosszabbat nem tud megjeleníteni, ha mégis
hosszabb a fájlnév, akkor ~ jellel és sorszámmal cseréli ki a nevek végét, mely
azonos kezdetű neveknél zavaró lehet.
11.) Írjunk programot,
amely egy üres sakktáblát rajzol a képernyőre.
Ahhoz, hogy a tábla a
lehetető legnagyobb legyen, 3 karakter magasnak kell lennie egy mezőnek
(3*8=24). A képernyő egy karaktere nem négyzet, hanem téglalap alakú. Kb. kétszer
olyan magas mint széles. Kísérletezéssel
megállapítható, hogy az arányt a 7:3 fejezi ki legjobban. Egy mező tehát 3*7
lesz. A sakktábla látványa úgy fog kialakulni, hogy ahol világos mező van, oda
teljes kitöltő fehér karaktereket rajzolunk (#219), ahol sötét, oda
nem rajzolunk semmit. A színeket tehát feketén-fehérre állítjuk. A táblát egy
négyszeres For ciklus rajzolja meg.
8*8 a mezőket, a 7*3 a karakterek adják. A feltételes rész két újdonságot
tartalmaz: az Odd függvény az argumentumába írt egész szám párosságát
állapítja meg, a visszaadott értéke páros esetén False, páratlan esetén True. A
páratlanság vizsgálata azért jó a sakktábla megrajzolásához, mert az átlósan
elhelyezkedő mezők indexei összegének a párossága azonos, így lehet azonosan
színezni őket. A másik újdonság a Not,
ami tagadást jelent, egy egyváltozós logikai függvényt, mely a logikai értéket
az ellenkezőjére változatja. A program további része már a tanultak alapján
teljesen egyértelmű. A lista:
Program
SakkTbl;
Uses
NewDelay, Crt, CrtPlus;
Var I,J,K,L: Byte;
Begin
TextMode(CO80);
Szinek(0,15);
ClrScr;
For
I:= 1 To 8 Do For J:= 1 To 8 Do
For
K:= 1 To 7 Do For L:= 1 To 3 Do
If
Not Odd(I+J)
Then
WriteXY((I-1)*7+K,(J-1)*3+L,Chr(219));
For
I:= 1 To 8 Do
Begin
WriteXY((I-1)*7+4,25,Chr(96+I));
WriteXY(58,26-I*3,Chr(48+I));
End;
Tunj;
Varj;
End.
Rendszerezés:
A
program végrehajtási sorrendjét meghatározó szerkezetek:
1. Szekvencia: a gép az
utasításokat olvasási sorrendben hajtja végre.
2. Iteráció (ismétlés):
-
For ciklus: elől tesztelő
léptető iteráció (lépések száma előre ismert);
-
Repeat ciklus: hátul tesztelő
ismétlő eljárás;
-
While ciklus: elől tesztelő
ismétlő eljárás.
4. Szelekció (kiválasztás):
-
GoTo: feltétel nélküli ugrás
(csak ritkán használjuk);
-
If .. Then .. Else: egyszerű elágazás;
-
Case: többszörös elágazás.
5. Feltétel nélküli ugró
utasítások:
-
GoTo Címke – a program a
Címke-vel megjelölt helyen folytatja, blokkba (függvény vagy eljárás) beugrani
nem lehet, lehetőleg kerüljük a GoTo
használatát
-
Exit: blokkból való kilépés,
-
Halt: programból való
kilépés.
Programhelyesség:
-
Szintaktikai:
helyesírási hiba, a hiba fordításkor kiderül;
-
Szemantikai:
tartalmi helyesség, a hiba csak futáskor derül ki; vagy nem azt teszi a
program, amit kellene, vagy futási hibával (Run Time Error) leáll a program,
pl.: 0-val való osztás.
12.)
Írj programot, amely egy táblázatban 1-től 20-ig kiírja a számokat, a
négyzetüket, köbüket, négyzetgyöküket, SIN, COS és TAN értéküket (elsősök
esetén a szögfüggvények helyett az 1/x értékeit) (utóbbi esetben a számokat
fokoknak gondoljuk).
A program kapcsán
megismerkedhetünk a legalapvetőbb matematikai függvényekkel. A négyzetet és
köböt a legcélszerűbb szorzatként leírni. A szám négyzetgyökét az Sqrt függvény
szolgáltatja, amelynek argumentuma természetesen nem lehet negatív. A sin és
cos függvények argumentumát radiánban kell megadni, ezért szerepel a listában a
*pi/180, ahol a pi a kör kerületének és átmérőjének az aránya, azaz a
matematikából ismert konstans. Az Sqrt, sin, cos és sin/cos visszaadott értékei
valós (Real) számok, melyeket a gép alapértelmezésként normál alakban ír a
képernyőre. Ez nehezen olvasható, ezért a kiíráskor a tizedes tört alakot
választottuk. Erre való a számok után a:12:4 rész.
Ennek jelentése: a tizedes törtet 12 karakterhelyen (tizedes pontot is
beleértve), 4 tizedes hellyel jelenjen meg. A program további része a
keretrajzolás. Azért került a program végére, hogy a táblázat belsejét
WriteLn-nel lehessen írni. Fordított sorrend esetén a táblázat keretvonalait a WriteLn
letörölte volna.
Program
Tablazat;
Uses
NewDelay, Crt, CrtPlus;
Var I:
Integer;
Begin
TextMode(CO80);
Szinek(1,14);
ClrScr;
WriteXY(32,1,'Függvénytáblázat');
WriteXY(2,3,'Szám Négyzet Köb
Négyzetgyök Sin(x) Cos(x)
Tan(x)');
GoToXY(1,5);
For I:= 1 To 20 Do WriteLn(I:4, I*I:12, I*I*I:12,
Sqrt(I):12:4, Sin(I*Pi/180):12:4, Cos(I*Pi/180):12:4,
Sin(I*Pi/180)/Cos(I*Pi/180):12:4);
Keret(1,2,79,25);
For
I:= 1 To 6 Do FVonal(I*12-5,3,24);
VVonal(2,78,4);
For
I:= 1 To 6 Do
Begin
WriteXY(I*12-5,2,Chr(194));
WriteXY(I*12-5,4,Chr(197));
WriteXY(I*12-5,25,Chr(193));
End;
WriteXY(1,4,Chr(195));
WriteXY(79,4,Chr(180));
Tunj;
Varj;
End.
Gyakorló programozási feladatok:
F.12:
Írjunk programot, amely a 15-ös játék mezőit a rendezett számokkal kiírja a
képernyőre.
13.) Írj programot,
amely egy egydimenziós számtömböt kezel. Megkérdezi, hány elemű a tömb, aztán
beolvassa a tömböt, majd megkeresi a legnagyobbat és legkisebbet, kiszámítja a
számok átlagát, végül növekedő sorrendben kiírja a számokat a képernyőre.
Eddigi programjainkban
az ismétlő eljárások szerepe az volt, hogy egy programrészletet többször is
végre kellett hajtani, leírni viszont csak egyszer írtuk le. Ez a program arra
ad megoldást, hogyan lehet nagyszámú ismeretlent kezelni. Gyakran előfordul
ugyanis, hogy egy programban több száz, esetleg több ezer adat szerepel.
Értékeinek tárolására tehát nagyon nagyszámú változóra lenne szükség.
Szerencsére, nagyon gyakran, a nagyszámú adat ugyanolyan jellegű. Ezek
tárolására a matematikából ismert vektort vagy mátrixot használják a
programnyelvek. Itt ezeket tömböknek nevezzük. Aszerint, hogy hány index
segítségével írhatók le, léteznek egy-, két- esetleg három-, négy- vagy
magasabb dimenziójú tömbök. Egy egyszerű névsor egydimenziós, de egy ülésrend,
vagy egy órarend kétdimenziós. Ebben a programban egydimenziós számtömbbel
találkozhatunk.
A tömb azonosítója: sz. A tömb elemeit indexek segítségével írhatjuk le. Az
indexeket szögletes zárójelben kell feltüntetni: Sz[8]
jelenti az Sz tömb 8. elemét. A tömb deklarációját az Array … Of
szópár segítségével adjuk meg. Az Array után fel kell tüntetni az indexeket [kezdőérték
.. végérték] formában, mely leggyakrabban egész
szám. Kezdőérték és végérték tetszőleges lehet, az indexek egyesével
növekszenek. Az index csak sorszámozott típus lehet, azaz: byte, integer, word,
char, logikai felsorolt és intervallum. A Of utáni típusnév határozza meg a tömb
elemeinek típusát, ez példánkban egész. Magasabb dimenziójú tömbnél a
további indexek felsorolását vesszővel kell elválasztani, pl.:
T: Array[1..4,2..10,5..8] Of String.
Ez a T egy háromdimenziós String tömb, elemeinek száma: 4*9*4=144, T[3,6,6] pedig egy eleme. A
programban egy újfajta azonosító típust
is találunk, ez
pedig a konstans: Const.
Típusát a kapott értéke azonosítja, példánkban ez egész.
Haszna az, hogy a programban sok helyen szerepelhet egy olyan, általában limit
érték, ahová mindig ki kellene azt írni, ami még nem is lenne nagy baj, de ha a
limit-et változtatni szeretnénk, akkor a listában végig mindenütt ki kellene
cserélni a helyesre, így viszont csak a program fejében, egyetlen helyen kell
cserét végrehajtani. A tömb deklarációjában is
használhatjuk. Így a program maximum Max
db szám
kezelésére alkalmas. Az aktuális darabszámot az N tartalmazza.
Nézzük meg, hogy jut ez az érték a programba: a ReadLn eljárással. Ez az első
olyan programunk, amely futás közben tőlünk adatot vár, mert a beadott érték
függvényében tud a továbbiakban dolgozni. A
program azt kérdezi meg, hogy hány számmal
szeretnénk dolgozni. Ezt a bekérést úgy teszi, hogy mindaddig újra
kérdez, ameddig 1..Max intervallumból nem adunk N-nek
értéket. Ezt a Repeat … Until ismétlő eljárással
lehet elegánsan megoldani. Az ismétlő eljárás
leállításáról egy intervallumba való tartozás vizsgálata gondoskodik, melynek
kulcsszava: In. Az első
For ciklus a
tömb elemeit kéri be, mindig kiírva, hogy hányadikat kérdezi. Az
utolsó tömbelem beírása után a program a végéig lefut. Az
Lk:= MaxInt; értékadással a lehető legnagyobb értéket veszi fel az Lk. A MaxInt
előre definiált konstans, értéke 32767. Azaz, ha helyesen írtunk be egészeket,
akkor a legkisebb ennél kisebb egyenlő. Ehhez hasonlítva a tömbelemeket és
cserélve, választja ki a legkisebbet. Az Ln:= -MaxInt-1; a legkisebb egész
számot jelenti, azaz a legnagyobb ennél nagyobb vagy egyenlő. A
következő programrészlet ezt keresi meg,
végighaladva a tömb elemein.
Program
SzamTomb;
Uses
NewDelay, Crt, CrtPlus;
Const
Max=20;
Var Sz: Array[1..Max] Of Integer;
I,J,Lk,Ln,N,S,Puf:
Integer;
Atl:Real;
Begin
TextMode(CO80);
Szinek(1,15);
Repeat
ClrScr;
Write('Hány
számmal dolgozol? ');
Szinek(1,14);
ReadLn(N);
Until
N In [1..Max];
For
I:= 1 To N Do
Begin
Write('Kérem a(z)
',I:3,'. számot: ');
ReadLn(Sz[I]);
End;
Lk:= MaxInt;
For
I:= 1 To N Do
If
Sz[I]<Lk Then
Lk:= Sz[I];
Ln:= -MaxInt-1;
For
I:= 1 To N Do
If
Sz[I]>Ln Then
Ln:= Sz[I];
Writeln('A
legkisebb szám: ',Lk);
Writeln('A
legnagyobb szám: ',Ln);
S:= 0;
For
I:= 1 To N Do S:= S+Sz[I];
Atl:= S/N;
Szinek(1,6);
Writeln('A számok
átlaga: ',Atl:10:2);
For
I:= 1 To N-1 Do For J:= I+1 To N Do
If
Sz[I]>Sz[J] Then
Begin
Puf:=
Sz[I];
Sz[I]:=
Sz[J];
Sz[J]:=
Puf;
End;
For I:= 1 To N Do
Write(Sz[I],’
’);
Tunj;
Varj;
End.
A számok átlagának
meghatározásához össze kell adni őket. Az összeget a program az s változóban
tárolja, ezért az összegzés előtt célszerű kinullázni. Az összegzést For ciklussal hajtjuk végre, a következő
tömbelem ismételt hozzáadásával. Az átlaghoz az összeget n-nel kell osztani. Az
átlag érték nem feltétlen egész szám, sőt mivel osztással keletkezett, a Pascal
biztosan Real-két kezeli. Real: valós számot takar, azaz itt tizedes törtet.
Ezért deklaráltuk az Atl-ot Real-nek.
Gyakran előfordul, hogy
elemeket sorba kell rendezni. Nagy elemszám esetén a rendezés időigényes
tevékenység. A rendezés végrehajtására többféle eljárást dolgoztak ki. Itt nem
a leggyorsabb, de talán a legérthetőbb eljárás rendez, melynek alapja a
közvetlen összehasonlítás. A külső ciklus az első elemtől az utolsó előttiig
megy, a belső a külső aktuális értékétől az utolsó elemig. Mire a kettős ciklus
lejár, bármely két elem össze lesz hasonlítva, és ha nem jó sorrendben voltak,
fel lesznek cserélve, azaz biztosan jó sorrendben fognak szerepelni a tömbben.
A módszert szokás közvetlen összehasonlításnak nevezni. A kiírást egy egyszerű For ciklus végzi.
Gyakorló programozási feladatok:
F.13: Készíts ülésrendet. Alul a tanári asztal,
felette 4 * 6 -os elrendezésben az osztály. A neveket a programlistában
tároljuk. Tudjon két tanuló helyet cserélni, melyet inputról irányíthatunk.
F.14: Készíts órarendet. Az oszlop és sorfejeket
(nap és óra) a program listában tárolja, de az órákat oszlop-folytonosan
lehessen beírni.
F.15: Készíts bizonyítványt. A tantárgyakat a
program tárolja, de a tantárgyi eredményeket inputról kéri. A magatartás és
szorgalom kivételével átlagot számít.
F.16: Készíts naplót, jegylezárással. A
tantárgyakat a program tárolja, de az 5 hónap jegyeit sorfolytonosan nekünk
kell beírni. Számítson tantárgyi átlagból félévi érdemjegyet, és a szokásos
módon tanulmányi átlagot.
F.17:
Írj programot, amely eldönti, hogy egy számtömb átlaga benne van-e a tömbben.
14.) Írjunk
programot, amely egy LOTTO szelvényt jelenít meg, válasszon véletlenül 5 számot
lottószámként, ezeket a számokat a képernyőn villogtassa, valamint külön is
írja ki a kiválasztott számokat.
A program a kihúzott
számokat a ki nem húzottaktól egy logikai tömb segítségével különbözteti meg.
Ennek neve Mutato. Ha egy szám, pl.: a 21-es ki lett húzva, akkor Mutato[21]
értéke True, ha nem, akkor False. A
lista első néhány ciklusa a
látvány megjelenítését végzi. A lottószelvény felrajzolásának utolsó
lépése a számok kiírása
1-től 90-ig.
Ez azt jelenti, hogy egy vektort tömbként (6*15-ös alakban) kell megjeleníteni.
Ez is tanulságos feladat, célszerű megjegyezni, mert gyakran előfordulhat ilyen
jellegű probléma. Ezt az első 90-ig futó ciklus hajtja végre. Nézzük a ciklus
magjában lévő GoToXY két paraméterét. Két új műveletet találunk benne: Mod és Div. A Mod eredménye a
két oldalán lévő szám egész osztásához tartozó maradék (előtte az osztandó,
mögötte az osztó), azaz: 14 Mod 3
értéke 1, mert 14-et 3-al osztva 1 maradékot kapunk. A Div eredménye a két oldalán lévő szám egész osztásának hányadosa,
azaz 14 Div 3 értéke 4, mert 14-ben
a 3 négy egész-szer van meg. E két művelet segítségével érhetjük el, hogy egy For ciklus 1-től 90-ig számol, közben
az X érték 6-szor kezd növekedéshez (0-15) és az Y csak minden 15 értékre
növekszik eggyel. Jegyezzük meg tehát, az X értéket a Mod, az Y értéket a Div
segítségével állíthatjuk elő. A pontos értékek beállítását az adja, hogy i=1-re
X=5-öt és Y=2-t kell kapni, valamint az X koordinátának 5-ösével, az Y-nak
2-esével kell változnia. (Első próbaként az X értékét (I Mod 15)*5, Y értékét (I Div
15)*2 képletekkel próbáljuk meg beállítani.)
Program
Lotto;
Uses
NewDelay, Crt, CrtPlus;
Var I,J,V: Byte;
Mutato: Array[1..90] Of Boolean;
begin
TextMode(CO80);
Szinek(Blue,Yellow);
ClrScr;
Racs(3,1,4,1,15,6);
For I:= 1 To
90 Do
Begin
GotoXY(((I-1) Mod 15)*5+5,((I-1) Div 15)*2+2);
Write(I:2);
End;
For
I:= 1 To 90 Do Mutato[I]:= False;
Randomize;
For
I:= 1 To 5 Do
Begin
Repeat
V:= Random(90)+1;
Until
Not Mutato[V];
Mutato[V]:= True;
End;
Szinek(Blue,Yellow+Blink);
For
I:= 1 To 90 Do If Mutato[I]
Then
Begin
GotoXY(((I-1) Mod 15)*5+5,((I-1) Div 15)*2+2);
Write(I:2);
End;
Szinek(Blue,Yellow);
WriteXY(1,20,’A
nyerőszámok: ’);
For I:= 1 To
90 Do If Mutato[I] Then
Write(I:4);
Tunj;
Varj;
End.
A következő 90-es For ciklus a logikai tömb értékét
False-ra állítja. A Randomize beindítja a véletlen-szám generátort. Az 5
lottószámot egy 5-ig menő For ciklus
állítja elő. A véletlen választás mindig a 90 számból történik, ezért
gondoskodni kell az újraválasztás kizárásáról. Ezt szolgálja a logikai tömb. A
lottószám generáló ciklusban a véletlen választás Repeat-el addig ismétlődik, ameddig ki nem húzott számot nem
választ a gép. A Repeat elhagyása
egy új számot jelent, melynek mutatóját a ciklus True-ra állítja. A
továbbiakban a számok villogtatása, illetve egyszerű kiíratása történik. Mivel
a mutatók nem keverednek, ezért indexük a kihúzott számmal megegyeznek, azaz
végül nem kell a nagyság szerinti kiíráskor a lottószámokat rendezni. Figyeljük
meg, hogy a programban a Mutato tömb elemeit, mint logikai értékeket
használjuk, és nem írtunk olyat a Repeat
leállításánál, hogy: Until Mutato[V]=False, helyette: Not
Mutato[V].
15.)
Irj programot, amely bekéri egy háromszög három oldalát, majd megvizsgálja,
valóban lehet-e a három távolság egy háromszög három oldala, ha igen, akkor
kiszámolja a háromszög kerületét és területét, valamint megállapitja, hogy a
háromszög hegyes-, derék- vagy tompaszögű.
Ha jól meggondoljuk,
ennek a programnak négy fő tevékenysége van: bekéri az adatokat, megvizsgálja,
kiszámítja a kerületet és területet, valamint minősíti a háromszöget. A
főprogram összesen ennek a négy tevékenységnek a hívásából áll, minden
tevékenységre eljárást irtunk. Igy célszerű eljárni azokban az esetekben, ha a
program sok, de külön-külön jól elhatárolt részfeladatokra bontható. Az Adatbe
eljárás egyetlen érdekessége: ha azt akarjuk, hogy a képernyőn idézőjel
jelenjék meg, meg kell kettőzni. A vizsgál rutinban
két új dolog van: az Or logikai
művelet, amely magyarul Vagy. Akkor
igaz, ha valamelyik tagja igaz a logikai kifejezésnek. Egyébként a
háromszög-egyenlőtlenség teljesülésének vizsgálatához használtuk a listában. A
másik a Halt eljárás, mely feltétel nélkül befejezi a programunk futtatását és
visszaadja a vezérlést, a programot hívó környezetnek. A KerTer eljárásban
talán a Heron képlet érdemel említést, mely húrnégyszögek területének
kiszámítására alkalmas az oldalak ismeretében. Ki kell számolni a húrnégyszög
fél-kerületét, minden oldalt ki kell belőle vonni, össze kell szorozni, a
szorzat négyzetgyöke adja a húrnégyszög területét. Mivel d=0 választással a
húrnégyszög háromszöggé fajul, a képlet háromszögekre is alkalmazható.
A Minoseg eljárásban
fontos új dolog található. Ez pedig a többszörös elágazás (szelekció), ahol az
ágak közül csak legfeljebb egy hajtódik végre. A minősítés Pithagorasz tétele
alapján történik. Mivel a háromszög oldalai bármilyen nagyság szerint
következhetnek, először meg kell állapítani, hogy melyik oldal a legnagyobb.
Első esetben az A, másodikban a B és harmadik esetben
a C oldal. Erre azért volt szükség, hogy Pithagorasz tételét fel tudjuk írni.
Mindhárom esetben létezhet mindhárom csoport, hogy a megfelelő alakban írjuk
fel a Pithagorasz tételt, esetenként kell szétválogatni a lehetőségeket, mivel
ez három eset, célszerű a már említett többszörös elágazást alkalmazni. Ennek
kulcsszavai: Case … Of … Else … End; A Case és Of közé kerül a diszkrét értékeket
felvevő szelektor. A Case
strukturált párja az End;. Közéjük a szelektor értékekkel kezdődő sorokat
bekezdésesen kell írni. A szelektor értékek után kettőspontot kell írni, melyet
egyetlen utasítás követhet. Ha több utasítást szeretnénk elhelyezni, akkor
összetett utasítás kell alkalmazni. Ha bizonyos értékekre mondjuk csak meg,
hogy mi a teendő, az összes többi esetén pedig valami egyéb a tevékenység,
akkor ezt a szelektor lista végén Else
mögé kell írni (programunkból ez most hiányzik). A csoportba sorolás kiírásánál
még egyszerűbb Case utasítást
látunk. Ha a szelektor olyan értéket vesz föl, amely nincs felsorolva a Case … End;-ben, akkor a szerkezet egyetlen
utasítása sem hajtódik végre (csak maga a Case).
Ezek után a lista:
Program
Haromsz;
Uses
NewDelay, Crt, CrtPlus;
Var A,B,C,T,K: Real;
Procedure
Adatbe;
Begin
TextMode(CO80);
ClrScr;
Write('Kérem a
háromszög ''a'' oldalát: '); ReadLn(A);
Write('Kérem a
háromszög ''b'' oldalát: '); ReadLn(B);
Write('Kérem a
háromszög ''c'' oldalát: '); ReadLn(C);
End;
Procedure
Vizsgal;
Begin
If
(A+B<=C) Or (A+C<=B) Or (B+C<=A)
Then
Begin
Writexy(1,6,'Az
adatok nem lehetnek egy háromszög oldalai!');
Tunj;
Varj;
Halt;
End;
End;
Procedure
KerTer;
Var S: Real;
Begin
K:= A+B+C;
S:= K/2;
T:= Sqrt(S*(S-A)*(S-B)*(S-C));
WriteXY(1,6,'A
háromszög kerülete: '); Write(K:8:4);
WriteXY(1,8,'A
háromszög területe: '); Write(T:8:4);
End;
Procedure
Minoseg;
Var Eset,Csop: Byte;
Begin
If (A>=B) And (A>=C) Then
Eset:= 1;
If
(B>=A) And
(B>=C) Then Eset:= 2;
If
(C>=A) And
(C>=B) Then Eset:= 3;
Case
Eset Of
1: If
A*A<B*B+C*C Then
Csop:=1 Else
If
A*A=B*B+C*C Then
Csop:=2 Else Csop:=3;
2: If
B*B<A*A+C*C Then
Csop:=1 Else
If
B*B=A*A+C*C Then
Csop:=2 Else Csop:=3;
3: If
C*C<A*A+B*B Then
Csop:=1 Else
If
C*C=A*A+B*B Then
Csop:=2 Else Csop:=3;
End;
Case
Csop Of
1: WriteXY(1,12,'A
háromszög hegyesszögű');
2: WriteXY(1,12,'A
háromszög derékszögű');
3: WriteXY(1,12,'A
háromszög tompaszögű');
End;
Tunj;
Varj;
End;
Begin
Adatbe;
Vizsgal;
KerTer;
Minoseg;
End.
16.)
Írjunk programot, amely bekéri egy másodfokú egyenlet három együtthatóját, majd
ez alapján megoldja az egyenletet.
Mivel a lista semmilyen új programozási elemet
nem tartalmaz, ezért elemzésétől eltekintünk. Íme a
program:
Program
Masodf;
Uses
NewDelay, Crt, CrtPlus;
Var A,B,C,D,X1,X2: Real;
Procedure
Adatbe;
Begin
TextMode(CO80);
ClrScr;
Write('Kérem a
másodfokú egyenlet ''a'' együtthatóját: '); ReadLn(A);
Write('Kérem a
másodfokú egyenlet ''b'' együtthatóját: '); Readln(B);
Write('Kérem a
másodfokú egyenlet ''c'' együtthatóját: '); Readln(C);
End;
Procedure
Vizsgal;
Begin
If
A=0 Then
Begin
WriteXY(1,10,’Az egyenlet nem
másodfokú’);
Tunj;
Varj;
Halt;
End;
D:= B*B-4*A*C;
If
D<0
Then
Begin
WriteXY(1,10,’Az egyenletnek
nincs valós gyöke’);
Tunj;
Varj;
Halt;
End;
End;
Procedure
Gyokok;
Begin
X1:=(-B-Sqrt(D))/2/A;
X2:=(-B+Sqrt(D))/2/A;
WriteXY(1,10,’Az egyenlet gyökei:’);
Write(X1:12:4,’ és ’,X2:12:4);
Tunj;
Varj;
End;
Begin
Adatbe;
Vizsgal;
Gyokok;
End.
17.)
Írjunk feleltető programot. A kérdések 10 és 20 közötti számok szorzatára
vonatkozzon. Számolja össze a helyes és a rossz válaszokat folyamatosan, a
végén adjon érdemjegyet a százalékos teljesités függvényében. A kérdések számát
kérdezze meg a program.
A program listájában
talán csak egyetlen hely van, amely magyarázatra szorul. A felelő válaszait a
képernyőnek mindig ugyanarra a helyére kell írni. Az újabb válaszokat a régi
válaszok a jelenlétükkel zavarnák. Eddigi ismereteink szerint a képernyőt le
kellene törölni, és a kérdésfeltevést mindig üres lappal kellene indítani,
ehelyett a listában egy újabb eljárást látunk, a ClrEOL-t, aminek az a szerepe,
hogy a képernyőn a kurzor helyétől a sor végéig letörli a képernyősor
tartalmát, így tüntetve el az előző inputok értékeit. A lista egyéb részlete
könnyen értelmezhető.
Program
Kerdezo;
Uses NewDelay,
Crt, CrtPlus;
Var A,B,I,N,Jv,Rv,V,Ej: Integer;
Sz: Real;
Begin
TextMode(CO80);
ClrScr;
Write('Hány szorzást
kérdezzek? ');
ReadLn(N);
WriteXY(30,8,'Mivel
egyenlő:');
Randomize;
For
I:= 1 To N Do
Begin
A:= Random(11)+10;
B:= Random(11)+10;
GoToXY(31,10);
Write(A:2,' * ',B:2,' = '); ClrEOL;
ReadLn(V);
If
V=A*B Then
Begin
Inc(Jv);
Sound(1000);
Delay(200);
NoSound;
End
Else
Begin
Inc(Rv);
Sound(100);
Delay(200);
NoSound;
End;
GoToXY(15,15);
Write('Jó válasz: ',Jv);
GoToXY(45,15);
Write('Rossz válasz: ',Rv);
End;
Sz:= Jv/N;
Ej:= 1;
If
Sz>1/3 Then Ej:=
2;
If
Sz>1/2 Then Ej:=
3;
If
Sz>2/3 Then Ej:=4;
If
Sz>17/20 Then Ej:=5;
GoToXY(1,20);
Write('Érdemjegyed: ',Ej);
Tunj;
Varj;
End.
18.)
Írj programot, amely meghatározza két szám legnagyobb közös osztóját és
legkisebb közös többszörösét.
A feladatot Euklideszi
algoritmussal oldjuk meg: Ha A és B a két szám, akkor
A-t oszd el maradékosan B-vel, majd A szerepét vegye át B, B szerepét pedig a
maradék, és az osztást és a cserét végezd mindaddig, amíg a maradék 0 nem lesz,
ekkor az utolsó osztó a legnagyobb közös osztó. Ezt végzi a program listájában
az ismétlő eljárás. Továbbá azt kell még tudni, hogy két szám legnagyobb közös
osztójának és legkisebb közös többszörösének a szorzata nem más, mint a két
szám szorzata. Így a legkisebb közös többszörös osztással meghatározható. A
listában szerepel még egy új deklaráció: a LongInt, vagy magyarul hosszú egész,
melynek értéke kb -2 milliárdtól + 2 milliárdig terjedhet. Íme
a lista:
Program Lnko; {Nyomkövetéssel
futtatni!}
Uses
NewDelay, Crt, CrtPlus;
Var A,B,M: LongInt;
S: LongInt;
Begin
TextMode(CO80);
ClrScr;
WriteXY(28,1,'A
legnagyobb közös osztó');
WriteXY(1,3,'Kérem
az első egész számot: ');
ReadLn(A);
WriteXY(1,4,'Kérem a
második egész számot: ');
ReadLn(B);
S:= A*B;
If
S=0 Then Halt;
Repeat
M:= A Mod
B;
A:= B;
B:= M;
Until
M=0;
WriteXY(1,6,'A
legnagyobb közös osztó: ');
Write(A);
WriteXY(1,8,'A
legkisebb közös többszörös: ');
Write(Round(S/A));
Tunj;
Varj;
End.
19.)
Írj programot, amely 0-99 intervallumban kiválogatja a prímszámokat, illetve
tetszőleges számról megállapítja, hogy prim-e.
A feladat első részét
Eratosztenész szitája segítségével oldjuk meg. Azaz: a 0-99 számból húzzuk ki a
0-t és 1-et, mert ezek nem prímszámok. Az első ki nem húzott szám a 2, ezért
húzzuk ki minden másodikat (kivéve magát a 2-t) egészen 99-ig, a következő ki
nem húzott szám a 3, ezért húzzuk ki minden 3. számot, a következő ki nem
húzott az 5 lesz, és így tovább. Az utolsó szám, amivel szitálni kell a 7 lesz.
Általánosan leírva a szitálást a szám négyzetgyökéig kell végezni. Ennek az az
oka, hogy minden összetett számnak létezik a négyzetgyökénél nem nagyobb
prímosztója. Ha tehát egy szám a négyzetgyökéig való szitálásig nem esett ki,
akkor az már nem is fog.
Ezek
után a program listája:
Program
Primszam;
Uses NewDelay,
Crt, CrtPlus;
Var I,J: Integer;
Szam: LongInt;
Pr: Array[0..99] Of
Boolean;
Procedure
Tabla;
Begin
TextMode(CO80);
Szinek(0,15);
ClrScr;
WriteXY(29,1,'Eratosztenész
szitája');
Racs(15,2,4,1,10,10);
For I:= 0 To
99 Do
Begin
GoToXY((I Mod 10)*5+17,(I Div 10)*2+3);
Write(I:2);
End;
End;
Procedure
Szitalas;
Var P:
Integer;
Procedure
Kikap(K: Byte);
Begin
GoToXY((K Mod 10)*5+17,(K Div 10)*2+3);
Write(K:2);
End;
Begin
For
I:= 0 To 99 Do Pr[I]:= True;
Szinek(0,7);
Pr[0]:= False;
Kikap(0);
Delay(100);
Pr[1]:= False;
Kikap(1);
Delay(100);
P:=0;
While
P<10 Do
Begin
Repeat
Inc(P);
Until
Pr[P];
If
P>10 Then
Exit;
I:= P;
While
I<100-P Do
Begin
Inc(I,P);
Pr[I]:= False;
Kikap(I);
Delay(100);
End;
End;
End;
Procedure
Prime;
Var P:
Integer;
Igen: Boolean;
Begin
WriteXY(1,24,'Mely
számról akarod tudni, hogy prim-e? ');
ReadLn(Szam);
I:= 1;
Igen:= True;
Repeat
Inc(I);
If
(Szam Mod I)=0 Then Igen:= False;
Until
(I>Sqrt(Szam)) Or
Not Igen;
If
Szam=1 Then Igen:= False;
If
Szam=2 Then Igen:= True;
If
Igen Then WriteXY(55,24,'Igen')
Else
Begin
WriteXY(55,24,'Nem,');
If
Szam<>1 Then
Write(' Osztja: ',I);
End;
Tunj;
Varj;
End;
Begin
Tabla;
Szitalas;
Prime;
End.
A programnak 3 fő
funkciója van: a tábla felrajzolása, a szitálás valamint egy tetszőleges szám
vizsgálata. A tábla felrajzolását végző Tabla eljárás már sok ismert dolgot
tartalmaz, ezért nem elemezzük. A szitálás eljárásban van egy újdonság, az
eljárásfejben újabb eljárást deklaráltunk, a kikap (K: Byte); eljárást, vagyis
egy eljárásnak lehetnek további saját eljárásai. Ez az eljárás a 15-ös kódú
fehér színről 7-re állítja az írás színét, azaz halványabban írja ki a K
számot. A szitálás alapját a 0-99 indexű logikai tömb adja. A bekapcsolt
állapotnak felel meg a True érték, amely azt mondja, hogy a szám prímszám.
Először minden érték True, csak az eljárás során alakul ki a helyes érték. A folyamatot
Delay(100) lassítja, így nyomon követhető a szitálás.
Először a nem automatizálható 0-t és 1-t kapcsolja ki. Majd a While, elől-tesztelő ciklus végzi a
szitálást, mindaddig, amíg P<10. Először megkeresi a
következő prímszámot. Ha ez véletlenül1 túllépett 10-en, akkor Exit eljárással kilép a Szitalas
eljárásból (az Exit a Halt-hoz hasonló, csak itt az
eljárásból lép ki a gép, a Halt-nál
pedig a programból). Aztán a megtalált prímszámmal, ismét egy While ciklus segítségével, kikapcsolja
a nem prímszámokat. A lépegetést az Inc eljárás eddig nem ismertetett
formájával oldja meg: a második paraméter a növelés mértékét adja, tehát ennek
hiányában egyesével számolna, itt viszont az I-t mindig P-vel növeli. Az
eljárás végén erősen írva maradnak a prímszámok, a nem prímszámok halványan
láthatók a táblázatban.
A Prime eljárás
egyszerűen végignézi (de legfeljebb csak a szám négyzetgyökéig), hogy létezik-e
olyan szám, mellyel a számot osztva maradékul 0-t kapunk (Mod). Az igen True értéke a szám prímszám mivoltát jelzi. Ezért a
leállító Not igen értéke. Az eljárás
a szám legkisebb prímosztóját is meghatározza, hiszen az a nem 1 de legkisebb szám, ami osztja, biztosan prím
(természetesen összetett számnál).
20.)
Elemezzük a szöveges változókra érvényes műveleteket, függvényeket és
eljárásokat.
A következőkben olyan
programokat szeretnénk írni, amelyek szöveges változókat is kezelnek. A
szöveges változókkal végezhető műveleteket és eljárásokat mutatja be a Szoveg nevű program:
Program
Szoveg;
Uses
NewDelay, Crt, CrtPlus;
Var A,B,C,D: String;
I,N: Byte;
Begin
TextMode(CO80);
ClrScr;
A:= 'alma';
B:= 'fa';
C:= a+b;
WriteLn(C);
n:= Length(C);
WriteLn(N);
D:= Copy(C,2,3);
WriteLn(D);
For
I:= 1 To N Do WriteLn(C[I]);
WriteLn(Ord(C[0]));
Insert('vad',C,1);
WriteLn(C);
WriteLn(Pos('dal',C));
Delete(C,4,4);
WriteLn(c);
Tunj;
Varj;
End.
Szöveges változók között
csak egyetlen művelet létezik, az összeadás, mely a két szöveg egymás után
helyezését jelenti. A Length függvény a szöveges változó hosszát adja vissza. A
Copy függvény első paramétere egy szöveg, melyből a második paramétertől
kezdődően, a harmadik paraméter hosszban másolatot készít. A String úgy tárolódik, hogy a nulladik
karakterének kódja a String hosszát
jelenti. Az Ord függvény a karakter sorszámát adja vissza (a Chr függvény
fordítottja), azaz a String hosszát. Az Insert eljárás első paraméterét, a
második paraméterként megadott szövegbe, a harmadik paraméterben megadott
helytől kezdve beszúrja. A Pos függvény az első paraméterként megadott szöveg
helyét keresi a második paraméterként megadott szövegben. Visszaadott értéke a
keresett szöveg első karakterének helye, ha ez 0, akkor a keresett szöveget nem
találta. A Delete eljárás, az első paraméterként megadott szövegből, a második
paraméterben megadott helytől kezdődően, a harmadik paraméterben megadott számú
karaktert töröl.
21.)
Írjunk programot, amely bekér egy szöveget, és fordítva írja ki.
Program
Fordito;
Uses
NewDelay, Crt, CrtPlus;
Var Szov: String;
I,N: Byte;
Begin
TextMode(CO80);
ClrScr;
Write('Kérem a
szöveget: ');
ReadLn(Szov);
N:= Length(szov);
For
I:= N DownTo 1 Do Write(Szov[I]);
Tunj;
Varj;
End.
A programban egyetlen
igazi újdonság az, hogy a For
ciklust csökkenő értékekkel használja. Elemzésétől eltekintünk.
22.)
Írjunk programot, amely egy beolvasott szöveg karaktereit a következőképpen
alakítja át: a Space és a kódban előtte lévő karaktereket Space-szé alakítja, a
számokat nem változtatja meg, a nagybetűből kisbetűt, a kisbetűből nagybetűt
készít, egyéb karaktereket ponttal helyettesít.
A program több újdoságot
is tartalmaz. Az első a Function,
azaz függvény deklaráció. A függvény formailag nagyon hasonlít az eljárásra,
csak itt van visszaadott érték, amelynek típusát a függvény neve után
kettősponttal elválasztva le kell megadni. A programbeli Valt függvényt Char
típusú paraméterrel kell meghívni, és Char típusú a visszaadatott érték is,
azaz karakterből másik karaktert készít. A visszaadott értéket a végrehajtó
részében kell megadni úgy, hogy a függvény nevét egy értékadás bal oldalán
szerepeltetjük. Jelen esetben a Valt értékét egy Case szerkezettel a legcélszerűbb megadni. A Ch változó értékétől
függően, négyféleképpen kap értéket a függvény. A külön le nem írt karakterek
esetére az Else ág adja az
értékeket. A betűváltások is tartalmaznak újdonságokat. A szelektor értékeket
tartományként is leírhatjuk. Az Ord függvényt már ismerjük, a kisbetű a
nagybetűs párjánál 32-vel nagyobb kódú, így állítottuk elő. Az UpCase függvény
a kisbetűből nagybetűt készít.
Program
Valto;
Uses
NewDelay, Crt, CrtPlus;
Var ISzov,OSzov: String;
I,N: Byte;
Function Valt(Ch: Char): Char;
Begin
Case
Ch Of
#0..#32: Valt:=' ';
’0’..’9’: Valt:= Ch;
'A'..'Z': Valt:=
Chr(Ord(Ch)+32);
'a'..'z': Valt:= UpCase(Ch);
Else
Valt:= '.';
End;
End;
Begin
TextMode(CO80);
ClrScr;
Write('Kérem a
szöveget: ');
ReadLn(ISzov);
N:= Length(ISzov);
OSzov[0]:= Chr(N);
For
I:= 1 To N Do OSzov[I]:= Valt(ISzov[I]);
WriteXY(19,3,OSzov);
Tunj;
Varj;
End.
Az OSzov (Out Szov)
létrehozása is érdekes. A hossza megadásával kezdjük, ami az ISzov (In Szov)
hosszával megegyezik. Majd a karaktereit a vált függvény segítségével egyenkét
hozzuk létre. Rövidebben a hosszbeállítás (N nélkül) Így
nézne ki: OSzov[0]:= ISzov[0];. Ha csak egyetlen szöveges változóval akarnánk
megoldani, akkor a Do utáni
értékadás: OSzov[0]:= Valt(Iszov[0]); lehetne.
Természetesen, ekkor ISzov-et kellene kiíratni.
23.)
Írjunk programot, amely bekér egy szöveget, majd feladványkét kiírja
magánhangzók nélkül, és addig kérdezi a felhasználót, amíg el nem találja a
helyes választ.
Program
Szoki;
Uses
NewDelay, Crt, CrtPlus;
Var FSzov,VSzov: String;
I,N: Integer;
Begin
TextMode(CO80);
ClrScr;
Write('Kérem a
szöveget: ');
ReadLn(FSzov);
ClrScr;
N:= Length(FSzov);
For
I:= 1 To N Do
If
FSzov[I] In
['a','á','e','é','i','í','o','ó','ö','ő','u','ú','ü','ű',
'A','Á','E','É','I','Í','O','Ó','Ö','Ő','U','Ú','Ü','Ű'] Then
Write('.') Else Write(FSzov[i]);
Window(1,3,80,25);
Repeat
Write('Mi a
tipped: ');
ReadLn(VSzov);
Until
FSzov=VSzov;
WriteLn('Eltaláltad');
Tunj;
Varj;
End.
A lista két új dolgot
tartalmaz. Az egyik a halmaz megadásának egyik módját, amikor a halmaz elemeit
szögletes zárójelbe téve felsoroljuk, mivel most karakterekről van szó ezért a
karaktereket zárójelbe kell tenni. A másik a halmazba való tartozás relációja,
melyet az In lefoglalt szóval
fogalmazhatunk meg. Mint minden relációnak ennek az értéke
is csak igaz vagy hamis lehet, ezért állhat az If feltételében.
24.) Írjunk programot,
amely bekér egy szöveget, majd szavanként fordított sorrendben írja ki.
Program
Szavalo; {Nyomkövetéssel
futtatni}
Uses
NewDelay, Crt, Crtplus;
Const
Max=10;
var
Szov: String;
N,I,J: Byte;
Sz: Array[1..Max] Of String;
Begin
TextMode(CO80);
ClrScr;
Write('Kérem a
szöveget: ');
ReadLn(Szov);
N:= Length(Szov);
J:= 1;
For
I:= 1 To N Do
If
Szov[I]<>' ' Then
Sz[J]:=
Sz[J]+Szov[I]
Else
Inc(J);
For
I:= J DownTo 1 Do WriteLn(Sz[I]);
Tunj;
Varj;
End.
A program a szavak
számát a J változóban tárolja, melynek maximális értéke Max lehet. A szöveg
szavakra bontáskor az Sz String-tömbbe
kerülnek. A szöveg beírásakor nem szabad a szavakat egynél több Space-szel
elválasztani, mert akkor üres szavakat is létrehoz. A fordított For ciklus oldja meg a fordított
sorrendű kiírást.
Írj
programot, amely az órarendedet jeleníti meg a képernyőn. A tanítási órák
számát FOR ciklussal jelenítsd meg, használd a CrtPlus Racs()
eljárását a vonalak megrajzolásához. A látvány az itt látható futtatási képhez
minél jobban hasonlítson: