Semestrálka: Tvorba hry

Obecné požadavky

V rámci semestrální práce je možné vytvořit hru podle vlastního návrhu. Hra bude realizována v textovém režimu, zde je možné využit terminály POSIX.

Hru lze implementovat jako jednovláknovou aplikaci nebo lze využít více vláken. Práce s více vlákny může být hodnocena bonusovými body (až +10 bodů).

Hra může využívat tři definovaná vlákna (viz ukázka) – vstupní, výstupní (vykreslovací) a výpočetní (časovací). Vlákna musí spolu komunikovat – překreslení hry se děje jenom pokud je to nutné, hru lze kdykoliv korektně ukončit apod. Tento návrh má výhodu v celkové struktuře vytvářené aplikace. Takto navržená aplikace je přehledná a snadno se vytváří.

Vzorové řešení hry Piškvorky splňuje pouze minimální požadavky na semestrální práci a může být hodnoceno až 20 body. Na řešení lze ocenit možnost nastavení hry přes parametry programu a přípravu testů (viz níže). Vyšší bodové hodnocení lze dosáhnout také použitím složitějších algoritmů pro výpočet (například automatickou kontrolou řešení, vyhodnocení odpovědí hráče apod.) nebo lepší grafickou podobou aplikace (například využití více barev, větší hrací pole, další možnosti nastavení hry).

Upozornění: Pro správnou funkčnost vytvářené konzolové aplikace využíváme přepnutí do raw módu a ANSI escape sequences. I když tyto možnosti nabízí i terminály systému Windows, práce zde je mnohem komplikovanější a často nepředvídatelná.

Pokud se rozhodnete vytvářet tento typ semestrální práce, doporučujeme vývoj pod některým z UN*X systémů. Pod Windows lze efektivně využít i Windows Subsystem for Linux.

Postup při tvorbě hry

Definice vláken

Tento typ semestrální práce využívá vlákna pro tvorbu konzolové aplikace. Semestrální práce je automaticky vícevláknová a demonstruje základní principy návrhu a tvorby uživatelského rozhraní. Ukážeme, jak lze implementovat jednoduchou hru piškvorky.

Začneme s programem tic_tac_toe_1.zip. Program využívá tři vlákna:

  • vlákno inputThread slouží k načítání vstupů z klávesnice. Zde je očekáváno zmáčknutí klávesy Q pro ukončení programu,
  • vlákno computeThread slouží k výpočtům. Zde pouze zvyšujeme hodnotu proměnné counter v pravidelném intervalu daném makrem PERIOD_COUNTER,
  • vlákno outputThread vypisuje hodnotu proměnné counter.

Při zadávání vstupů je obvykle vyžadováno jejich potvrzení klávesou ENTER. Pro zjednodušené načítání vstupů přepínáme terminál do tzv. raw módu, který potvrzování klávesou ENTER nevyžaduje. K tomu slouží funkce set_rawset_raw(true) nastaví raw mód, set_raw(false) ho naopak zruší.

Předpokládáme, že program tic_tac_toe_1.zip připočítá jedničku do proměnné counter s periodou PERIOD_COUNTER. Změnu vypisuje na terminál. Po zmáčknutí Q se program ukončí. Program vyzkoušejte a upravte podle zadání. Na následující otázky byste měli odpovědět kladně:

  • Spustí se všechna vlákna?
  • Ukončí se všechna vlákna po stisku klávesy Q korektně?
  • Chová se program stejně při opětovném spuštění?
  • Je počet změn proměnné counter stejný jako počet výpisů hodnoty proměnné?

Řešení

  • Deklarace zámku mutexu ve vlákně inputThread zablokuje vykonávání programu, který takto čeká na zmáčknutí klávesy Q.
  • Synchronizaci computeThread a outputThread provedeme pomocí podmínkové proměnné std::condition_variable.

Vzhled hry

Tři definovaná vlákna využijeme ke konstrukci hry. Začneme návrhem vzhledu výpisů. Hrací pole pro Piškvorky bude vypadat následovně:

-------------
|   |   |   |
-------------
|   |   |   |     
-------------
|   |   |   |
-------------
Kolecko:
-------------
| X | O |   |
-------------
| O | X |   |
-------------
| O |   |   |
-------------
Krizek:
-------------
|   |   |   |
-------------
|   |   |   |
-------------
|   |   |   |
-------------
Kolecko: 1 3
-----------------------------
| O |   |   | X | O |   |   |
-----------------------------
| X | O | O | X |   |   |   |
-----------------------------
|   | O | X |   |   |   |   |
-----------------------------
|   | X |   |   |   |   |   |
-----------------------------
|   |   |   |   |   |   |   |
-----------------------------
Kolecko:

