4it101»Adv Hadanka

Adv Hadanka

Hádanka (dotaz)

Na dotazech a hádankách je nejsložitější vymyslet vhodné uspořádání kódu tak, aby hra v budoucnosti mohla být spuštěna v textové i v grafické verzi. V textové verzi se čte ze standardního vstupu, v grafické verzi je nejjednodušší použít třídu JOptionPane. Tj. jsou dvě řešení v závislosti na tom, zda budeme hru spouštět v textovém či v grafickém režimu. Tyto implementace (třídy) musí mít stejné rozhraní, aby volba implementace neovlivňovala zbývající třídy. Je potřeba vytvořit ještě jednu implementaci pro potřeby testování - aby při spuštění testů nemusel programátor vždy zadávat nějaký vstupní text.

Příklad použití bude jednoduchý (a trochu umělý) - při vstupu do místnosti kancelář musí hráč zadat vstupní kód. Ve své adventuře musíte umístit dotaz do vhodné metody. Většinou to bude některý z příkazů, ve výjimečném případě by dotaz mohl být přímo ve třídě Hra.

1. Rozhraní ZadavaniDotazu

Připravíme si rozhraní ZadavaniDotazu, které bude mít tři implementace - jednu pro textové rozhraní, jednu pro grafické rozhraní a jednu pro testy.

Rozhraní ZadavaniDotazu bude předepisovat jednu metodu pro získání odpovědi na otázku (kód je bez komentářů):

    public interface ZadavaniDotazu {

        String odpovez(String otazka);
    }

2. Třída TextoveDotazy

K tomuto rozhraní vytvoříme třídu pro dotazy v textovém rozhraní. Vlastní metoda pro čtení z konzole se velmi podobá odpovídající metodě ve třídě TextoveRozhrani. Bylo by možné vytvořit jednu třídu, kterou by využívali obě třídy (něco podobného, jako bylo v projektu Trojuhelniky).

