Thursday, 16 April 2020

Xorka - logikai játék a xor elvén. Enterprise változat elkészítése

Spectrum számítógépre készítette el Alexander Zavgorodniy 2015-ben basic nyelven ezt a játékot, a Spectrum Computing oldalán is megtalálható.



A játék egy 10x10-es felületen játszódik, ahol a célunk a színes (a képen zöld) mezők eltüntetése. A pályán egy kurzort (X alakú) mozgathatunk. A tűzgomb megnyomására a gép egy vízszintes és egy függőleges vonalat rajzol úgy, hogy azok a kurzor pozíciójában metszik egymást. Pontosabban a vonalak kirajzolása közben a pályán oda, ahol nincs pályaelem, pályaelemet tesz, ahol pedig már van valami, onnan letörli. Tehát a xor elvén az adott vízszintes és függőleges pozícióban átállítja a 0 jelű elemeket 1 jelűvé, az 1 jelűeket pedig 0 jelűvé. A játék indításakor kirajzol véletlenszerűen vízszintes és függőleges vonalakat, ebből kell nekünk visszaállítani az üres pályát.
Az ep128.hu oldalon ennél tömörebben és érthetőbben van leírva a játék lényege: Feladatunk a megadott méretű játéktér megtisztítása a sötét mezőktől. Ennek egyetlen lehetséges módja, hogy a mozgatható célkereszt oszlopában és sorában a tűz gomb megnyomásával ellentétes színűre változtatjuk az összes mezőt (vagyis amelyik mező eddig sötét volt, most világos lesz, a világos mezőkből pedig sötét).
Az Enterprise változat a Xorgame 2 nevet kapta. Az első rész, a Xorgame Endi és IstvánV közös, gépi kódú programja, melyet Endi PC-re írt meg, majd István ebből elkészítette az Enterprise változatot. A Xorgame kapcsán botlottunk bele a Xorka nevű játékba, így merült fel, hogy ezt is meg lehetne írni Enterprise-ra.



A program működése:


A program az elején létrehoz egy kétdimenziós tömböt, ebben fogja tárolni az egész pályát. Játék közben ennek a tömbnek a megfelelő elemét fogja majd vizsgálni a program, illetve ennek a tömbnek az elemeit fogja módosítani xor végrehajtásakor (tűzgomb játék közben). Ahogy a képernyőre kiír ill. onnan letöröl pályaelemeket, azzal párhuzamosan a tömb tartalmát is módosítja. A tömb helyett kiolvashatná éppen a képernyőről is, hogy az adott pozícióban 0 vagy 1 van (vagyis van-e pályaelem vagy nincs), azonban a játék attribútum képernyőn fut, hogy több szín lehessen, grafikus képernyőről pedig nem tudunk karaktereket kiolvasni. (Elvileg megoldható lenne az is, hogy ne a karaktereket, hanem a színüket olvassa ki a program, ezzel még nem próbálkoztam.)

A játéknak két fő része van:


1. a kurzor (X jel) mozgatása a pályán
2. a xor művelet végrehajtása a tűzgombra (ez a XOR nevű eljárás a DEF XOR blokkban, amit a CALL XOR paranccsal hívunk meg mindig, amikor a játékos megnyomja a tűzgombot).

A pálya kirajzolása nem külön rész, hanem a program véletlenszerűen kiválaszt kurzorpozíciókat, és ott végrehajtja a xor műveletet (meghívja a XOR eljárást a CALL XOR-ral), ezzel rak a pályára vonalakat.

