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).

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.

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

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());