Dnešní úkoly budou asi povědomé. Vytvoříme totiž ... hru 1D piškvorky!
Dostaneš ale tentokrát hotový testovací soubor a s jeho použitím budeš postupně zkoušet znovu vytvářenou hru.
Vymyslet, jak hezky napsat takový program, to není úplně jednoduché. Proto jsme to udělali za tebe a program jsme rozdělili do malých částí - funkcí a procedur. Z nich budeš hru postupně skládat. Napřed tedy musíš vytvořit ty malé části, pak je poskládáš dohromady.
V praxi to chodí podobně - seniorní kolegové ti řeknou, jaké funkce máš napsat, co mají ty funkce dělat, a jaké mají mít vstupy a výstupy - neboli rozhraní. Na tobě je funkce napsat tak, aby splňovaly toto zadání. Jen tak je totiž bude možné do programu zapojit, aby celek fungoval.
Stejné je to i u našich piškvorek. A právě ten hotový testovací soubor kontroluje nejenom to, jestli jednotlivé kousky fungují správně, ale taky to, že dodržují stanovené rozhraní.
I když máš Piškvorky už hotové z minula, určitě je udělej znovu. Po prázdninové pauze takové opakování jistě přijde vhod. Ty původní Piškvorky můžeš mít vedle a nakouknot do nich, když si nebudeš moct vzpomenout.
Stáhni si soubor s testy, test_piskvorky.py
a dej ho do adresáře,
kde budeš tvořit Piškvorky.
Na ulehčení testování si s aktivním virtuálním prostředím nainstaluj
modul pytest-level
.
Ten umožňuje pouštět jen určité testy – podle toho, jak jsi daleko:
(venv)$ python -m pip install pytest-level
Zkus spustit všechny testy. Asi ti neprojdou:
(venv)$ python -m pytest -v
Pak zkus spustit testy pro úroveň 0:
(venv)$ python -m pytest -v --level 0
Teď se nepustí žádné testy – všechny se přeskočí. Výpis by měl končit nějak takto:
collected N items / N deselected
=== N deselected in 0.01 seconds ===
Zadáš-li v posledním příkazu --level 1
, aktivuje se první z testů.
Pravděpodobně neprojde – v dalším úkolu ho spravíš!
Tvůj postup vždycky bude:
V modulu piskvorky
(tj. v souboru piskvorky.py
)
napiš funkci vyhodnot
, která dostane řetězec
s herním polem 1-D piškvorek
a vrátí jednoznakový řetězec podle stavu hry:
"x"
– Vyhrál hráč s křížky (pole obsahuje "xxx"
)"o"
– Vyhrál hráč s kolečky (pole obsahuje "ooo"
)"!"
– Remíza (pole neobsahuje "-"
, a nikdo nevyhrál)"-"
– Ani jedna ze situací výše (t.j. hra ještě neskončila)Například:
vyhodnot('--------------------')
vrátí '-'
vyhodnot('--o--xxx---o--o-----')
vrátí 'x'
vyhodnot('xoxoxoxoxoxoxoxoxoxo')
vrátí '!'
Zatímco budeš psát tento úkol, průběžně ho kontroluj automatickými testy.
Pusť příkaz python -m pytest -v --level N
podle toho, jak jsi daleko:
--level 1
: V modulu piskvorky
je nějaká funkce vyhodnot
.--level 2
: V případě výhry dává funkce správný výsledek, 'x'
nebo 'o'
--level 3
: V případě remízy dává funkce správný výsledek, '!'
--level 4
: Když hra neskončila, funkce dává správný výsledek, '-'
Odevzdej celý soubor piskvorky.py
.
V modulu util
(tj. v souboru util.py
) napiš funkci tah
, která
dostane řetězec s herním polem, číslo políčka, a symbol (x
nebo o
),
a vrátí herní pole (t.j. řetězec) s daným symbolem umístěným na danou pozici.
Hlavička funkce by tedy měla vypadat nějak takhle:
def tah(pole, pozice, symbol):
"""Vrátí herní pole s daným symbolem umístěným na danou pozici
`pole` je herní pole, na které se hraje.
`pozice` je číslo políčka. Čísluje se od nuly.
`symbol` může být 'x' nebo 'o', podle toho jestli je tah za křížky
nebo za kolečka.
"""
...
Například:
tah('--------------------', 0, 'x')
vrátí 'x-------------------'
tah('--------------------', 19, 'o')
vrátí '-------------------o'
tah('x-o-x-o-x-o-x-o-x-o-', 5, 'x')
vrátí 'x-o-xxo-x-o-x-o-x-o-'
Použij (zavolej) funkci zamen
, kterou už máš napsanou.
Zatímco funkci budeš psát, průběžně ji kontroluj automatickými testy.
Pusť příkaz python -m pytest -v --level N
podle toho, jak jsi daleko:
--level 10
: V modulu util
je nějaká funkce tah
.
--level 11
: Funkce dává na prázdné pole x
nebo o
na dané místo
--level 20
: Hra na pozici, která není v poli, např.
tah('--------------------', -1, 'x')
--level 22
: Hra na obsazené políčko, např.
tah('x-------------------', 0, 'o')
--level 24
: Hra jiným symbolem než 'x'
nebo 'o'
, např.
tah('--------------------', 0, 'řeřicha')
Odevzdej celý soubor util.py
.
V modulu piskvorky
(tj. v souboru piskvorky.py
)
napiš funkci tah_hrace(pole, symbol)
, která dostane řetězec
s herním polem a symbol (x
nebo o
) a:
tah
zjistí, jak vypadá herní pole se zaznamenaným tahem
hráčePokud uživatel zadá špatný vstup (nečíslo, záporné číslo, obsazené políčko apod.), funkce mu vynadá a zeptá se znova.
Hlavička funkce by tedy měla vypadat nějak takhle:
def tah_hrace(pole, symbol):
"""Zeptá se hráče na tah a vrátí nové herní pole
`pole` je herní pole, na které se hraje.
`symbol` může být 'x' nebo 'o', podle toho jestli hráč hraje za křížky
nebo za kolečka.
"""
...
Například zavolání print(tah_hrace('o-------------------', 'x'))
by mohlo
dopadnout takto:
Kam chceš hrát? nevím
Zadávej čísla!
Kam chceš hrát? 0
Tam nejde hrát!
Kam chceš hrát? -1
Tam nejde hrát!
Kam chceš hrát? 151
Tam nejde hrát!
Kam chceš hrát? 2
o-x-----------------
Nezapomeň, že ve vedlejším modulu máš funkci tah
, kterou si můžeš
naimportovat.
Funguje-li tahle funkce s příkladem výše, otestuj ji opět pomocí
automatických testů. Tentokrát nastav level na 30 až 34.
(Testuje se funkce, která volá input
. Jak takový test napsat je nad rámec
tohoto kurzu.)
Odevzdej celý soubor piskvorky.py
(i s funkcí vyhodnot
).
V modulu ai
(tj. v souboru ai.py
)
napiš funkci tah_pocitace(pole, symbol)
, která dostane řetězec s herním
polem a symbol, vybere pozici, na kterou hrát, a vrátí herní pole
se zaznamenaným tahem počítače.
Nejde-li na dané pole hrát, funkce musí skončit s chybou ValueError
.
Použij jednoduchou náhodnou „strategii”:
Navíc k tomu funkce nesmí „zamrznout“ (způsobit nekonečný cyklus),
ať jí předáš jakékoli hodnoty argumentů.
Kdyby strategie výše měla „zamrznout“, funkce ať místo toho způsobí
ValueError
.
Hlavička funkce by tedy měla vypadat nějak takhle:
def tah_pocitace(pole, symbol):
"""Vrátí herní pole se zaznamenaným tahem počítače
`pole` je herní pole, na které se hraje.
`symbol` může být 'x' nebo 'o', podle toho jestli hráč hraje za křížky
nebo za kolečka.
"""
...
Zavolání print(tah_pocitace('o-------------------', 'x'))
by
mohlo vypsat třeba o---------x---------
.
Testy jsou v levelech 40 až 44.
Odevzdej celý soubor ai.py
.
V modulu piskvorky
(tj. v souboru piskvorky.py
)
napiš funkci piskvorky1d
, která:
tah_hrace
, a výsledek uloží jako nové poletah_pocitace
, a výsledek uloží jako nové poleZatím nemusíš řešit konec hry (pokud ho už nemáš z minula).
V modulu hra
(tj. v souboru hra.py
) přidej import a volání funkce
piskvorky1d
.
Původní testy by měly stále procházet.
Automatické testy na celou hru ale nejsou – otestuj to ručně
pomocí python hra.py
!
Tady odevzdej pouze modul piskvorky.py
.
Tady odevzdej soubor hra.py
.
Pošéfuj konec hry. Když někdo vyhraje nebo dojde k remíze, cyklus se ukončí a vypíše se výsledek – třeba s gratulací nebo povzbuzující zpráva.
Stav hry kontroluj po každém tahu.
Nezapomeň, že máš k dispozici funkci vyhodnot
!
Automatické testy na celou hru nejsou – otestuj to ručně! Nezapomeň zkontrolovat remízu.
Odevzdej celý soubor piskvorky.py
.
Zvládneš pro počítač naprogramovat lepší strategii? Třeba aby se snažil hrát vedle svých existujících symbolů nebo aby bránil protihráčovi? Stačí jen docela malé vylepšení!
Testy by stále měly procházet.
Odevzdej celý soubor ai.py
.