Klondike Solitaire zbývá dát konečně dohromady kousky, které jsme v několika posledních lekcích připravovali!
V těchto materiálech najdeš hotové funkce, které je dobré si prohlédnout a porozumět jim, ale pak si je můžeš zkopírovat do svého kódu. Velké procvičení seznamů a slovníků přijde na konci.
Vzpomínáš si na schéma hry?
V Pythonu to bude vypadat následovně.
Program si ulož do modulu hra.py
:
from klondike import udelej_hru, vypis_hru, presun_kartu, presun_nekolik_karet
print()
hra = udelej_hru()
while not hrac_vyhral(hra):
vypis_hru(hra)
odkud, kam = nacti_tah()
try:
udelej_tah(hra, odkud, kam)
except ValueError as e:
print('Něco je špatně:', e)
vypis_hru(hra)
print('Gratuluji!')
K tomu, abys doplnila funkce do této hry, budeš potřebovat namodelovat
onu hru
.
Ta se skládá z několika balíčků/sloupečků, tedy seznamů karet.
Ve výpisu butou pojmenované A-Z:
U
je dobírací balíček, ze kterého se doplňuje V
.V
je balíček, ze kterého můžeš brát kartyW-Z
jsou cílové hromádky. Cílem hry je na ně přemístit všechny
karty.A-G
jsou sloupečky, kde se karty dají přeskládávat.Těchto 13 pojmenovaných seznamů reprezentuje celý stav rozehrané hry. Hru proto budeme reprezentovat slovníkem, kde klíče budou písmenka a hodloty pak jednotlivé seznamy.
Následující funkce takovou hru vytvoří:
def udelej_hru():
"""Vrátí slovník reprezentující novou hru.
"""
balicek = vytvor_balicek()
hra = {
'U': balicek,
}
# V-Z začínají jako prázdné seznamy
for pismenko in 'VWXYZ':
hra[pismenko] = []
# A-G jsou sloupečky
for pismenko, sloupec in zip('ABCDEFG', rozdej_sloupecky(balicek)):
hra[pismenko] = sloupec
return hra
Další funkce, vypis_hru
, hru vypíše do konzole pomocí print
.
Výsledek bude něco jako:
U V W X Y Z
[???] [ ] [ ] [ ] [ ] [ ]
A B C D E F G
[3♣ ] [???] [???] [???] [???] [???] [???]
[5 ♥] [???] [???] [???] [???] [???]
[6♣ ] [???] [???] [???] [???]
[5♠ ] [???] [???] [???]
[Q ♥] [???] [???]
[4♠ ] [???]
[3 ♦]
V téhle funkci není nic moc objevného a testům záleží na každé mezeře, takže si ji určitě zkopíruj:
def vypis_hru(hra):
"""Vypíše hru textově.
Tato funkce je jen pro zobrazení, používá proto přímo funkci print()
a nic nevrací.
"""
print()
print(' U V W X Y Z')
print('{} {} {} {} {} {}'.format(
popis_vrchni_kartu(hra['U']),
popis_vrchni_kartu(hra['V']),
popis_vrchni_kartu(hra['W']),
popis_vrchni_kartu(hra['X']),
popis_vrchni_kartu(hra['Y']),
popis_vrchni_kartu(hra['Z']),
))
print()
print(' A B C D E F G')
vypis_sloupecky([
hra['A'], hra['B'], hra['C'], hra['D'], hra['E'], hra['F'], hra['G']
])
print()
Pro kontrolu můžeš pustit testy:
udelej_hru
existujeudelej_hru
funguje dle zadánívypis_hru
existujevypis_hru
funguje dle zadáníHra se bude ovládat zadáním dvou jmen balíčku: odkud a kam hráč chce kartu přesunout.
Tahle funkce není součást logiky hry. Dej ji do hra.py
, hned za import
.
def nacti_tah():
while True:
tah = input('Tah? ')
try:
jmeno_zdroje, jmeno_cile = tah.upper()
except ValueError:
print('Tah zadávej jako dvě písmenka, např. UV')
else:
return jmeno_zdroje, jmeno_cile
K úplné hře nám chybí ještě samotná logika hry: hrac_vyhral
a udelej_tah
.
Aby ti hra aspoň trochu fungovala, vytvoř si zástupné funkce,
které nic nekontrolují a nenechají tě vyhrát.
Dej ji do hra.py
, opět hned za import
:
def hrac_vyhral(hra):
"""Vrací True, pokud je hra vyhraná.
"""
return False
def udelej_tah(hra, jmeno_odkud, jmeno_kam):
"""Udělá tah z jednoho místa na druhé.
Místa jsou označovány velkými písmeny (např. 'A', 'V' nebo 'X').
Není-li tah možný, vyhodí ValueError s popisem problému.
"""
presun_kartu(hra[jmeno_odkud], hra[jmeno_kam], True)
Obě bude ještě potřeba upravit, ale teď už si můžeš hru víceméně zahrát! Zkus si to!
Celý tento projekt píšeš ve funkcích s daným jménem a s daným počtem a významem argumentů. To má dvě výhody.
První z nich je testování: připravené testy importují tvé funkce a zkouší je, takže si můžeš být jista, že fungují.
Druhá je zajímavější: máš-li logiku hry, funkce udelej_hru
udelej_tah
a hrac_vyhral
, napsané podle specifikací, může je použít i jakýkoli jiný
program – ne jen ten, který jsi napsala ty.
Jeden takový si můžeš vyzkoušet:
Nainstaluj si do virtuálního prostředí knihovnu pyglet
, která umí ovládat
grafická okýnka:
(venv)$ python -m pip install pyglet
Hru spusť pomocí:
(venv)$ python ui.py
Hra považuje chyby ValueError
za chyby uživatele, tedy tahy proti pravidlům.
Zobrazí je v terminálu a v titulku okýnka.
Ostatní chyby by ve správném programu neměly nastat; objeví se jako normální
chybové hlášky na terminálu.
Obrázky karet jsou z Board Game Pack studia kenney.nl.
Zbývá doplnit „pravidla hry“ do dvou funkcí, hrac_vyhral
a udelej_tah
.
To už bude na tobě.
Hráč vyhrál, pokud jsou všechny karty na cílových hromádkách W
-Z
.
Když tah není podle pravidel, funkce udelej_tah
vyhodí ValueError
.
Možné tahy:
U
→V
:U
musí něco býtV
→U
:presun_kartu(hra['V'], hra['U'], False)
dokud ve V něco je)V
nebo sloupeček A
-G
(zdroj) → hromádka W
-Z
: V
→ „cílový“ sloupeček A
-G
A
-G
→ „cílový“ sloupeček A
-G
W
-Z
→ sloupeček A
-G
(nepovinné – jen v některých variantách hry)*⁾ Kdy přesouvaná karta pasuje na sloupeček?