Doposud jsme s Prologem komunikovali spíše jednostranně. My jsme se ptali, on odpovídal. Ale program, který nemluví a nereaguje na uživatele, je jako socha – krásný, ale nudný. V této kapitole se naučíme, jak Prologu vdechnout život. Ukážeme si, jak číst vstup od uživatele, jak zapisovat výsledky na obrazovku a jak pracovat se soubory. A co je nejdůležitější, všechny tyto znalosti spojíme dohromady a vytvoříme si vlastní textovou dobrodružnou hru!
Prolog má jednoduché predikáty pro komunikaci s vnějším světem.
write(Term): Vypíše zadaný term (atom, číslo, proměnnou) na obrazovku.nl: Vypíše nový řádek (New Line). Je to jako stisknout Enter.read(Promenna): Přečte term od uživatele. POZOR: Uživatel musí zadat term a ukončit ho tečkou . a Enterem!get_char(Char): Přečte jeden znak z klávesnice.get_code(Code): Přečte ASCII kód jednoho znaku.Příklad: Jednoduchý chatbot "Psycholog"
start_chatbot :-
write('Ahoj, jak se cítíš? '), nl,
read(Pocit), % Uživatel musí napsat např. 'smutny.'
reakce(smutny) :- write('To mě mrzí. Dej si čokoládu.'), nl.
reakce(stastny) :- write('To je skvělé! Jen tak dál.'), nl.
reakce(_) :- write('Zajímavé... pověz mi víc.'), nl.
Dynamická databáze (Kapitola 15) je skvělá, ale její obsah zmizí, když program vypnete. Co když chceme uložit stav hry nebo data pro příští spuštění? K tomu slouží práce se soubory.
see(Soubor): Otevře soubor pro čtení. Všechny následující read operace budou číst z tohoto souboru.tell(Soubor): Otevře soubor pro zápis. Všechny následující write operace budou zapisovat do tohoto souboru.seen: Zavře aktuálně otevřený soubor pro čtení.told: Zavře aktuálně otevřený soubor pro zápis.Příklad: Uložení a načtení skóre
% Uloží aktuální skóre do souboru
uloz_skore(Skore) :-
tell('skore.txt'),
write(Skore), write('.'), nl, % Uložíme jako term s tečkou
told.
% Načte skóre ze souboru
nacti_skore(Skore) :-
see('skore.txt'),
read(Skore), % Přečte term
seen.
Teď spojíme vše, co jsme se naučili: fakta, pravidla, proměnné, dynamickou databázi a vstup/výstup. Vytvoříme jednoduchou textovou hru, kde hráč prozkoumává místnosti, sbírá předměty a řeší jednoduché hádanky. Prolog je pro takové hry ideální, protože jeho logická povaha se skvěle hodí pro popis světa a jeho pravidel.
Náš svět bude popsán fakty. Některá fakta budou statická (popis místností), jiná dynamická (kde je hráč, co má v inventáři).
% --- Statická fakta o světě ---
% mistnost(ID, Popis).
mistnost(jeskyne, 'Jsi v temné jeskyni. Slyšíš kapání vody.').
mistnost(les, 'Jsi v hustém lese. Slunce prosvítá skrz koruny stromů.').
mistnost(reka, 'Stojíš u břehu divoké řeky.').
% cesta(Odkud, Smer, Kam).
cesta(jeskyne, sever, les).
cesta(les, jih, jeskyne).
cesta(les, vychod, reka).
cesta(reka, zapad, les).
% objekt(ID, Popis).
objekt(mec, 'Starý, rezavý meč.').
objekt(klic, 'Malý, lesklý klíč.').
objekt(truhla, 'Stará dřevěná truhla.').
% umisteni_objektu(ObjektID, MistnostID).
umisteni_objektu(mec, jeskyne).
umisteni_objektu(klic, les).
umisteni_objektu(truhla, reka).
% --- Dynamické stavy (mění se během hry) ---
% Musíme je deklarovat jako dynamické!
:- dynamic umisteni_hrace/1.
:- dynamic inventar/1.
% Počáteční stav hráče
umisteni_hrace(jeskyne).
% --- Popis aktuální místnosti ---
popis_mistnosti :-
umisteni_hrace(AktualniMistnost),
mistnost(AktualniMistnost, Popis),
write(Popis), nl,
write('Vidíš: '),
(umisteni_objektu(Objekt, AktualniMistnost) ->
objekt(Objekt, PopisObjektu),
write(PopisObjektu), write(' ')
;
write('nic zajímavého.')
), nl,
write('Můžeš jít: '),
(cesta(AktualniMistnost, Smer, _) ->
write(Smer), write(' ')
;
write('nikam.')
), nl.
% --- Pohyb hráče ---
jdi(Smer) :-
umisteni_hrace(AktualniMistnost),
cesta(AktualniMistnost, Smer, NovaMistnost),
retract(umisteni_hrace(AktualniMistnost)),
assert(umisteni_hrace(NovaMistnost)),
popis_mistnosti.
jdi(_) :-
write('Tudy cesta nevede.'), nl.
% --- Vzít předmět ---
vezmi(Objekt) :-
umisteni_hrace(AktualniMistnost),
umisteni_objektu(Objekt, AktualniMistnost),
retract(umisteni_objektu(Objekt, AktualniMistnost)),
assert(inventar(Objekt)),
write('Vzal jsi '), write(Objekt), nl.
vezmi(Objekt) :-
write('Nemůžeš vzít '), write(Objekt), nl.
% --- Zobrazit inventář ---
ukaz_inventar :-
write('Tvůj inventář:'), nl,
(inventar(X) ->
write('- '), write(X), nl,
fail
;
write('Je prázdný.'), nl
).
ukaz_inventar. % Pro případ, že inventář je prázdný a fail selže
% --- Hlavní herní smyčka ---
herni_smycka :-
popis_mistnosti,
write('> '),
read(Prikaz), % Přečte příkaz (např. jdi(sever).)
(Prikaz == konec ->
write('Konec hry.'), nl
;
call(Prikaz), % Zavolá predikát odpovídající příkazu
herni_smycka
).
1. Zkopírujte kód do souboru hra.pl.
2. Spusťte Prolog a načtěte soubor: ?- [hra].
3. Začněte hru: ?- herni_smycka.
4. Zadávejte příkazy (nezapomeňte na tečku!):
* jdi(sever).
* vezmi(mec).
* ukaz_inventar.
* konec. (pro ukončení hry)
Vstupní a výstupní operace, spolu s dynamickou databází, mění Prolog z pouhého "logického stroje" na interaktivní program. Umožňují mu reagovat na uživatele, měnit svůj vnitřní stav a vytvářet tak dynamické a poutavé aplikace, jako jsou hry nebo chatboti.
umisteni_hrace/1 a inventar/1 byly deklarovány jako dynamic?pouzij(Objekt1, Objekt2) a fakt ma_klic(truhla, klic)).write(Term) a write('Text')?pouzij(Objekt). Například, pokud hráč má meč a je v jeskyni, může "použít(mec)" a objevit skrytou chodbu.uloz_hru(Soubor) a nacti_hru(Soubor), které uloží a načtou aktuální pozici hráče a jeho inventář do souboru.