Sokoban levels
Ciele
- Modulárne programovanie.
- Dynamické údajové typy.
- Správa pamäte.
- Práca so súbormi.
Úvod
Hru samotnú robí zaujímavou to, že po úspešnom vyriešení jedného problému dostane hráč na riešenie problém ďalší a hlavne ťažší. Hra je teda tvorená súborom niekoľkých levelov (alebo úrovní), ktoré musí hráč zdolať. Ak ich všetky úspešne zdolá, hru samotnú dohrá.
Na tomto cvičení vytvoríte vo svojej hre takýto mechanizmus, pomocou ktorého bude hráč môcť prechádzať z levelu do levelu. Samostatné levely budú uložené v externom súbore a pri spustení hry sa zavedú do pamäte, v ktorej budú reprezentované pomocou spojkového zoznamu.
Postup
Krok č. 1
Úloha 1.1:
Úloha 1.2:
Úloha 1.3:
Úloha 1.4:
Krok č. 2
Úloha 2.1:
- spustiť hru - hra sa spustí od začiatku (level 0)
- ukončiť hru - hra sa korektne ukončí (uzatvorením všetkých otvorených súborov, uvoľnením celej obsadenej pamäte a pod; nestačí len zavolať funkciu exit())
Okrem uvedených položiek môžete do menu pridať napr. aj položku o autorovi.
Úloha 2.2:
Krok č. 3
Úloha 3.1:
Úloha 3.2:
- name - názov levelu
- description - (veselý) opis levelu, ktorý sa zobrazí pri jeho spúšťaní
- password - heslo pre vstup do daného levelu
- map - mapa samotného levelu v Sokoban formáte
- next_level - referencia na ďalší level
Úloha 3.3:
Funkcia nebude mať žiadny parameter a taktiež nebude vracať žiadnu hodnotu. Funkciu volajte v hre len raz a to pri jej spustení.
Pre prvé tri levely môžete použiť nasledujúce mapy:
char* level1 = "---####|---#--#|---#--#|---#$.#|####--#|#-----#|#@$.--#|#######"; char* level2 = "-#####|##---#|#--.-#|#-$.$###|##$.$--#|-#-.@--#|-#######"; char* level3 = "--#####|###-@-#|#--$.$##|#--$*$-#|###.*.-#|--#-.--#|--#--###|--####";Heslá, názvy a opisy jednotlivých levelov nech sú nasledovné:
- level 1 - názov: at the beginning...; opis: ...programmer created the world and the robot...; heslo: sokoban
- level 2 - názov: the next level; opis: you should have no expectations!; heslo: budokan
- level 3 - názov: level 3; opis: this is level 3; heslo: saboteur
Úloha 3.4:
Úloha 3.5:
Úloha 3.6:
Krok č. 4
Úloha 4.1:
názov levelu;opis levelu;heslo;mapaSúbor s vyššie uvedenými levelmi môže teda vyzerať nasledovne:
at the beginning...;...programmer created the world and the robot...;sokoban;---####|---#--#|---#--#|---#$.#|####--#|#-----#|#@$.--#|####### the next level;you should have no expectations!;budokan;-#####|##---#|#--.-#|#-$.$###|##$.$--#|-#-.@--#|-####### level 3;this is level 3;saboteur;--#####|###-@-#|#--$.$##|#--$*$-#|###.*.-#|--#-.--#|--#--###|--####
Úloha 4.2:
Poznámka:
Keďže budete potrebovať načítavať jednotlivé hodnoty dynamicky a nikdy si nebudete istí dĺžkou načítavaného reťazca, môžete využiť nasledovnú vlastnosť funkcií scanf() a fscanf() (zdroj: manuálová stránja funkcie scanf()):
The GNU C library supports a nonstandard extension that causes the library to dynamically allocate a string of sufficient size for input strings for the %s and %a[range] conversion specifiers. To make use of this feature, specify a as a length modifier (thus %as or %a[range]). The caller must free(3) the returned string, as in the following example:
char *p; int n; errno = 0; n = scanf("%a[a-z]", &p); if (n == 1) { printf("read: %s\n", p); free(p); } else if (errno != 0) { perror("scanf"); } else { fprintf(stderr, "No matching characters\n"); }
As shown in the above example, it is only necessary to call free(3) if the scanf() call successfully read a string.
The a modifier is not available if the program is compiled with gcc -std=c99 or gcc -D_ISOC99_SOURCE (unless _GNU_SOURCE is also specified), in which case the a is interpreted as a specifier for floating-point numbers (see above).
Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier. The m modifier has the following advantages:
- It may also be applied to %c conversion specifiers (e.g., %3mc).
- It avoids ambiguity with respect to the %a floating-point conversion specifier (and is unaffected by gcc -std=c99 etc.)
- It is specified in the upcoming revision of the POSIX.1 standard.
Úloha 4.3:
Doplňujúce úlohy
- Podľa zadania sú levely uložené v čistej textovej forme, čo umožňuje jednoducho sa dostať ku ľubovoľnému heslu a teda umožňuje hráčovi hrať ľubovoľný level. Vytvorte preto funkcie char* code(char*) a char* decode(char*), z ktorých jedna bude vedieť zakódovať reťazec a druhá ho dekódovať. Na kódovanie môžete použiť ľubovoľný mechanizmus, resp. šifru (napr. môžete použiť jednoduchú substitučnú šifru známu pod názvom Cézarofa šifra).
- Pridajte do hry kláves 'r', pomocou ktorého budete vedieť reštartovať práve rozohratý level.
- Pridajte do menu položku Redefine keys (Zmena kláves), pomocou ktorej si bude môcť hráč nastaviť vlastné klávesy pre ovládanie hry.
- Rozšírte proces zmeny kláves o možnosť zapnúť, resp. vypnúť tzv. God mode, kedy bude hráč môcť miesto hesla zadávať priamo čísla levelov, ktoré chce hrať. Samozrejme môžete do hry vložiť aj úplne iný easter egg, ktorý nemusí byť založený na zmene kláves, ale na postupnosti stlačených kláves počas hry.
-
Rozšírte štruktúrovaný typ Level o položku solution. Položka solution je reprezentovaná ako postupnosť hráčových ťahov na vyriešenie danej úrovne (formát). Hráč sa pritom môže pohybovať len v smere hore (u), dole (d), vľavo (l) a vpravo (r). Príklad takéhoto reťazca je nasledujúci:
DDrdrruLruLLDllU
Smery s veľkými písmenami znamenajú, že Sokoban bude v danom smere pred sebou tlačiť bedňu. Riešenie však musí byť platné nehľadiac na veľkosť písmen.Túto položku môžete aktualizovať zakaždým, keď hráč level prejde a jeho riešenie je jednoduchšie (to znamená kratšie) ako to, ktoré je v aktuálnom leveli uvedené.
Obsah tejto položky môžete využiť ako demo pri hlavnom menu (buď ako samostatnú položku alebo sa demo spustí automaticky po uplynutí časového limitu). Počas behu dema sa samozrejme nezobrazí kompletné riešenie hry, ale len istý počet krokov z riešenia (max. polovica).
-
Vytvorte funkciu validate_level(), ktorá:
- sa pokúsi nájsť riešenie uvedeného levelu,
- bude mať jeden parameter, ktorý bude obsahovať referenciu na premennú typu Level,
- vráti hodnotu True, ak je daný level naozaj vyriešiteľný, alebo False, ak vyriešiteľný nie je.
- Vytvorte jednoduchý editor levelov, ktorý môže byť súčasťou samotnej hry alebo môže byť implementovaný ako samostatný program.
- Vytvorte samostatnú (úvodnú obrazovku) pred spustením levelu. V tejto obrazovke nech sa zobrazí názov levelu, jeho opis a heslo do tohto levelu. Pre výpis týchto textov môžete vymyslieť vhodný efekt (napr. tzv. terminálový výpis, kedy sa každý znak vypíše s miernym spozdením).
Ďalšie zdroje
- Rudolf Pecinovský: Základy algoritmizace
- Pavel Herout: Učebnice jazyka C (1. díl)
- Formát reťazca pre riešenie úrovne Sokobana
- Tutoriál k Makefile
Poznámka: