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.