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:

Megoldás

A program teljes forráskódja letölthető innen: labirintus.c. (Csupasz 2D karaktertömbbel, nem sztringekkel.)

1. Labirintus játék

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!

2. További feladatok

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!