3. týždeň

Úloha 2 - Implementujeme jadro hry

Ciele

  1. Vytvoriť triedy podľa návrhu jadra hry z minulého cvičenia.
  2. Implementovať základnú logiku hry na základe návrhov z minulého cvičenia.
  3. Vytvoriť unit testy pre otestovanie inicializácie herného poľa a metód hernej logiky.

Postup

Krok 1

Úloha 1.1

Vytvorte triedy jadra hry v jazyku Java podľa návrhu, ktorý ste vypracovali za uplynulý týždeň.

Dbajte na vhodné pomenovania tried, metód, premenných a pod., udržiavajte patričné odsadenia kódu a čleňte zdrojový kód s ohľadom na princípy OOP.

Poznámka

Pri implementácii podľa možností využite návrhové vzory, s ktorými ste sa už mohli oboznámiť na predmete Objektovo-orientované programovanie.

Váš zdrojový kód organizujte do vhodných balíkov. Pre hru Minesweeper by bol hlavným balíkom napr. sk.tuke.kpi.kp.minesweeper umiestnený v adresári src.

Pre reprezentáciu herného poľa vašej hry zvážte vhodnú údajovú štruktúru. V prípade hry Minesweeper sa ako vhodné javí dvojrozmerné pole typu Tile[][]. Pre rôzne typy dlaždíc odporúčame využiť viaceré triedy, ktoré dedia od všeobecnej triedy Tile.

Poznámka

Pred začatím implementácie návrh môžete prekonzultovať s cvičiacim.

Úloha 1.2

Vygenerujte konvenčné metódy get, set a konštruktory podľa pravidiel zapuzdrenia v objektovo-orientovanom programovaní.

V prostredí IntelliJ Idea je možné get a set metódy generovať na základe už deklarovaných atribútov triedy, výberom možnosti Refactor -> Encapsulate Fields ... z ponuky kontextového alebo hlavného menu.

Obr. 1

Následne je možné v zobrazenom dialógovom okne vybrať metódy, ktoré sa majú vygenerovať.

Obr. 2

Konštruktory je v prostredí IntelliJ Idea možné vygenerovať výberom možnosti Generate... z ponuky kontextového menu alebo Code -> Generate... z hlavného menu a následne výberom možnosti Constructor z menu zobrazeného nad zdrojovým kódom.

Obr. 3

Následne je možné v zobrazenom dialógovom okne vybrať atribúty, ktoré majú byť konštruktorom inicializované.

Obr. 4

Generovanie kódu je možné kedykoľvek vyvolať aj klávesovou skratkou Alt+Insert.

Krok 2

Implementujte základy hernej logiky na základe vášho návrhu z uplynulého týždňa. Pre pripomenutie, ide konkrétne o:

  • Spôsob generovania herného poľa, jeho inicializáciu.
  • Spôsob overovania stavov hry po každom ťahu hráča - či je hra vyhratá, prehratá alebo prebieha.
  • Spôsob prechodu medzi stavmi dlaždíc, ťahy hráča.

Ak sa vám to podarí, na konci tohto modulu by ste mali mať pripravené všetko potrebné na vytvorenie konzolového rozhrania hry.

Krok 3

Keďže ešte nemáme hotové používateľské rozhranie hry, je na mieste otestovať vytvorené metódy.

Úloha 3.1

Vytvorte jednotkové (unit) testy pomocou JUnit 5 pre otestovanie:

  • správnej inicializácie herného poľa a stavov hry či dlaždíc,
  • správneho generovania herného poľa,
  • správnej funkcionality metód hernej logiky - overovanie stavov hry a dlaždíc, prechody medzi stavmi a pod.

Poznámka: Pre písanie testov budete potrebovať knižnicu JUnit, so stiahnutím ktorej vám môže pomôcť priamo vyvojové prostredie IntelliJ IDEA. Pri označení testovacej metódy s anotáciou @Test bude táto pravdepodobne vyznačená červenou farbou. Presunutím kurzora na anotáciu a použitím klávesovej skratky Alt+Enter vyvoláte kontextové menu s akciami, medzi ktorými bude aj možnosť pridať potrebnú knižnicu JUnit do projektu.

Poznámka: Zdrojový kód pre testy umiestňujte do osobitného adresára, napríklad test (vedľa adresára src) a taktiež ho patrične čleňte do balíkov (napríklad pre hru Minesweeper by bol hlavný balík sk.tuke.kpi.kp.minesweeper).

Triedy s kódom testov pomenovávajte podľa tried, ktoré testujete, s tým, že za názov pripojte ešte slovo Test. Napríklad, trieda s testami overujúcimi funkcionalitu triedy herného poľa Field by sa nazývala FieldTest.

Jednotlivé testovacie metódy, ktoré budú overovať základné jednotky funkcionality, označte anotáciou @Test.

Testovacia trieda FieldTest s ukážkou niekoľkých testov by mohla vyzerať napríklad nasledovne:

package sk.tuke.kpi.kp.minesweeper;

import org.junit.jupiter.api.Test;
import sk.tuke.gamestudio.game.mines.myname.core.Field;
import sk.tuke.gamestudio.game.mines.myname.core.Mine;

import java.util.Random;

import static org.junit.jupiter.api.Assertions.*;

public class FieldTest {

    private Random randomGenerator = new Random();
    private Field field;
    private int rowCount;
    private int columnCount;
    private int minesCount;

    public FieldTest() {
        rowCount = randomGenerator.nextInt(10) + 5;
        columnCount = rowCount;
        minesCount = Math.max(1, randomGenerator.nextInt(rowCount * columnCount));
        field = new Field(rowCount, columnCount, minesCount);
    }

    @Test
    public void checkMinesCount() {
        int minesCounter = 0;
        for (int row = 0; row < rowCount; row++) {
            for (int column = 0; column < columnCount; column++) {
                if (field.getTile(row, column) instanceof Mine) {
                    minesCounter++;
                }
            }
        }

        assertEquals(minesCount, minesCounter, "Field was initialized incorrectly - " +
                "a different amount of mines was counted in the field than amount given in the constructor.");
    }

    @Test
    public void fieldWithTooManyMines() {
        Field fieldWithTooManyMines = null;
        int higherMineCount = rowCount * columnCount + randomGenerator.nextInt(10) + 1;
        try {
            fieldWithTooManyMines = new Field(rowCount, columnCount, higherMineCount);
        } catch (Exception e) {
            // field with more mines than tiles should not be created - it may fail on exception
        }
        assertTrue((fieldWithTooManyMines == null) || (fieldWithTooManyMines.getMineCount() <= (rowCount * columnCount)));
    }
    
    // ... dalsie testy
}

Úloha 3.2

Overte vašu implementáciu jadra hry spustením jednotkových testov, ktoré ste implementovali v predošlej úlohe.

V prípade, že niektorý z testov neprejde, vyhľadajte chyby vo vašej implementácii a opravte ich. Postup opakujte, kým nebude váš zdrojový kód fungovať správne.

Krok 4

Úloha 4.1

Nahrajte vašu implementáciu do vášho repozitára na GitLab-e. Projekt môžete ďalej priebežne aktualizovať. Pred ďalším cvičením sa uistite, že máte v repozitári vaše aktuálne súbory. Zároveň si pripravte otázky, ktoré by ste na cvičení chceli vyriešiť.

Zdroje

  1. JUnit 5
  2. Príklad JUnit testu pre Minesweeper.
  3. Dokumentácia pre tvorbu JUnit testov v prostredí IntelliJ IDEA.
  4. JUnit 5 používateľská príručka