======= 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 {{ :courses:b6b36pcc:ukoly:tic_tac_toe_1.zip |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_raw'' – ''set_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é? {{ :courses:b6b36pcc:ukoly:tic_tac_toe_2.zip |Ř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 3x3 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í [[https://en.wikipedia.org/wiki/ANSI_escape_code|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ě. {{:courses:b6b36pcc:ukoly:semestralka:barvy.png?400|}} Barvy lze definovat i specificky pro pozadí a popředí výpisu (''n'' je číslo v rozmezí **0 až 256** a udává [[https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit|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 3x3): * ''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 7x5, 4 značky v řadě): * ''112212132333344521445553463526154325'' - vyhrává křížek * ''112212231314243515173351162644534352544527'' - remíza Příklad testů pro hru Piškvorky (rozměry 7x5, 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, [[https://gitlab.fel.cvut.cz/nagyoing/mujprojekt|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 Visibility((Settings -> General -> Permissions)) 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) * 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 [[https://cs.wikipedia.org/wiki/Othello_(deskov%C3%A1_hra)|Ottello]] (reversi) * Hra [[https://cs.wikipedia.org/wiki/Hled%C3%A1n%C3%AD_min|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 [[https://cs.wikipedia.org/wiki/Tetris|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 [[https://deti.mensa.cz/index.php?pg=tipy--hry--online&prid=134 | logické hry pro děti]] na stránce společnosti MENSA