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.
1.
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.
2.
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.