1. Az X mozgatása a pályán: figyeli a program, hogy a botkormány el van-e döntve valamelyik irányba. Ha igen, akkor megvizsgálja, hogy az adott irányba lehet-e tovább lépni, nem vagyunk-e már a pálya szélénél. Ha még lehet lépni, akkor a kurzort letörli a helyéről, az adott koordinátájához hozzáad egyet, majd kirajzolja az új helyén. Közben arra is figyelni kell, hogy milyen mezőre lép a kurzor, oda, ahol van pályaelem, vagy oda, ahol üres a pálya. Bárhova rakjuk ki a kurzort, az letörli, ami éppen ott van, tehát a pályaelem helyére és az üres helyre kirakva is teljesen ugyanúgy fog kinézni. Így nem lehetne eldönteni, a kurzor helyén pályaelem van-e vagy sem. Ezért az X kirakása előtt előbb meg kell vizsgálni, hogy az adott pozícióban mi van, és ha pályaelem, akkor inverz X-et kell kirakni. Az inverz X karakter definiálásáról a program elején gondoskodunk.
Akár meg lehetett volna csinálni, hogy az X villogjon, így látszana az is, ami alatta van. De azt is meg lehetett volna csinálni, hogy villogjon is, és a pályaelemhez is hasonuljon.
Fontos még, hogy a kurzor mozgatásakor, amikor a régi pozíciójából letörli és az új pozíciójába kirakja, akkor a régi pozíciójából ne csak letörölje, hanem az ott lévő pályaelemet rakja ki maga után. Ezt a tömbből kell kiolvasni. Ha nem tömböt használnánk, hanem a képernyőről olvasná ki, milyen karakter van adott pozícióban, akkor adott pozícióba lépés előtt egy stringben el kellene tárolnia az adott pozícióban lévő karaktert, utána kéne rálépnie, majd onnan ellépéskor kiírni a kurzor régi helyére, amit kiolvasott onnan odalépéskor.

2. A XOR művelet végrehajtása nem bonyolult. Két FOR ciklus kell hozzá. Az első a pálya felső szélétől a az alsó széléig, a második a pálya jobb szélétől a bal széléig rajzol vagy pályaelemet minden pozícióba, vagy vonalat, attól függően, hogy mi van ott: megnézi a program minden pozícióban a tömb adott elemét, és ha az 1 (pályaelem), akkor átírja 0-ra. Ha pedig 0, akkor átírja 1-re.
Amikor a keret kirajzolása után a pályát felépíti a gép véletlenszerű pozíciókba xorolással, akkor az 1-esek lerakásakor megnöveli 1-gyel a SUM változó értékét, mely kezdetben 0. Ha pedig egy 1-et átváltoztat 0-ra, akkor csökkenti 1-gyel a SUM értékét. Így tehát azt tárolja a SUM változóban, hogy jelenleg hány 1 (pályaelem) van a képernyőn. Erre azért van szükség, hogy játék során, ha sikerül az összes pályaelemet lepucolnunk, akkor a játszma befejeződhessen, és kiírja a gép a képernyőre a gratulációját. Figyelni kell arra is, hogy a XOR műveleteket végző eljárást a pálya kirajzolásakor, vagy pedig játék közben hívjuk-e meg. Erre azért van szükség, mert a pálya kirajzolásakor is előállhat az az állapot, hogy eltűnik, minden 1-es a pályáról, mert egymás után kétszer hajt végre a kirajzoló ugyanabban a pozícióban xor műveletet, így egyszer kirajzolja az 1-eseket, utána pedig letörli, és ebben a helyzetben a játék gratulációját fejezi ki, és vége a játéknak. Először bele is estem ebbe a hibába, hogy erre nem figyeltem, utólag tettem bele annak figyelését, hogy játékból vagy pedig a pálya kirajzolásából hívjuk-e meg a XOR eljárást, az előbbi esetben a GAME változó értéke 1, utóbbi esetben 0.
XOR művelet legelején a kurzor pozíciójában lévő karaktert átváltoztatja az ellentétére. Az eredeti program írója úgy oldotta meg, hogy ahol a két vonal metszi egymást, ott az maradjon a pályaelem, ami előtte volt, így én is ezt az elvet követtem. Elméletileg az se lenne baj, ha a vonalak metszéspontjában ellenkezőjére váltana a karakter, mert az egyik vonal felülírja azt, a másik vonal pedig ismét felülírja.


No comments:

Post a Comment