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