Labor, 14. hét: labirintus játék
Czirkos Zoltán, Nagy Gergely, Pohl László · 2021.12.04.
Labirintus játék írása: a félév anyagát áttekintő gyakorlófeladat.
A mai órán egy összetett programot készítünk el. Ez egy labirintus játék, amelyben egy játékos egy előre adott labirintusban mozoghat, kincseket gyűjtve. A labirintust, amely egy kétdimenziós pálya, kétdimenziós karaktertömbben, vagyis sztringek tömbjében tároljuk.
A programot több forrásfájl, valamint fejlécfájl alkalmazásával valósítsd meg!
Felkészülés a laborra:
- A többmodulos programokról szóló előadás átismétlése.
Megoldás
A program teljes forráskódja letölthető innen: labirintus.c. (Csupasz 2D karaktertömbbel, nem sztringekkel.)
A labirintus egy fallal körülvett 10×10-es tábla. A labirintust körülvevő falon egy kijárat található. A labirintusban több kincset rejtettek el. A játékos feladata, hogy összeszedje a kincseket és eljusson a kijáratig.
A labirintust a következő formában kell megjeleníteni:
###### ### #$ # # #### ### # # # # #### ### # # #$# # ##$# # # #@ ### # # # $# # ##########
Itt a falakat a # jelzi, a járható részeket szóköz, az elrejtett kincseket a $ karakter, a játékost pedig a @. Ha a játékos felvette, a kincs helyére is szóköz kerül.
Ebben a feladatban az alább látható részfeladatok mind egymásra épülnek, vagyis sorban kell megcsinálnod őket. Minden függvény megírásakor írj egy rövid programrészt a főprogramba, amely meghívja a függvényt – így lépésenként ellenőrizni tudod azt, hogy helyesen működik-e.
Tömb
Hozz létre egy tömböt a labirintus tárolására! A tömb tárolja a labirintus egyes sorait sztringként. Mivel a sztringek maguk is tömbök, ezért ennek a tömbnek két dimenziósnak kell lennie (tömbök tömbje). Figyelj arra, hogy a sztringként tárolt sorok miatt eggyel nagyobbra kell választanod a tömböt vízszintesen (vagyis szélesebbre), hogy a sztringet lezáró nulla is beleférjen.
Inicializáld a tömböt úgy, hogy a fent látható labirintust tartalmazza. Ehhez azt át tudod másolni a forráskódba.
Emlékeztető
Kétdimenziós tömböt így lehet létrehozni:
tipus nev[sorok_szama][oszlopok_szama];
Vajon melyik itt a sztringek mérete? Melyiket kell eggyel nagyobbra választani?
Kirajzolás
Írj függvényt, amely paraméterként veszi a labirintust tároló tömböt és kirajzolja a labirintust a képernyőre!
A játékos koordinátái
Hozz létre alkalmas struktúratípust a labirintusbeli koordináták tárolására! Írj függvényt, amely paraméterként veszi át a labrintust tároló tömböt, és visszaadja a játékos koordinátáit. Ennek visszatérési típusa a korábban definiált struktúra legyen. A függvény keresse meg a játékost a tömbben, és állítsa be a struktúrában a megfelelő pozíciót!
Emlékeztető
Struktúratípust a következőképpen lehet létrehozni:
typedef struct opcionalis_struct_nev {
tipus mezo_1;
tipus mezo_2;
…
} struktura_nev;
Kincsek száma
Írj függvényt, amely paraméterként veszi át a labirintust tároló tömböt, és visszaadja a benne található kincsek számát!
Emlékeztető
Kétdimenziós tömb függvény-paramétert így kell definiálni:
visszateresi_tipus fuggveny_nev(tipus nev[][oszlopok_szama], unsigned sorok_szama);
Vagyis ebben a speciális esetben a szögletes zárójelek közt meg kell adni
méretinformációt, de csak az oszlopok számát. Enélkül ugyanis nem tudna működni az összetett
indexelő operátor, hiszen a C-ben a kétdimenziós tömbök sorfolytonosan vannak tárolva, tehát a
fordítónak tudnia kell, hogy milyen hosszú egy sor, vagyis hány elemet kell ugrani indexeléskor.
A képlet, ami egy elem pozícióját megadja ugyanis a következő:
elem_index = sor_index * oszlopok_szama + oszlop_index
Irányok
Definiálj felsorolt típust, amely alkalmas az irányok (le, fel, jobbra, balra) tárolására!
Emlékeztető
Felsorolt típust így kell definiálni (ez is typedef
-elhető):
enum nev { azonosito_1, azonosito_2, … };
Mehet-e arra?
Írj függvényt, amely paraméterként veszi át a labirintust tároló tömböt valamint egy irányt! A visszatérési típusa logikai legyen, ami akkor vegye fel az IGAZ értéket, ha a játékos elmozdulhat az adott irányba. A játékos akkor nem mehet egy irányba, ha ott fal van.
Gondolj arra, hogy ennek a függvénynek nem kell paraméterként átvennie a játékos helyzetét, hanem azt az egyik előbb megírt függvénnyel meg tudja határozni.
Léptetés
Írj függvényt, amely paraméterként átveszi a labirintust tároló tömböt és egy adott irányt, és lépteti a játékost, ha ez lehetséges! Azt, hogy az adott irányba léphet-e a játékos, az előző pontban elkészített függvény segítségével ellenőrizd! A léptetés azt jelenti, hogy a játékos aktuális pozíciójára egy szóköz, az új pozíciójára pedig egy @ kerül.
A függvény a visszatérési értékében jelezze, ha
- az irány rossz, mert ott fal van!
- a játékos a kijáratba lépett!
- a játékos kincset talált!
- a játékos üres mezőre lépett!
Tippek
A visszatéréshez érdemes létrehozni egy újabb felsorolt típust, amely a fenti négy
lehetőséget jelöli egy-egy konstanssal. Így a főprogramban a lépés eredményének ellenőrzése egy
nagyon jól olvasható switch
segítségével valósítható meg.
Azt, hogy a játékos kijáratra lépett, úgy döntheti el, hogy a lépést ellenőrző függvény visszatérése IGAZ és a játékos új koordinátáinak valamelyike 0 vagy 9.
Főprogram
A main függvényben írj egy ciklust, amely bekéri a felhasználótól a mozgás irányát és ennek megfelelően lépteti a játékost!
- Tartsd számon, hogy a játékos hány kincset talált!
- Ha a játékos a kijáraton kiment, akkor nézd meg, hogy megtalált-e minden kincset (a 4. részfeladatban megírt függvény segítségével)! Ha már nincs több kincs a labirintusban, akkor nyert, ha van, akkor veszített. Írd ki a végeredményt a képernyőre!
- Ha nem mehet a kívánt irányba a játékos, akkor ezt írd ki a képernyőre!
- Rajzold ki lépésről-lépésre az új táblát!
Iránysorozat
Írd át a labirintus programot úgy, hogy a játékos egyszerre több irányt is megadhasson! Például ha az irányokat a következő betűk segítségével kell bevinni: 'w', 'a', 's', 'd', akkor a "wddsa" jelentse azt, hogy a játékos egy öt lépésből álló sorozatot kíván megtenni: fel-jobbra-jobbra-le-balra.
Útkereső
Írj függvényt, ami paraméterként kapja a labirintust tartalmazó tömböt és a játékos indulási koordinátáit, a visszatérési értéke pedig egy logikai érték legyen, ami akkor IGAZ, ha a játékos ki tud jutni a labirintusból, tehát ha létezik út a két pont között!
Tipp
Keresd meg a labirintusban a játékost, és „színezd ki” a mellette lévő üres helyeket. Ezután fésüld végig újra a labirintust, és a „kiszínezett” cellák melletti üres helyeket is színezd. Folytasd ezt addig, amíg van színezés. Ha nincs már több, végeztél – ha a kijárat ki lett színezve, akkor a játékos ki tud jutni.
Fájlból olvasva
Egészítsd ki úgy a programot, hogy a labirintust fájlból olvassa be!