(:source lang=java:) import java.io.*; /******************************************************************************* * Třída TextovyDotaz ... * * @author Luboš Pavlíček * @version 0.01.000, 26. listopadu 2007 */ public class TextoveDotazy implements ZadavaniDotazu { //== Datové atributy (statické i instancí)====================================== //############################################################################## //== Konstruktory a tovární metody ============================================= /*************************************************************************** * */ public TextoveDotazy() { } //== Nesoukromé metody (instancí i třídy) =============================================== public String odpovez(String otazka) { return prectiString(otazka); } //== Soukromé metody (instancí i třídy) =========================================== /** * Metoda přečte řetězec z konzole. Parametrem je prompt, který se nejdříve vypíše * na konzoli. * *@return Vrací přečtený řetězec */ private String prectiString(String prompt) { String vstupniRadek=""; System.out.print(prompt); // vypíše se prompt BufferedReader vstup = new BufferedReader(new InputStreamReader(System.in)); try { vstupniRadek = vstup.readLine(); } catch (java.io.IOException exc) { System.out.println("Vyskytla se chyba během čtení z konzole " + exc.getMessage()); } return vstupniRadek; } }

3. Úpravy tříd TextoveRozhrani a Hra

Třídě Hra se předá v konstruktoru odkaz na správnou implementaci rozhraní ZadavaniDotazu. Dále se předá třídě PrikazJdi, neboť v této třídě (tj. před vstupem do místnosti) je potřeba se zeptat na kód. Konstruktor třídy Hra vypadá takto:

    public Hra(ZadavaniDotazu zadDotazu) {
        herniPlan = new HerniPlan();
        platnePrikazy = new SeznamPrikazu();
        platnePrikazy.vlozPrikaz(new PrikazNapoveda(platnePrikazy));
        platnePrikazy.vlozPrikaz(new PrikazJdi(herniPlan, zadDotazu));
        platnePrikazy.vlozPrikaz(new PrikazKonec(this));
    }

Ve třídě TextoveRozhrani se v konstruktoru vytváří instance třídy TextoveDotazy:

    public TextoveRozhrani() {
        hra = new Hra(new TextoveDotazy());
    }

4. Úpravy třídy Mistnost

Místnost s dotazem se vytváří podobně jako zamčená místnost. Vytvoříme dva datové atributy:

    private String otazka;
    private String odpoved;

K nim vytvoříme následující metody:

    public void nastavOtazku(String otazka, String odpoved) {
        this.otazka = otazka;
        this.odpoved = odpoved;
    }

    public String getOtazka() {
        return otazka;
    }

    public String getOdpoved() {
        return odpoved;
    }

    public boolean sOtazkou() {
        return otazka != null;
    }

V herním plánu nastavíme kancelář takto:

        kancelar.nastavOtazku("Zadej kód ke dveřím:", "42");

5. Úprava metody proved v PrikazJdi

Jako poslední nám zbývá úprava metody proved ve třídě PrikazJdi:

        if (sousedniMistnost == null) {
            return "Tam se odsud jit neda!";
        }
        else {
            String vypis="";
            if (sousedniMistnost.sOtazkou()) {
                String odpoved = zadDotazu.odpovez(sousedniMistnost.getOtazka());
                if (odpoved.trim().toLowerCase().equals(sousedniMistnost.getOdpoved())) {
                    vypis="Podařilo se ti zadat správný kód a opatrně vstupuješ do místnosti\n";
                    plan.setAktualniMistnost(sousedniMistnost);
                    vypis += sousedniMistnost.dlouhyPopis();
                }
                else {
                    vypis = "Zpoza dveří se ozvalo podezřelé cvakání. Poté se hlasitě rozezněl zvonek\n";
                    vypis += "a ty jsi rychle zabočil za roh. Do místnosti jsi se nedostal.";
                }
            }
            else {
                plan.setAktualniMistnost(sousedniMistnost);
                vypis = sousedniMistnost.dlouhyPopis();
            }
            return vypis;
        }

6. Třída GuiDotazy

Třída pro čtení odpovědí v grafickém rozhraní, zde je spíše pro zajímavost. Jsou zde i dva obrázky z grafické varianty.

V kurzu 4it115 se dozvíte o grafickém rozhraní více informací, takže si budete moci vzhled upravit dle svých představ.

(:source lang=java:) import javax.swing.JOptionPane; /******************************************************************************* * Třída GuiDotazy ... * * @author Luboš Pavlíček * @version 0.01.000, 26. listopadu 2007 */ public class GuiDotazy implements ZadavaniDotazu { //== Datové atributy (statické i instancí)====================================== //############################################################################## //== Konstruktory a tovární metody ============================================= /*************************************************************************** * */ public GuiDotazy() { } //== Nesoukromé metody (instancí i třídy) =============================================== public String odpovez(String otazka) { return JOptionPane.showInputDialog(null,otazka); } //== Soukromé metody (instancí i třídy) =========================================== }

7. Třída DotazyDoTestu

(:source lang=java:) import java.util.*; /******************************************************************************* * Třída DotazyDoTestu ... * * @author Luboš Pavlíček * @version 0.01.000, 15. listopadu 2008 */ public class DotazyDoTestu implements ZadavaniDotazu { //== Datové atributy (statické i instancí)====================================== private List<String> odpovedi = new ArrayList<String>(); //############################################################################## //== Konstruktory a tovární metody ============================================= /*************************************************************************** * */ public DotazyDoTestu() { } //== Nesoukromé metody (instancí i třídy) =============================================== public String odpovez(String otazka) { if (odpovedi.isEmpty()) { return ""; } else { return odpovedi.remove(0); } } public void pridejOdpoved(String odpoved) { odpovedi.add(odpoved); } }

V testovací třídě se při vytváření instance třídy Hra musí vytvořit instance třídy DotazyDoTestu. Před dotazem na uživatele se musí do instance třídy DotazyDoTestu vložit příslušná odpověď (lze testovat samozřejmě i chybné odpovědi).

	DotazyDoTestu dotazy = new DotazyDoTestu();
	Hra hra1 = new Hra(dotazy);
	 // .....
	// testuji chybnou odpověď
	dotazy.pridejOdpoved("41");
	hra1.zpracujPrikaz("jdi kancelar");
	assertEquals("chodba", hra1.getHerniPlan().getAktualniMistnost().getNazev());
	// testuji správnou odpověď 
	dotazy.pridejOdpoved("42");
	hra1.zpracujPrikaz("jdi kancelar");
	assertEquals("kancelar", hra1.getHerniPlan().getAktualniMistnost().getNazev());