Rozměry hracího pole a požadovaný počet značek v řadě pro výhru jsou parametry třídy tic_tac_toe. Parametry lze zadat prostřednictvím příkazové řádky. Parsování příkazové řádky se provádí ve třídě ArgParser, která na základě argumentů programu nastaví parametry pro třídu tic_tac_toe:

  • -w (-width) – počet sloupců hracího pole,
  • -h (-height) – počet řádků hracího pole,
  • -c (-count) – požadovaný počet značek pro výhru.

Pokud nejsou parametry programu zadány, jsou využity předdefinované hodnoty – hrací pole velikosti 3×3 políčka.

Příklad spuštění programu:

Piskvorky -w 7 -c 4 -h 5
Piskvorky -width 7 -c 4 -height 5
Piskvorky -w 7 -h 5

Definujeme typ jednoho políčka hrací plochy p_field – typ nothing, wheel, cross. Informace o jednotlivých políčkách hracího pole jsou uloženy v std::vector typu p_field velikosti hracího pole (šířka x výška).

Pod vykresleným hracím polem bude vypsáno, kdo je na řadě a případně souřadnice aktuálně zadaného bodu ve formátu řádek sloupec. Výpis pod hrací plochou využijeme i k dalším informacím pro hráče a definujeme ho jako speciální řetězec výpisu (proměnná text).

K překreslování hracího pole (probuzení vlákna outputThread) bude docházet vždy, když dojde ke změnám parametrů hry, tj. když bude do hracího pole vložen nový křížek nebo kolečko. K tomu dochází po zadání souřadnic hráčem hry.

Definujeme třídu Window, která podle daného návrhu vykreslí hrací pole. Předpokládáme využití ANSI escape sequences. Potřebné konstanty definujeme pomocí maker:

#define ANSI_CLEAR  "\x1B[2J\x1B[H" 
#define ANSI_COLOR_RESET "\x1B[m"
#define COLOR_RED   "\x1B[91m"
#define COLOR_GREEN "\x1B[92m"
#define COLOR_WIN   "\x1B[48;5;52m\x1B[38;5;208m"
#define COLOR_DRAW  "\x1B[48;5;17m\x1B[38;5;75m"

Konstanta ANSI_CLEAR vymaže terminál a nastaví počátek vykreslování na levý horní roh terminálu. Konstanta ANSI_COLOR_RESET zruší nastavení barev – další vykreslování probíhá podle nastavení terminálu (obvykle bílá barva na černém pozadí).

