Zadání: 28. 11. 2016
Odevzdání: do 07.12.2016 22:00
Poznámky k řešení domácích úkolů:
du5.py
s definicemi všech požadovaných funkcí, tříd a metod. Funkce, třídy i jejich metody se musí jmenovat tak, jak je popsáno v zadání. Kromě požadovaných funkcí si samozřejmě můžete nadefinovat libovolné množství pomocných funkcí (tříd, metod).__init__
.global
).V tomto úkolu si za pomocí jednoduchých objektů naprogramujete jednoduchou textovou dobrodružnou hru (tzv. „textovku“). Hlavní hrdina této hry se vydává do egyptské pyramidy, aby zde čelil mnohým nástrahám a přinesl si odtamtud co nejvíce hodnotných předmětů. Protože v pyramidě se mohou vyskytovat nepřátelská stvoření, bude hrdina také vyzbrojen (a možná v pyramidě najde nějaké zbraně po předchozích pokusech svých méně úspěšných kolegů).
Pyramida bude reprezentována jako množství místností, mezi kterými se dá procházet (někdy jednosměrně). V místnostech se budou nacházet cenné předměty, zbraně a případně i nepřátelé. Všechny tyto věci budeme reprezentovat pomocí Pythonovských objektů. Pro pohyb a jiné akce hrdiny se budou používat textové příkazy zadávané na vstup.
Abyste si mohli své řešení vyzkoušet a otestovat, máte k dispozici předpřipravené předměty, zbraně, příšery a plán pyramidy v souboru IB111DU5template.py
. Tento plán si samozřejmě můžete libovolně upravit.
Vytvořte třídu Item
pro reprezentaci cenných předmětů. Každý předmět má následující atributy:
name
): jednoslovný popis předmětu (musí být jednoznačnou identifikací, bude se používat pro textové příkazy)description
): textový popis předmětuvalue
): cena předmětu (použije se při závěrečném skóre)weight
): hmotnost předmětu (hrdina má omezenou nosnost)Všechny tyto atributy nastaví metoda __init__(self, name, description, value, weight)
.
Dále pak ve třídě Item
vytvořte metodu describe(self)
, která vypíše popis předmětu na výstup ve formátu uvedeném níže.
>>> it = Item("mince", "Stara petikoruna.", 5, 1)
>>> it.describe()
mince: Stara petikoruna. (cena: 5, vaha 1)
Vytvořte třídu Weapon
pro reprezentaci zbraní. Každá zbraň má následující atributy:
name
): jednoslovný popis zbraně (musí být jednoznačnou identifikací, bude se používat pro textové příkazy)description
): textový popis zbraněattack
): útočné číslo zbraně (používá se při souboji)defence
): obranné číslo zbraně (používá se při souboji)Všechny tyto atributy nastaví metoda __init__(self, name, description, attack, defence)
.
Dále pak ve třídě Weapon
vytvořte metodu describe(self)
, která vypíše popis zbraně na výstup ve formátu uvedeném níže.
>>> w = Weapon("dyka", "Stara rezava dyka. Dost tupa.", 5, 2)
>>> w.describe()
dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
Vytvořte třídu Monster
pro reprezentaci nepřátelských příšer. Každá příšera má následující atributy:
name
): může být i víceslovnéattack
): útočné číslodefence
): obranné číslovigilance
): číslo mezi 1 a 20, které udává, jak snadno se příšera vzbudí, a rovněž řeší iniciativu při soubojíchhealth
): počet bodů zdravísleeping
): pravdivostní hodnota udávající, zda příšera spí; na začátku vždy nastaveno na True
Všechny tyto atributy nastaví metoda __init__(self, name, attack, defence, vigilance, health)
.
Dále pak ve třídě Monster
vytvořte metodu react_to_noise(self)
. Tato metoda reprezentuje reakci příšery na hluk (při příchodu do místnosti apod.). V této metodě se hodí dvacetistěnnou kostkou (vygeneruje se číslo od 1 do 20) a pokud je toto číslo menší nebo rovno hodnotě ostražitosti dané příšery, pak se její stav sleeping
nastaví na False
.
>>> m = Monster("zla mumie", 10, 5, 10, 100)
>>> print m.sleeping
True
>>> m.react_to_noise() # polovicni sance, ze se probudi
>>> print m.sleeping
False
Vytvořte třídu Player
pro reprezentaci hráče. Hráč má následující atributy:
name
)max_health
): bude na začátku nastaveno na náhodnou hodnotu mezi 150 a 200health
): bude na začátku nastaveno na stejnou hodnotu jako max_health
capacity
): označuje, kolik toho hrdina unese v batohu; na začátku bude nastavena na náhodnou hodnotu mezi 150 a 200weapon
): aktuálně držená zbraň; aby hrdina nešel do pyramidy zcela neozbrojen, nějakou mu na začátek dejte – doporučuji starou rezavou dýku popsanou v části 2 zadáníbag
): reprezentuje cenné předměty, které hrdina nasbíral; na začátku je batoh prázdný; přesnou implementaci nechávám na vás, doporučil bych ale použít slovníkVšechny tyto atributy nastaví metoda __init__(self, name)
.
Dále pak ve třídě Player
vytvořte následující metody:
rest(self)
– odpočinek; přidá hráči 50 bodů zdraví (ale ne víc, než je jeho maximální zdraví).add_to_bag(self, item)
se pokusí přidat do batohu zadaný cenný předmět. Pokud by přidání předmětu překročilo kapacitu, nepřidá jej a vrátí False
, jinak vrátí True
. Zároveň příslušným způsobem sníží atribut capacity
.take_from_bag(self, item_name)
z batohu vybere cenný předmět s daným názvem. Vrátí vybraný předmět, pokud takový existoval, jinak vrátí None
.take_weapon(self, weapon)
vymění hráčovu zbraň za zadanou. Vrátí původní hráčovu zbraň.describe(self)
vypíše informace o hráči ve formátu popsaném níže.score(self)
vrátí součet hodnot všech cenných předmětů v batohu.>>> p = Player("Indiana Jones")
>>> p.describe()
Jmeno hrace: Indiana Jones
Zdravi: 182/182
Zbyvajici kapacita batohu: 152
Prazdny batoh.
Zbran: dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
>>> print p.add_to_bag(it)
True
>>> p.describe()
Jmeno hrace: Indiana Jones
Zdravi: 182/182
Zbyvajici kapacita batohu: 151
Obsah batohu:
- mince: Stara petikoruna. (cena: 5, vaha: 1)
Zbran: dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
>>> print p.add_to_bag(Item("tuna", "Fakt tezka vec", 100, 200))
False
>>> x = p.take_from_bag("mince")
>>> x.describe()
mince: Stara petikoruna. (cena: 5, vaha: 1)
>>> lte = Weapon("lte", "Laserovy takticky eliminator.", 100, 0)
>>> y = p.take_weapon(lte)
>>> y.describe()
dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
>>> p.describe()
Jmeno hrace: Indiana Jones
Zdravi: 182/182
Zbyvajici kapacita batohu: 152
Prazdny batoh.
Zbran: lte: Laserovy takticky eliminator. (utok: 100, obrana: 0)
Když už máte hráče i nepřátele, je čas na implementaci souboje. Vytvořte funkci fight(player, monster)
, která odehraje souboj mezi hráčem a příšerou podle následujících pravidel:
V průběhu souboje by měla funkce fight
vypisovat podrobné informace o jeho průběhu (včetně zdraví účastníků). Pro přehlednost nechte uživatele mezi jednotlivými koly stisknout Enter (nápověda: použijte raw_input
). Na konci pak funkce fight
vrátí True
, pokud byl protivník poražen, nebo False
, pokud byl poražen hráč.
>>> p = Player("Indiana Jones")
>>> m = Monster("mumie", 5, 2, 10, 100)
>>> result = fight(p, m)
Souboj s protivnikem: mumie (100 zdravi)
Tvoje zdravi: 173/173
Protivnik "mumie" na tebe utoci.
Tento utok ti zpusobil 3 zraneni.
Tvoje zdravi: 170/173
Stiskni enter:
Utocis na protivnika.
Tvuj utok zpusobil 2 zraneni.
Protivnikovo zdravi: 98
Stiskni enter:
Protivnik "mumie" na tebe utoci.
Tento utok ti zpusobil 2 zraneni.
Tvoje zdravi: 168/173
Stiskni enter:
Utocis na protivnika.
Tvuj utok zpusobil 3 zraneni.
Protivnikovo zdravi: 95
Stiskni enter:
# ... vynechano 248 radku ...
Protivnik "mumie" na tebe utoci.
Tento utok ti zpusobil 2 zraneni.
Tvoje zdravi: 73/173
Stiskni enter:
Utocis na protivnika.
Tvuj utok zpusobil 3 zraneni.
Protivnikovo zdravi: 4
Stiskni enter:
Protivnik "mumie" na tebe utoci.
Tento utok ti zpusobil 4 zraneni.
Tvoje zdravi: 69/173
Stiskni enter:
Utocis na protivnika.
Tvuj utok zpusobil 4 zraneni.
Protivnikovo zdravi: 0
Stiskni enter:
Protivnik je porazen!
>>> print result
True
Vytvořte třídu Room
pro reprezentaci místností v pyramidě. Každá místnost má následující atributy:
description
): text, který se vypíše při vstupu do místnostiending
): True
, pokud je vstupem do místnosti hra úspěšně ukončena, False
, pokud je vstupem do místnosti hra neúspěšně ukončena, pro ostatní místnosti None
monster
): příšera nacházející se v místnosti; na začátku None
weapons
): seznam zbraní v místnosti; na začátku prázdný; doporučuji použít slovníkitems
): seznam cenných předmětů v místnosti; na začátku prázdný; doporučuji použít slovníkdirections
): slovník s položkami ve tvaru smer : mistnost
; na začátku prázdnýVšechny tyto atributy nastaví metoda __init__(self, description, ending=None)
. Všimněte si, že parametr ending
má implicitní hodnotu.
Dále pak ve třídě Room
vytvořte následující metody:
set_monster(self, monster)
nastaví aktuální příšeru v místnosti.add_weapon(self, weapon)
přidá zadanou zbraň do místnosti.remove_weapon(self, weapon)
odebere zadanou zbraň z místnosti, pokud se v ní vyskytuje.add_item(self, item)
a remove_item(self, item)
fungují podobně, jen pro cenné předměty.add_direction(self, name, room)
přidá do slovníku směrů položku name : room
.describe(self)
vypíše popis místnosti. Popis bude obsahovat informace o zbraních a předmětech v místnosti. Dále pak se vypíše informace o možných směrech ven z místnosti. Nakonec se vypíše informace o tom, zda je v místnosti nějaká příšera a jestli spí nebo ne. Před výpisem o stavu příšery se zavolá její metoda react_to_noise
.Příklad toho, jak může vypadat popis místnosti:
Jsi uprostred chodby, ktera vede zapadovychodnim smerem.
V mistnosti se nachazeji nasledujici zbrane:
- sekera: Obrovska oborucni sekera. Uneses ji? (utok: 15, obrana: 1)
- kus: Samostril. Ucinny, ale obtizne se natahuje. (utok: 20, obrana: 0)
V mistnosti se nachazeji nasledujici cenne predmety:
- prsten1: Prsten s diamantem. (cena: 50, vaha: 1)
- prsten2: Prsten bez diamantu. (cena: 5, vaha: 1)
Z mistnosti se da odejit nasledujicimi smery:
- zapad
- vychod
V mistnosti je slaba mumie. Spi.
Aby byla hra zajímavější, tak chceme většinu předmětů, zbraní a příšer rozmístit po pyramidě náhodně. K tomu účelu vytvořte funkci randomize(rooms, monsters, items, weapons)
, která dostane seznamy místností, příšer, předmětů a zbraní a provede náhodné rozmístění. Pamatujte na to, že v každé místnosti smí být jen jedna příšera.
Poznámka: Funkce randomize
nemá předměty (zbraně, příšery) duplikovat, jen je má rozmístit po místnostech. To znamená, že ve výsledku nemůže být jeden předmět ve více místnostech zároveň.
Máte-li už všechno připraveno, můžete se pustit do implementace samotné hry. Napište funkci play(start)
, která jako parametr dostane počáteční místnost. Funkce by se nejprve měla hráče zeptat na jméno, poté vypsat základní informace o hráči a o počáteční místnosti. Dále pak bude hra očekávat textové příkazy (popsané dále) a reagovat na ně. Hra končí v těchto případech:
ending
je True
. V tu chvíli můžete hráči pogratulovat a vypsat jeho dosažené skóre.ending
je False
. Tento konec hry je neúspěšný.konec
(viz dále).Příkazy, které může hráč zadávat jsou následující:
(Pro jednoduchost zde ignorujeme správnou gramatiku, takže příkazy budou znít jdi sever
a vezmi dyka
, ale tím se zbytečně netrapte.)
info
: Vypíše aktuální informace o hráči.jdi <smer>
: Hráč odejde z místnosti zadaným směrem.vezmi <vec>
: Hráč sebere (pokud možno) zadanou věc, která může být buď zbraň nebo cenný předmět. Po sebrání věci znovu vypište popis místnosti (jednak proto, aby bylo vidět, k jaké změně (ne)došlo, jednak proto, že každá manipulace s předměty v místnosti může vzbudit příšeru). Nezapomeňte, že hráč může nést jen jednu zbraň, proto při sebrání zbraně musí svou původní v místnosti zanechat.odpocinek
: Pokud je hráč v místnosti bez příšer, odpočine si a dočerpá zdraví (metodou rest
). V místnosti s příšerou odpočinek není možný.poloz <predmet>
: Hráč položí daný cenný předmět, který má v batohu, pokud je to možné. Pro jednoduchost příkaz funguje pouze pro cenné předměty, ne pro zbraně.konec
: Ukončení hry.napoveda
: Vypíše seznam všech povolených příkazů.Nemusíte nijak reagovat na špatně napsané příkazy. Bylo by ale lepší, pokud by se vaše hra při zadání špatného příkazu nezhroutila.
Ve chvíli, kdy se hráč nachází v místnosti s probuzenou příšerou, začne okamžitě probíhat souboj (bez možnosti útěku). Pokud souboj dopadne pro hráče vítězně, příšera je z místnosti odstraněna.
Příklad toho, jak může vypadat sehrání hry:
Zadej sve jmeno: Indiana Jones
Jmeno hrace: Indiana Jones
Zdravi: 170/170
Zbyvajici kapacita batohu: 168
Prazdny batoh.
Zbran: dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
Jsi ve vchodu do pyramidy.
Z mistnosti se da odejit nasledujicimi smery:
- ven
- dovnitr
Zadej prikaz: jdi dovnitr
Jsi v pyramide, chodby vedou na sever, na jih a na vychod.
V mistnosti se nachazeji nasledujici zbrane:
- r_mec: Rezavy mec. (utok: 6, obrana: 4)
V mistnosti se nachazeji nasledujici cenne predmety:
- prsten3: Zlaty prsten. (cena: 20, vaha: 1)
Z mistnosti se da odejit nasledujicimi smery:
- jih
- sever
- vychod
V mistnosti je stir. Spi.
Zadej prikaz: vezmi r_mec
Beres zbran r_mec.
Jsi v pyramide, chodby vedou na sever, na jih a na vychod.
V mistnosti se nachazeji nasledujici zbrane:
- dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
V mistnosti se nachazeji nasledujici cenne predmety:
- prsten3: Zlaty prsten. (cena: 20, vaha: 1)
Z mistnosti se da odejit nasledujicimi smery:
- jih
- sever
- vychod
V mistnosti je stir. Spi.
Zadej prikaz: vezmi prsten3
Beres predmet prsten3.
Jsi v pyramide, chodby vedou na sever, na jih a na vychod.
V mistnosti se nachazeji nasledujici zbrane:
- dyka: Stara rezava dyka. Dost tupa. (utok: 5, obrana: 2)
Z mistnosti se da odejit nasledujicimi smery:
- jih
- sever
- vychod
V mistnosti je stir. Spi.
Zadej prikaz: jdi jih
Jsi v klikate chodbe, ze ktere se da pokracovat na sever a na zapad.
U steny chodby jsou schody nahoru.
V mistnosti se nachazeji nasledujici zbrane:
- sekera: Obrovska oborucni sekera. Uneses ji? (utok: 15, obrana: 1)
V mistnosti se nachazeji nasledujici cenne predmety:
- miska: Zlata miska osazena drahokamy. (cena: 120, vaha: 5)
- prsten2: Prsten bez diamantu. (cena: 5, vaha: 1)
- vaza: Cenna anticka vaza. (cena: 75, vaha: 20)
Z mistnosti se da odejit nasledujicimi smery:
- nahoru
- zapad
- sever
V mistnosti je ostrazita mumie. Je vzhuru!
Souboj s protivnikem: ostrazita mumie (50 zdravi)
Tvoje zdravi: 170/170
Protivnik "ostrazita mumie" na tebe utoci.
Tento utok ti zpusobil 2 zraneni.
Tvoje zdravi: 168/170
Stiskni enter:
# ... vynechan souboj ...
Utocis na protivnika.
Tvuj utok zpusobil 7 zraneni.
Protivnikovo zdravi: -6
Stiskni enter:
Protivnik je porazen!
Jsi v klikate chodbe, ze ktere se da pokracovat na sever a na zapad.
U steny chodby jsou schody nahoru.
V mistnosti se nachazeji nasledujici zbrane:
- sekera: Obrovska oborucni sekera. Uneses ji? (utok: 15, obrana: 1)
V mistnosti se nachazeji nasledujici cenne predmety:
- miska: Zlata miska osazena drahokamy. (cena: 120, vaha: 5)
- prsten2: Prsten bez diamantu. (cena: 5, vaha: 1)
- vaza: Cenna anticka vaza. (cena: 75, vaha: 20)
Z mistnosti se da odejit nasledujicimi smery:
- nahoru
- zapad
- sever
Zadej prikaz: vezmi miska
Beres predmet miska.
Jsi v klikate chodbe, ze ktere se da pokracovat na sever a na zapad.
U steny chodby jsou schody nahoru.
V mistnosti se nachazeji nasledujici zbrane:
- sekera: Obrovska oborucni sekera. Uneses ji? (utok: 15, obrana: 1)
V mistnosti se nachazeji nasledujici cenne predmety:
- prsten2: Prsten bez diamantu. (cena: 5, vaha: 1)
- vaza: Cenna anticka vaza. (cena: 75, vaha: 20)
Z mistnosti se da odejit nasledujicimi smery:
- nahoru
- zapad
- sever
Zadej prikaz: info
Jmeno hrace: Indiana Jones
Zdravi: 145/170
Zbyvajici kapacita batohu: 162
Obsah batohu:
- prsten3: Zlaty prsten. (cena: 20, vaha: 1)
- miska: Zlata miska osazena drahokamy. (cena: 120, vaha: 5)
Zbran: r_mec: Rezavy mec. (utok: 6, obrana: 4)
Zadej prikaz: jdi zapad
Jsi v klikate chodbe, ze ktere se da pokracovat na sever a na vychod.
V mistnosti se nachazeji nasledujici cenne predmety:
- prsten4: Zelezny prsten. (cena: 1, vaha: 1)
Z mistnosti se da odejit nasledujicimi smery:
- vychod
- sever
V mistnosti je velky zly pavouk. Spi.
Zadej prikaz: jdi sever
Vchazis do mistnosti, kdyz tu slysis, jak pod tebou cvaklo propadlo.
Z mistnosti se da odejit nasledujicimi smery:
- dolu
Zadej prikaz: jdi dolu
Padas do mistnosti plne hadu. Tim to pro tebe konci.
--- neuspesny konec hry ---
Můžete získat bonusové body, pokud svou hru proti tomuto základnímu zadání nějak rozšíříte. Do bonusových rozšíření se ale pouštějte až ve chvíli, kdy vám funguje základní varianta. Možných rozšíření je jistě celá řada, můžete se inspirovat následujícími náměty: ukládání skóre hráčů do souboru a výpis nejlepších hrdinů po skončení hry, rozšíření hry o jiné textové příkazy, rozšíření soubojového systému, počítání kroků, omezení odpočívání, apod. V komentářích popište, v čem vaše rozšíření spočívá.