Další barvy lze definovat pomocí následující tabulky nebo lze využít další možnosti ANSI escape podle dokumentace. Například “\x1B[4m” způsobí výpis podtrženým písmem, “\x1B[9m” způsobí výpis přeškrtnutým písmem, “\x1B[91m” výpis červeně.

Barvy lze definovat i specificky pro pozadí a popředí výpisu (n je číslo v rozmezí 0 až 256 a udává barvu podle tabulky):

  • “\x1B[38:5:⟨n⟩m” - výběr barvy popředí,
  • “\x1B[48:5:⟨n⟩m” - výběr barvy pozadí.

Ovládání hry

Proces ovládání hry je řízen vláknem inputThread. První zadaná číslice určuje řádek, druhá sloupec vložení značky. Novou značku vkládáme na dané místo pouze v případě, že na tomto místě jiná značka není. Při vložení značky je nutné zkontrolovat stav hry – výhru některého z hráčů nebo remízu. V případě ukončení hry je nutné vypsat odpovídající informace.

Doporučujeme k ovládání hry vybrat klávesy reprezentující písmena anglické abecedy nebo číslice. Speciální znaky (šipky, funkční klávesy apod.) jsou na zpracování náročnější.

V případě složitějšího ovládání hry doporučujeme pro ovládání definovat speciální třídu.

Časování

Některé hry mohou vyžadovat pravidelnou změnu hracího pole, například pravidelný pohyb hráče bez ohledu na vstup z klávesnice (housenka se pohybuje po ploše), pohyb pozadí (hra Mario) nebo pravidelný výpis skóre.

Pro demonstraci využití časování ve hře vypisujeme „časové“ skóre hráčů – jak dlouho jednotliví hráči své tahy promýšleli. Dojde-li k remíze, lze výhru započítat hráči s menším skóre, s kratším časem stráveným nad jednotlivými tahy.

Testy a testování

Semestrální práce by měla být dobře otestována a ověřena. Můžete využít automatické testy (tzv. Continuous Integration), jak jste se s nimi setkávali v průběhu semestru. Nebo můžete dodat testy ve formě různých posloupností znaků pro ovládání hry. Příklad testů pro hru Piškvorky (rozměry 3×3):

  • q
  • 1q
  • 12q
  • 112233q
  • 1121223133 - vyhrává kolečko (hlavní diagonála)
  • 122113112231 - vyhrává křížek (sloupec vlevo)
  • 1221223233111331 - vyhrává křížek (sloupec vlevo)
  • 112112223123 - vyhrává křížek (prostřední řádek)
  • 311122213113 - vyhrává kolečko (vedlejší diagonála), kolečko – chybné zadání
  • 11121321222331 - vyhrává kolečko (vedlejší diagonála)
  • 111222333121321323 - remíza
  • 1121311233222332 - vyhrává křížek (prostřední sloupec)
  • 13s2223z1133 - vyhrává kolečko (sloupec vpravo)
  • 1121122213 - vyhrává kolečko (horní řádek)
  • 3122211133132232 - vyhrává kolečko (dolní řádek), kolečko – chybné zadání
  • 1122213113123223 - remíza

Příklad testů pro hru Piškvorky (rozměry 7×5, 4 značky v řadě):

  • 112212132333344521445553463526154325 - vyhrává křížek
  • 112212231314243515173351162644534352544527 - remíza

Příklad testů pro hru Piškvorky (rozměry 7×5, 5 značek v řadě):

  • 11221223212431252613415133353246574217522753544337474445151634 - remíza
  • 1122122321243125261341513335324657421752275354433747441516453455 - vyhrává křížek
  • 1122122313142435151733511626445343525445273442 - vyhrává kolečko

Ukázka

Připravili jsme pro vás i ukázku semestrálky - hra Piškvorky. Najdete ji na fakultní instanci GitLabu, zde.

Odpovídající email by pak vypadal zhruba takto:

Dobrý den,

odevzdávám semestrálku "Odhad Pí za pomoci Monte Carlo simulace".
Kód je na https://gitlab.fel.cvut.cz/nagyoing/mujprojekt, hash
acbf81b733323cd87250269f38415c0c7f0f5c99.

...

Pokud forknete ukázkový repozitář a nechcete, aby byl váš kód viditelný světu, nastavte Visibility1) na Internal.

Checklist pro odevzdání

Před odevzdáním semestrální práce na téma tvorba hry si zde můžete zkontrolovat, zda jste na něco nezapomněli.

* Kód
  * Obsahuje váš kód CMakeLists.txt přes který se vaše semestrálka dá postavit?
  * Je implementována nápověda (argument programu --help)?
* Použití vláken pro vyšší bodové hodnocení
  * Používá váš kód alespoň tři vlákna, která správně komunikují?
  * Nepoužívá váš kód rozšíření jazyka? (Například OpenMP, VLA)
  * Nepoužívá váš kód nepřenosné knihovny (Například POSIX, Win32, filesystem, windows.h, conio.h)
* Testování
  * Obsahuje vaše řešení popis způsobů a postupů testování? Obsahuje příklady testů, které jste prováděli?
  * Zkontrolovali jste svoje řešení s využitím vhodného analytického nástroje (valgrind, dr. Memory apod.)?
* Zpráva
  * Obsahuje vaše zpráva hash commitu (nebo tag), vůči kterému byla napsaná?
  * Obsahuje vaše zpráva popis zadání? 
  * Obsahuje vaše zpráva popis ovládání hry?
  * Obsahuje vaše zpráva popis možností a způsobů nastavení hry?
  * Máte proměnné a funkce programu řádně zdokumentovány? Jsou všude doplněny komentáře?

Před odevzdáním práce si pozorně projděte Checklist. Odevzdáním práce se dílo považuje za hotové a jeho delší opravy za účelem většího bodového zisku či z jiných důvodů jsou možné pouze po svolení cvičícího.

Šuplíkové zadání

Věříme, že vymyslet vlastní návrh aplikace, kterou lze ovládat pomocí vstupů z klávesnice, by neměl být problém. Přesto uvádíme seznam her, které lze pro zadání využít. Lze vymyslet různé varianty uvedených her.

  • Hra Ottello (reversi)
  • Hra Hledání min známá z MS Windows
  • Generování bludiště a procházení bludištěm
  • Hry typu “Mario” - pohyb hráče v labyrintu
  • Hra Tetris
  • Hra Housenka - pohybuje se po ploše a sbírá zelí
  • Hra ping-pong - chytání, odrážení různých předmětů
  • Inspirací mohou být logické hry pro děti na stránce společnosti MENSA
1)
Settings → General → Permissions
courses/b6b36pcc/ukoly/sem_tvorhru.txt · Last modified: 2024/09/18 17:25 by nagyoing