Pojďme vytvořit karetní hru Klondike Solitaire, kterou možná znáš v nějaké počítačové verzi.
Naše hra bude ze začátku jednodušší – nebudeme se zabývat grafikou, ale logikou hry. „Grafiku“ zatím zajistí textová konzole:
U V W X Y Z
[???] [ ] [ ] [ ] [ ] [ ]
A B C D E F G
[3♣ ] [???] [???] [???] [???] [???] [???]
[5 ♥] [???] [???] [???] [???] [???]
[6♣ ] [???] [???] [???] [???]
[5♠ ] [???] [???] [???]
[Q ♥] [???] [???]
[4♠ ] [???]
[3 ♦]
Hra funguje takto:
Karta bude trojice (hodnota, barva, je_licem_nahoru) – viz sraz.
Následující funkce (v souboru karty.py
) nám zjednoduší práci:
def popis_kartu(karta):
"""Vrátí popis karty, např. [Q ♥] nebo [6♣ ] nebo [???]
Trojice čísla (2-13), krátkého řetězce ('Sr', 'Ka', 'Kr' nebo 'Pi')
a logické hodnoty (True - lícem nahoru; False - rubem) se jednoduše
zpracovává v Pythonu, ale pro "uživatele" není nic moc.
Proto je tu tahle funkce, která kartu hezky "popíše".
Aby byly všechny karty jedno číslo nebo písmeno, se desítka
se vypisuje jako "X".
Aby se dalo rychle odlišit červené (♥♦) karty od černých (♣♠),
mají červené mezeru před symbolem a černé za ním.
"""
def otoc_kartu(karta, pozadovane_otoceni):
"""Vrátí kartu otočenou lícem nahoru (True) nebo rubem nahoru (False)
Nemění původní trojici; vytvoří a vrátí novou.
(Ani by to jinak nešlo – n-tice se, podobně jako řetězce čísla, měnit
nedají.)
"""
Funkce najdeš v souboru karty.py
. Projdi si je; rozumíš jim?
Testy k nim jsou v test_karty.py
– ty procházet nemusíš, jestli nechceš.
Stáhni si soubor s testy, test_klondike.py, a dej ho do adresáře,
kde budeš tvořit hru a kde máš karty.py
.
Na ulehčení testování si nainstaluj modul pytest-level
.
Ten umožňuje pouštět jen určité testy – podle toho, jak jsi daleko.
python -m pip install pytest pytest-level
Zkus pustit všechny testy. Asi ti neprojdou:
python -m pytest -v
Pak zkus pustit testy pro úroveň 0:
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íš!
Jako první věc ve hře potřebujeme rozdat balíček karet. Co je to ale takový balíček? Jak se dá balíček karet reprezentovat pomocí řetězců, čísel, seznamů, n-tic a podobně?
Způsobů, jak takový balíček karet reprezentovat, je více. Abychom měli projekt všichni stejný (a aby k němu mohly být testy), je v těchto materiálech tento úkol už vyřešený.
Balíček karet bude seznam karet – tedy seznam trojic. To dává smysl – karet v balíčku může být různý počet (klidně 0), kar se z něj dají brát nebo do něj přidávat, balíček se dá zamíchat nebo seřadit.
Balíček bude například:
balicek = [(4, 'Pi', True), (4, 'Sr', True), (4, 'Ka', False), (4, 'Kr', True)]
prazdny_balicek = []
Napiš následující funkci, která balíček popíše:
def popis_balicku(balicek):
"""Vrátí popis daného balíčku karet -- tedy vrchní karty, která je vidět"""
popis_kartu
z modulu karty
.)[ ]
(3 mezery v hranatých závorkách).Napiš následující funkci:
def vytvor_balicek():
"""Vrátí balíček 52 karet – od esa (1) po krále (13) ve čtyřech barvách
Karty jsou otočené rubem nahoru (nejsou vidět).
"""
Když výsledek funkce vytvor_balicek
vypíšeš, je docela nepřehledný.
Funkce popis_balicku
tomu příliš nepomáhá, protože popisuje jen vrchní kartu.
Aby se ti s balíčkem lépe pracovalo, vytvoř následující funkci:
def popis_seznam_karet(karty):
"""Vrátí popis všech karet v balíčku. Jednotlivé karty odděluje mezerami.
"""
Nezapomeň využít funkci popis_kartu
!
Například:
>>> karty = [
(13, 'Pi', True),
(12, 'Sr', True),
(11, 'Ka', True),
(10, 'Kr', False),
]
>>> popis_seznam_karet(karty)
[A♠ ] [2 ♥] [3 ♦] [???]
Teď zkus rozdat 7 sloupečků karet, tedy konečně první krok hry.
V N-tém sloupečku (počítáno od nuly) je N karet rubem nahoru plus jedna karta lícem nahoru. Karty do sloupečků se z balíčku rozdávají postupně: vždy se lízne vrchní (poslední) karta z balíčku a dá se na konec sloupečku.
Napiš následující funkci:
def rozdej_sloupecky(balicek):
"""Rozdá z daného balíčku 7 "sloupečků" -- seznamů karet
Karty ve sloupečcích jsou odstraněny z balíčku.
Vrátí všechny sloupečky -- tedy seznam sedmi seznamů.
"""
Například:
>>> balicek = priprav_balicek()
>>> sloupecky = rozdej_sloupecky(balicek)
24
>>> popis_seznam_karet(sloupecky[0])
[3♣ ]
>>> popis_seznam_karet(sloupecky[1])
[???] [5 ♥]
>>> popis_seznam_karet(sloupecky[2])
[???] [???] [6♣ ]
>>> popis_seznam_karet(sloupecky[6])
[???] [???] [???] [???] [???] [???] [3 ♦]
>>> len(balicek) # Z balíčku zmizely karty, které jsou ve sloupečcích
Jak tahle funkce funguje?
pop
) kartu zvrchu balíčkuappend
)pop
) kartu zvrchu balíčkuotoc_kartu
)
a dá vršek sloupečku (append
)Testy:
Vzpomínáš si na základní schéma hry?
Rozdání balíčku a sloupečků už víceméně máš! Pro teď přeskoč zjišťování, jestli hráč vyhrál, a podívej se na vypsání stavu hry.
Například, pokud jsou sloupečky tyto:
sloupecky = [
[(1, 'Pi', True), (7, 'Sr', True)],
[(2, 'Sr', True), (6, 'Ka', True)],
[(3, 'Ka', True), (5, 'Kr', False)],
[(4, 'Kr', False), (4, 'Pi', True)],
[(5, 'Pi', False), (3, 'Sr', True)],
[(6, 'Sr', True), (2, 'Ka', True)],
[(7, 'Ka', True), (1, 'Kr', True), (10, 'Ka', True)],
]
… můžeš je vypsat jednotlivě:
>>> for sloupecek in sloupecky:
>>> print(popis_seznam_karet(sloupecek))
[A♠ ] [7 ♥]
[2 ♥] [6 ♦]
[3 ♦] [???]
[???] [4♠ ]
[???] [3 ♥]
[6 ♥] [2 ♦]
[7 ♦] [A♣ ] [X ♦]
To ale není to, co chceme vypsat ve hře: tam se karty v jednom sloupečku ukazují pod sebou.
Budeš potřebovat na prvním řádku ukázat první karty ze všech sloupečků, na druhém řádku druhé karty ze všech sloupečků, na třetím třetí, atd. Pro příklad výše by tedy mělo vyjít:
[A♠ ] [2 ♥] [3 ♦] [???] [???] [6 ♥] [7 ♦]
[7 ♥] [6 ♦] [???] [4♠ ] [3 ♥] [2 ♦] [A♣ ]
[X ♦]
Znáš funkci, která vezme několik seznamů, a dá ti k dispozici napřed první prvky těch seznamů, potom druhé, a tak dál? Zkus ji použít!
def vypis_sloupecky(sloupecky):
"""Vypíše sloupečky textově.
Tato funkce je jen pro zobrazení, používá proto přímo funkci print()
a nic nevrací.
"""
Aby sis v budoucnu ušetřila práci, a aby sis procvičila seznamy, zkus teď napsat dvě funkce, které přesunují karty mezi balíčky:
def presun_kartu(sloupec_odkud, sloupec_kam, pozadovane_otoceni):
"""Přesune vrchní kartu ze sloupce "odkud" do sloupce "kam".
Karta bude otocena lícem nebo rubem nahoru podle "pozadovane_otoceni".
"""
def presun_nekolik_karet(sloupec_odkud, sloupec_kam, pocet):
"""Přesune "pocet" vrchních karet ze sloupce "odkud" do sloupce "kam".
Karty se přitom neotáčí.
"""
presun_kartu
existujepresun_kartu
funguje dle zadánípresun_nekolik_karet
existujepresun_nekolik_karet
funguje dle zadáníVzpomínáš si na schéma hry?
V Pythonu to bude vypadat následovně.
Program si ulož do modulu hra.py
:
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 V W X Y Z
[???] [ ] [ ] [ ] [ ] [ ]
A B C D E F G
[3♣ ] [???] [???] [???] [???] [???] [???]
[5 ♥] [???] [???] [???] [???] [???]
[6♣ ] [???] [???] [???] [???]
[5♠ ] [???] [???] [???]
[Q ♥] [???] [???]
[4♠ ] [???]
[3 ♦]
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
A takhle se hra dá vypsat:
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_balicku(hra['U']),
popis_balicku(hra['V']),
popis_balicku(hra['W']),
popis_balicku(hra['X']),
popis_balicku(hra['Y']),
popis_balicku(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
.
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 nám hra aspoň trochu fungovala, vytvoř si zástupné funkce, které nic nekontrolují a nenechají tě vyhrát:
def hrac_vyhral(hra):
"""Vrací True, pokud je hra vyhraná.
"""
return False
def udelej_tah(hra, jmeno_odkud, jmeno_kam):
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
:
(venv)$ python -m pip install pyglet
Hru spusť pomocí:
(venv)$ python ui.py
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) → cíl 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?
{ "data": { "sessionMaterial": { "id": "session-material:2019/brno-podzim-pondeli:solitaire:2", "title": "Klondike Solitaire (dočasné materiály)", "html": "\n \n \n\n <h1>Klondike Solitaire</h1>\n<p>Pojďme vytvořit karetní hru <em>Klondike Solitaire</em>, kterou možná znáš v nějaké\npočítačové verzi.</p>\n<p><span class=\"figure\"><a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/klondike.png\"><img src=\"/2019/brno-podzim-pondeli/projects/klondike/static/klondike.png\" alt=\"Jedna z grafických podob hry\"></a></span></p>\n<p>Naše hra bude ze začátku jednodušší – nebudeme se zabývat grafikou,\nale logikou hry.\n„Grafiku“ zatím zajistí textová konzole:</p>\n<div class=\"highlight\"><pre><code> U V W X Y Z\n [???] [ ] [ ] [ ] [ ] [ ]\n\n A B C D E F G\n [3♣ ] [???] [???] [???] [???] [???] [???]\n [5 ♥] [???] [???] [???] [???] [???]\n [6♣ ] [???] [???] [???] [???]\n [5♠ ] [???] [???] [???]\n [Q ♥] [???] [???]\n [4♠ ] [???]\n [3 ♦]</code></pre></div><h2>Schéma hry</h2>\n<p>Hra funguje takto:</p>\n<ul>\n<li>Rozdej balíček a sloupečky karet</li>\n<li>Dokud hráč nevyhrál:<ul>\n<li>Zobraz stav hry</li>\n<li>Zeptej se hráče, odkud a kam chce hrát</li>\n<li>Je-li to možné:<ul>\n<li>Proveď tah</li>\n</ul>\n</li>\n<li>Jinak:<ul>\n<li>Vynadej hráči, že daný tah nedává smysl</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>Pogratuluj hráči</li>\n</ul>\n<h2>Karta</h2>\n<p>Karta bude trojice (hodnota, barva, je_licem_nahoru) – viz sraz.\nNásledující funkce (v souboru <a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/karty.py\"><code>karty.py</code></a>) nám zjednoduší práci:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">popis_kartu</span><span class=\"p\">(</span><span class=\"n\">karta</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Vrátí popis karty, např. [Q ♥] nebo [6♣ ] nebo [???]</span>\n\n<span class=\"sd\"> Trojice čísla (2-13), krátkého řetězce ('Sr', 'Ka', 'Kr' nebo 'Pi')</span>\n<span class=\"sd\"> a logické hodnoty (True - lícem nahoru; False - rubem) se jednoduše</span>\n<span class=\"sd\"> zpracovává v Pythonu, ale pro "uživatele" není nic moc.</span>\n<span class=\"sd\"> Proto je tu tahle funkce, která kartu hezky "popíše".</span>\n\n<span class=\"sd\"> Aby byly všechny karty jedno číslo nebo písmeno, se desítka</span>\n<span class=\"sd\"> se vypisuje jako "X".</span>\n\n<span class=\"sd\"> Aby se dalo rychle odlišit červené (♥♦) karty od černých (♣♠),</span>\n<span class=\"sd\"> mají červené mezeru před symbolem a černé za ním.</span>\n<span class=\"sd\"> """</span>\n</pre></div><div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">otoc_kartu</span><span class=\"p\">(</span><span class=\"n\">karta</span><span class=\"p\">,</span> <span class=\"n\">pozadovane_otoceni</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Vrátí kartu otočenou lícem nahoru (True) nebo rubem nahoru (False)</span>\n\n<span class=\"sd\"> Nemění původní trojici; vytvoří a vrátí novou.</span>\n<span class=\"sd\"> (Ani by to jinak nešlo – n-tice se, podobně jako řetězce čísla, měnit</span>\n<span class=\"sd\"> nedají.)</span>\n<span class=\"sd\"> """</span>\n</pre></div><p>Funkce najdeš v souboru <a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/karty.py\"><code>karty.py</code></a>. Projdi si je; rozumíš jim?</p>\n<p>Testy k nim jsou v <a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/test_karty.py\"><code>test_karty.py</code></a> – ty procházet nemusíš, jestli nechceš.</p>\n<h2>Testy a úkoly</h2>\n<p>Stáhni si soubor s testy, <a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/test_klondike.py\">test_klondike.py</a>, a dej ho do adresáře,\nkde budeš tvořit hru a kde máš <code>karty.py</code>.</p>\n<p>Na ulehčení testování si nainstaluj modul <code>pytest-level</code>.\nTen umožňuje pouštět jen určité testy – podle toho, jak jsi daleko.</p>\n<div class=\"highlight\"><pre><code>python -m pip install pytest pytest-level\n\n</code></pre></div><p>Zkus pustit všechny testy. Asi ti neprojdou:</p>\n<div class=\"highlight\"><pre><code>python -m pytest -v\n\n</code></pre></div><p>Pak zkus pustit testy pro úroveň 0:</p>\n<div class=\"highlight\"><pre><code>python -m pytest -v --level 0\n\n</code></pre></div><p>Teď se nepustí žádné testy – všechny se přeskočí. Výpis by měl končit nějak takto:</p>\n<div class=\"highlight\"><pre><code>collected N items / N deselected\n=== N deselected in 0.01 seconds ===\n\n</code></pre></div><p>Zadáš-li v posledním příkazu --level 1, aktivuje se první z testů. Pravděpodobně neprojde – v dalším úkolu ho spravíš!</p>\n<h2>Popis balíčku</h2>\n<p>Jako první věc ve hře potřebujeme rozdat <em>balíček</em> karet.\nCo je to ale takový balíček?\nJak se dá balíček karet reprezentovat pomocí řetězců, čísel, seznamů,\n<var>n</var>-tic a podobně?</p>\n<p>Způsobů, jak takový balíček karet reprezentovat, je více.\nAbychom měli projekt všichni stejný (a aby k němu mohly být testy),\nje v těchto materiálech tento úkol už vyřešený.</p>\n<p>Balíček karet bude <em>seznam</em> karet – tedy seznam trojic.\nTo dává smysl – karet v balíčku může být různý počet (klidně 0),\nkar se z něj dají brát nebo do něj přidávat, balíček se dá zamíchat nebo\nseřadit.</p>\n<p>Balíček bude například:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">balicek</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">'Pi'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">'Sr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">'Ka'</span><span class=\"p\">,</span> <span class=\"bp\">False</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">'Kr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)]</span>\n<span class=\"n\">prazdny_balicek</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</pre></div><p>Napiš následující funkci, která balíček popíše:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">balicek</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Vrátí popis daného balíčku karet -- tedy vrchní karty, která je vidět"""</span>\n</pre></div><ul>\n<li>level 10: Funkce existuje</li>\n<li>level 11: Funkce vrátí popis poslední karty. (Bude se hodit funkce <code>popis_kartu</code> z modulu <code>karty</code>.)</li>\n<li>level 12: Funkce popíše prázdný balíček jako <code>[ ]</code> (3 mezery v hranatých závorkách).</li>\n</ul>\n<h2>Vytvoření balíčku</h2>\n<p>Napiš následující funkci:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">vytvor_balicek</span><span class=\"p\">():</span>\n <span class=\"sd\">"""Vrátí balíček 52 karet – od esa (1) po krále (13) ve čtyřech barvách</span>\n\n<span class=\"sd\"> Karty jsou otočené rubem nahoru (nejsou vidět).</span>\n<span class=\"sd\"> """</span>\n</pre></div><ul>\n<li>level 20: Funkce existuje</li>\n<li>level 21: V balíčku je 52 karet, žádné se neopakují.</li>\n<li>level 22: V balíčku jsou všechny požadované karty.</li>\n<li>level 23: Balíček je zamíchaný.</li>\n</ul>\n<h2>Rozepsání balíčku</h2>\n<p>Když výsledek funkce <code>vytvor_balicek</code> vypíšeš, je docela nepřehledný.\nFunkce <code>popis_balicku</code> tomu příliš nepomáhá, protože popisuje jen vrchní kartu.\nAby se ti s balíčkem lépe pracovalo, vytvoř následující funkci:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">karty</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Vrátí popis všech karet v balíčku. Jednotlivé karty odděluje mezerami.</span>\n<span class=\"sd\"> """</span>\n</pre></div><p>Nezapomeň využít funkci <code>popis_kartu</code>!</p>\n<p>Například:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">karty</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n<span class=\"go\"> (13, 'Pi', True),</span>\n<span class=\"go\"> (12, 'Sr', True),</span>\n<span class=\"go\"> (11, 'Ka', True),</span>\n<span class=\"go\"> (10, 'Kr', False),</span>\n<span class=\"go\"> ]</span>\n\n<span class=\"gp\">>>> </span><span class=\"n\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">karty</span><span class=\"p\">)</span>\n<span class=\"go\">[A♠ ] [2 ♥] [3 ♦] [???]</span>\n</pre></div><ul>\n<li>level 25: Funkce existuje</li>\n<li>level 26: Funkce správně popisuje balíček</li>\n<li>level 27: Funkce umí popsat i prázdný balíček</li>\n</ul>\n<h2>Rozdání sloupečků</h2>\n<p>Teď zkus rozdat 7 sloupečků karet, tedy konečně první krok hry.</p>\n<p>V <var>N</var>-tém sloupečku (počítáno od nuly) je <var>N</var>\nkaret rubem nahoru plus jedna karta lícem nahoru.\nKarty do sloupečků se z balíčku rozdávají postupně: vždy se lízne\nvrchní (poslední) karta z balíčku a dá se na konec sloupečku.</p>\n<p><span class=\"figure\"><a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/klondike.png\"><img src=\"/2019/brno-podzim-pondeli/projects/klondike/static/klondike.png\" alt=\"Ukázka sloupečků\"></a></span></p>\n<p>Napiš následující funkci:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">rozdej_sloupecky</span><span class=\"p\">(</span><span class=\"n\">balicek</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Rozdá z daného balíčku 7 "sloupečků" -- seznamů karet</span>\n\n<span class=\"sd\"> Karty ve sloupečcích jsou odstraněny z balíčku.</span>\n<span class=\"sd\"> Vrátí všechny sloupečky -- tedy seznam sedmi seznamů.</span>\n<span class=\"sd\"> """</span>\n</pre></div><p>Například:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">balicek</span> <span class=\"o\">=</span> <span class=\"n\">priprav_balicek</span><span class=\"p\">()</span>\n<span class=\"gp\">>>> </span><span class=\"n\">sloupecky</span> <span class=\"o\">=</span> <span class=\"n\">rozdej_sloupecky</span><span class=\"p\">(</span><span class=\"n\">balicek</span><span class=\"p\">)</span>\n<span class=\"go\">24</span>\n<span class=\"gp\">>>> </span><span class=\"n\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">sloupecky</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n<span class=\"go\">[3♣ ]</span>\n<span class=\"gp\">>>> </span><span class=\"n\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">sloupecky</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"go\">[???] [5 ♥]</span>\n<span class=\"gp\">>>> </span><span class=\"n\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">sloupecky</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n<span class=\"go\">[???] [???] [6♣ ]</span>\n<span class=\"gp\">>>> </span><span class=\"n\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">sloupecky</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">])</span>\n<span class=\"go\">[???] [???] [???] [???] [???] [???] [3 ♦]</span>\n<span class=\"gp\">>>> </span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">balicek</span><span class=\"p\">)</span> <span class=\"c1\"># Z balíčku zmizely karty, které jsou ve sloupečcích</span>\n</pre></div><p>Jak tahle funkce funguje?</p>\n<ul>\n<li>Vytvoří prázdný seznam sloupečků</li>\n<li>Sedmkrat (pro <var>N</var> od 0 do 6):<ul>\n<li>Vytvoří prázdný sloupeček (seznam)</li>\n<li><var>N</var>-krát za sebou:<ul>\n<li>„Lízne“ (<code>pop</code>) kartu zvrchu balíčku</li>\n<li>Dá líznutou kartu na vršek sloupečku (<code>append</code>)</li>\n</ul>\n</li>\n<li>„Lízne“ (<code>pop</code>) kartu zvrchu balíčku</li>\n<li>Líznutou kartu otočí lícem nahoru (<code>otoc_kartu</code>)\na dá vršek sloupečku (<code>append</code>)</li>\n<li>Hotový sloupeček přidá do seznamu sloupečků</li>\n</ul>\n</li>\n<li>Výsledné sloupečky vrátí</li>\n</ul>\n<p>Testy:</p>\n<ul>\n<li>level 30: Funkce existuje</li>\n<li>level 31: Funkce vrací seznam sedmi seznamů</li>\n<li>level 32:<ul>\n<li>V každém sloupečku je aspoň jedna karta</li>\n<li>Poslední karta je lícem nahoru</li>\n</ul>\n</li>\n<li>level 33: V každém sloupečku je správný počet karet rubem nahoru</li>\n</ul>\n<h2>Vypsání sloupečků</h2>\n<p>Vzpomínáš si na základní schéma hry?</p>\n<ul>\n<li>Rozdej balíček a sloupečky karet</li>\n<li>Dokud hráč nevyhrál:<ul>\n<li>Zobraz stav hry</li>\n<li>Zeptej se hráče, kam chce hrát</li>\n<li>Je-li to možné:<ul>\n<li>Proveď tah</li>\n</ul>\n</li>\n<li>Jinak:<ul>\n<li>Vynadej hráči, že daný tah nedává smysl</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>Pogratuluj hráči</li>\n</ul>\n<p>Rozdání balíčku a sloupečků už víceméně máš!\nPro teď přeskoč zjišťování, jestli hráč vyhrál, a podívej se na vypsání\nstavu hry.</p>\n<p>Například, pokud jsou sloupečky tyto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">sloupecky</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n <span class=\"p\">[(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s1\">'Pi'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">7</span><span class=\"p\">,</span> <span class=\"s1\">'Sr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)],</span>\n <span class=\"p\">[(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s1\">'Sr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">6</span><span class=\"p\">,</span> <span class=\"s1\">'Ka'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)],</span>\n <span class=\"p\">[(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"s1\">'Ka'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"s1\">'Kr'</span><span class=\"p\">,</span> <span class=\"bp\">False</span><span class=\"p\">)],</span>\n <span class=\"p\">[(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">'Kr'</span><span class=\"p\">,</span> <span class=\"bp\">False</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">'Pi'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)],</span>\n <span class=\"p\">[(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"s1\">'Pi'</span><span class=\"p\">,</span> <span class=\"bp\">False</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"s1\">'Sr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)],</span>\n <span class=\"p\">[(</span><span class=\"mi\">6</span><span class=\"p\">,</span> <span class=\"s1\">'Sr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s1\">'Ka'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)],</span>\n <span class=\"p\">[(</span><span class=\"mi\">7</span><span class=\"p\">,</span> <span class=\"s1\">'Ka'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s1\">'Kr'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"s1\">'Ka'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)],</span>\n<span class=\"p\">]</span>\n</pre></div><p>… můžeš je vypsat jednotlivě:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"k\">for</span> <span class=\"n\">sloupecek</span> <span class=\"ow\">in</span> <span class=\"n\">sloupecky</span><span class=\"p\">:</span>\n<span class=\"gp\">>>> </span> <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">popis_seznam_karet</span><span class=\"p\">(</span><span class=\"n\">sloupecek</span><span class=\"p\">))</span>\n<span class=\"go\">[A♠ ] [7 ♥]</span>\n<span class=\"go\">[2 ♥] [6 ♦]</span>\n<span class=\"go\">[3 ♦] [???]</span>\n<span class=\"go\">[???] [4♠ ]</span>\n<span class=\"go\">[???] [3 ♥]</span>\n<span class=\"go\">[6 ♥] [2 ♦]</span>\n<span class=\"go\">[7 ♦] [A♣ ] [X ♦]</span>\n</pre></div><p>To ale není to, co chceme vypsat ve hře: tam se karty v jednom sloupečku\nukazují pod sebou.</p>\n<p>Budeš potřebovat na prvním řádku ukázat první karty ze všech sloupečků,\nna druhém řádku druhé karty ze všech sloupečků, na třetím třetí, atd.\nPro příklad výše by tedy mělo vyjít:</p>\n<div class=\"highlight\"><pre><code>[A♠ ] [2 ♥] [3 ♦] [???] [???] [6 ♥] [7 ♦]\n[7 ♥] [6 ♦] [???] [4♠ ] [3 ♥] [2 ♦] [A♣ ]\n [X ♦]</code></pre></div><p>Znáš funkci, která vezme několik seznamů, a dá ti k dispozici napřed první\nprvky těch seznamů, potom druhé, a tak dál?\nZkus ji použít!</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">vypis_sloupecky</span><span class=\"p\">(</span><span class=\"n\">sloupecky</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Vypíše sloupečky textově.</span>\n\n<span class=\"sd\"> Tato funkce je jen pro zobrazení, používá proto přímo funkci print()</span>\n<span class=\"sd\"> a nic nevrací.</span>\n<span class=\"sd\"> """</span>\n</pre></div><ul>\n<li>level 40: Funkce existuje</li>\n<li>level 41: Funkce vypisuje karty ze věch sloupečků</li>\n<li>level 42: Funkce funguje, když jsou sloupečky nestejně dlouhé. (Na prázdné místo patří 5 mezer.)</li>\n</ul>\n<h2>Práce se sloupečky</h2>\n<p>Aby sis v budoucnu ušetřila práci, a aby sis procvičila seznamy,\nzkus teď napsat dvě funkce, které přesunují karty mezi balíčky:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">presun_kartu</span><span class=\"p\">(</span><span class=\"n\">sloupec_odkud</span><span class=\"p\">,</span> <span class=\"n\">sloupec_kam</span><span class=\"p\">,</span> <span class=\"n\">pozadovane_otoceni</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Přesune vrchní kartu ze sloupce "odkud" do sloupce "kam".</span>\n<span class=\"sd\"> Karta bude otocena lícem nebo rubem nahoru podle "pozadovane_otoceni".</span>\n<span class=\"sd\"> """</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">presun_nekolik_karet</span><span class=\"p\">(</span><span class=\"n\">sloupec_odkud</span><span class=\"p\">,</span> <span class=\"n\">sloupec_kam</span><span class=\"p\">,</span> <span class=\"n\">pocet</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Přesune "pocet" vrchních karet ze sloupce "odkud" do sloupce "kam".</span>\n<span class=\"sd\"> Karty se přitom neotáčí.</span>\n<span class=\"sd\"> """</span>\n</pre></div><ul>\n<li>level 50: Funkce <code>presun_kartu</code> existuje</li>\n<li>level 51: Funkce <code>presun_kartu</code> funguje dle zadání</li>\n<li>level 60: Funkce <code>presun_nekolik_karet</code> existuje</li>\n<li>level 61: Funkce <code>presun_nekolik_karet</code> funguje dle zadání</li>\n</ul>\n<h2>Hra</h2>\n<p>Vzpomínáš si na schéma hry?</p>\n<ul>\n<li>Rozdej balíček a sloupečky karet</li>\n<li>Dokud hráč nevyhrál:<ul>\n<li>Zobraz stav hry</li>\n<li>Zeptej se hráče, odkud a kam chce hrát</li>\n<li>Je-li to možné:<ul>\n<li>Proveď tah</li>\n</ul>\n</li>\n<li>Jinak:<ul>\n<li>Vynadej hráči, že daný tah nedává smysl</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>Pogratuluj hráči</li>\n</ul>\n<p>V Pythonu to bude vypadat následovně.\nProgram si ulož do modulu <code>hra.py</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">hra</span> <span class=\"o\">=</span> <span class=\"n\">udelej_hru</span><span class=\"p\">()</span>\n\n<span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">hrac_vyhral</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">):</span>\n <span class=\"n\">vypis_hru</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">)</span>\n <span class=\"n\">odkud</span><span class=\"p\">,</span> <span class=\"n\">kam</span> <span class=\"o\">=</span> <span class=\"n\">nacti_tah</span><span class=\"p\">()</span>\n <span class=\"k\">try</span><span class=\"p\">:</span>\n <span class=\"n\">udelej_tah</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">,</span> <span class=\"n\">odkud</span><span class=\"p\">,</span> <span class=\"n\">kam</span><span class=\"p\">)</span>\n <span class=\"k\">except</span> <span class=\"ne\">ValueError</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Něco je špatně:'</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n\n<span class=\"n\">vypis_hru</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Gratuluji!'</span><span class=\"p\">)</span>\n</pre></div><p>K tomu, abys doplnila funkce do této hry, budeš potřebovat namodelovat\nonu <code>hru</code>.\nTa se skládá z několika balíčků/sloupečků, tedy seznamů karet.\nVe výpisu butou pojmenované A-Z:</p>\n<div class=\"highlight\"><pre><code> U V W X Y Z\n [???] [ ] [ ] [ ] [ ] [ ]\n\n A B C D E F G\n [3♣ ] [???] [???] [???] [???] [???] [???]\n [5 ♥] [???] [???] [???] [???] [???]\n [6♣ ] [???] [???] [???] [???]\n [5♠ ] [???] [???] [???]\n [Q ♥] [???] [???]\n [4♠ ] [???]\n [3 ♦]</code></pre></div><ul>\n<li><code>U</code> je dobírací balíček, ze kterého se doplňuje <code>V</code>.</li>\n<li><code>V</code> je balíček, ze kterého můžeš brát karty</li>\n<li><code>W-Z</code> jsou cílové hromádky. Cílem hry je na ně přemístit všechny\nkarty.</li>\n<li><code>A-G</code> jsou sloupečky, kde se karty dají přeskládávat.</li>\n</ul>\n<p>Těchto 13 pojmenovaných seznamů reprezentuje celý stav rozehrané hry.\nHru proto budeme reprezentovat slovníkem, kde klíče budou písmenka\na hodloty pak jednotlivé seznamy.</p>\n<p>Následující funkce takovou hru vytvoří:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">udelej_hru</span><span class=\"p\">():</span>\n <span class=\"sd\">"""Vrátí slovník reprezentující novou hru.</span>\n<span class=\"sd\"> """</span>\n <span class=\"n\">balicek</span> <span class=\"o\">=</span> <span class=\"n\">vytvor_balicek</span><span class=\"p\">()</span>\n\n <span class=\"n\">hra</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n <span class=\"s1\">'U'</span><span class=\"p\">:</span> <span class=\"n\">balicek</span><span class=\"p\">,</span>\n <span class=\"p\">}</span>\n <span class=\"c1\"># V-Z začínají jako prázdné seznamy</span>\n <span class=\"k\">for</span> <span class=\"n\">pismenko</span> <span class=\"ow\">in</span> <span class=\"s1\">'VWXYZ'</span><span class=\"p\">:</span>\n <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"n\">pismenko</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n <span class=\"c1\"># A-G jsou sloupečky</span>\n <span class=\"k\">for</span> <span class=\"n\">pismenko</span><span class=\"p\">,</span> <span class=\"n\">sloupec</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"s1\">'ABCDEFG'</span><span class=\"p\">,</span> <span class=\"n\">rozdej_sloupecky</span><span class=\"p\">(</span><span class=\"n\">balicek</span><span class=\"p\">)):</span>\n <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"n\">pismenko</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">sloupec</span>\n\n <span class=\"k\">return</span> <span class=\"n\">hra</span>\n</pre></div><p>A takhle se hra dá vypsat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">vypis_hru</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Vypíše hru textově.</span>\n\n<span class=\"sd\"> Tato funkce je jen pro zobrazení, používá proto přímo funkci print()</span>\n<span class=\"sd\"> a nic nevrací.</span>\n<span class=\"sd\"> """</span>\n <span class=\"k\">print</span><span class=\"p\">()</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">' U V W X Y Z'</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'{} {} {} {} {} {}'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span>\n <span class=\"n\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'U'</span><span class=\"p\">]),</span>\n <span class=\"n\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'V'</span><span class=\"p\">]),</span>\n <span class=\"n\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'W'</span><span class=\"p\">]),</span>\n <span class=\"n\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'X'</span><span class=\"p\">]),</span>\n <span class=\"n\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'Y'</span><span class=\"p\">]),</span>\n <span class=\"n\">popis_balicku</span><span class=\"p\">(</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'Z'</span><span class=\"p\">]),</span>\n <span class=\"p\">))</span>\n <span class=\"k\">print</span><span class=\"p\">()</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">' A B C D E F G'</span><span class=\"p\">)</span>\n <span class=\"n\">vypis_sloupecky</span><span class=\"p\">([</span><span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'A'</span><span class=\"p\">],</span> <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'B'</span><span class=\"p\">],</span> <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'C'</span><span class=\"p\">],</span> <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'D'</span><span class=\"p\">],</span>\n <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'E'</span><span class=\"p\">],</span> <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'F'</span><span class=\"p\">],</span> <span class=\"n\">hra</span><span class=\"p\">[</span><span class=\"s1\">'G'</span><span class=\"p\">]])</span>\n <span class=\"k\">print</span><span class=\"p\">()</span>\n</pre></div><p>Pro kontrolu můžeš pustit testy:</p>\n<ul>\n<li>Level 70: Funkce <code>udelej_hru</code> existuje</li>\n<li>Level 71: Funkce <code>udelej_hru</code> funguje dle zadání</li>\n<li>Level 80: Funkce <code>vypis_hru</code> existuje</li>\n<li>Level 81: Funkce <code>vypis_hru</code> funguje dle zadání</li>\n</ul>\n<h2>Načtení tahu</h2>\n<p>Hra se bude ovládat zadáním dvou jmen balíčku: odkud a kam hráč chce kartu\npřesunout.</p>\n<p>Tahle funkce není součást logiky hry. Dej ji do <code>hra.py</code>.</p>\n<div class=\"highlight\"><pre><code>def nacti_tah():\n while True:\n tah = input('Tah? ')\n try:\n jmeno_zdroje, jmeno_cile = tah.upper()\n except ValueError:\n print('Tah zadávej jako dvě písmenka, např. UV')\n else:\n return jmeno_zdroje, jmeno_cile</code></pre></div><h2>Zástupné funkce</h2>\n<p>K úplné hře nám chybí ještě samotná logika hry: <code>hrac_vyhral</code> a <code>udelej_tah</code>.</p>\n<p>Aby nám hra aspoň trochu fungovala, vytvoř si zástupné funkce,\nkteré nic nekontrolují a nenechají tě vyhrát:</p>\n<div class=\"highlight\"><pre><code>def hrac_vyhral(hra):\n """Vrací True, pokud je hra vyhraná.\n """\n return False\n\ndef udelej_tah(hra, jmeno_odkud, jmeno_kam):\n presun_kartu(hra[jmeno_odkud], hra[jmeno_kam], True)</code></pre></div><p>Obě bude ještě potřeba upravit, ale teď už si můžeš hru víceméně zahrát!\nZkus si to!</p>\n<h2>Jiné rozhraní</h2>\n<p>Celý tento projekt píšeš ve funkcích s daným jménem a s daným počtem a významem\nargumentů.\nTo má dvě výhody.</p>\n<p>První z nich je testování: připravené testy importují tvé funkce a zkouší je,\ntakže si můžeš být jista, že fungují.</p>\n<p>Druhá je zajímavější: máš-li logiku hry, funkce <code>udelej_hru</code> <code>udelej_tah</code>\na <code>hrac_vyhral</code>, napsané podle specifikací, může je použít i jakýkoli jiný\nprogram – ne jen ten, který jsi napsala ty.</p>\n<p>Jeden takový si můžeš vyzkoušet:</p>\n<ul>\n<li><p>Nainstaluj si do virtuálního prostředí knihovnu <code>pyglet</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(venv)$ </span>python -m pip install pyglet\n</pre></div></li>\n<li><p>Stáhni si do aktuálního adresáře soubory <a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/ui.py\">ui.py</a> a <a href=\"/2019/brno-podzim-pondeli/projects/klondike/static/cards.png\">cards.png</a>.</p>\n</li>\n</ul>\n<ul>\n<li><p>Hru spusť pomocí:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(venv)$ </span>python ui.py\n</pre></div></li>\n</ul>\n<p><em>Obrázky karet jsou z <a href=\"https://kenney.nl/assets/boardgame-pack\">Board Game Pack</a>\nstudia <a href=\"https://kenney.nl\">kenney.nl</a>.</em></p>\n<h2>Logika hry</h2>\n<p>Zbývá doplnit „pravidla hry“ do dvou funkcí, <code>hrac_vyhral</code> a <code>udelej_tah</code>.\nTo už bude na tobě.</p>\n<h3>hrac_vyhral</h3>\n<p>Hráč vyhrál, pokud jsou všechny karty na cílových hromádkách <code>W</code>-<code>Z</code>.</p>\n<h3>udelej_tah</h3>\n<p>Když tah není podle pravidel, funkce <code>udelej_tah</code> vyhodí <code>ValueError</code>.</p>\n<p>Možné tahy:</p>\n<ul>\n<li><code>U</code>→<code>V</code>:<ul>\n<li>V balíčku <code>U</code> musí něco být</li>\n<li>Přesouvá se jedna karta; otočí se lícem nahoru</li>\n</ul>\n</li>\n<li><code>V</code>→<code>U</code>:<ul>\n<li>V balíčku U nesmí být nic</li>\n<li>Přesouvají se všechny karty, seřazené v opačném pořadí;\notočí se rubem nahoru (tj. volej dokola\n<code>presun_kartu(hra['V'], hra['U'], False)</code> dokud ve V něco je)</li>\n</ul>\n</li>\n<li>Balíček <code>V</code> nebo sloupeček <code>A</code>-<code>G</code> (zdroj) → cíl <code>W</code>-<code>Z</code>: <ul>\n<li>Přesouvá se jedna karta</li>\n<li>Je-li cíl prázdný:<ul>\n<li>Musí to být eso</li>\n</ul>\n</li>\n<li>Jinak:<ul>\n<li>Přesouvaná karta musí mít stejnou barvu jako vrchní karta cíle</li>\n<li>Přesouvaná karta musí být o 1 vyšší než vrchní karta cíle</li>\n</ul>\n</li>\n<li>Je-li zdroj po přesunu neprázdný, jeho vrchní karta se otočí lícem nahoru</li>\n</ul>\n</li>\n<li>Balíček <code>V</code> → „cílový“ sloupeček <code>A</code>-<code>G</code><ul>\n<li>Přesouvá se jedna karta</li>\n<li>Přesouvaná karta musí pasovat*⁾ na cílový sloupeček</li>\n</ul>\n</li>\n<li>„Zdrojový“ sloupeček <code>A</code>-<code>G</code> → „cílový“ sloupeček <code>A</code>-<code>G</code><ul>\n<li>Přesouvá se několik karet<ul>\n<li>(zkontroluj všechny možnosti: 1 až počet karet ve zdrojovém sloupečku;\nvždy je max. jedna správná možnost) </li>\n</ul>\n</li>\n<li>Všechny přesouvané karty musí být otočené lícem nahoru</li>\n<li>První z přesouvaných karet musí pasovat*) na cílový sloupeček</li>\n</ul>\n</li>\n<li>Cíl <code>W</code>-<code>Z</code> → sloupeček <code>A</code>-<code>G</code> (nepovinné – jen v některých variantách hry)<ul>\n<li>Přesouvá se jedna karta</li>\n<li>Přesouvaná karta musí pasovat*) na cílový sloupeček</li>\n</ul>\n</li>\n</ul>\n<p>*⁾ Kdy přesouvaná karta pasuje na sloupeček?</p>\n<ul>\n<li>Je-li sloupeček prázdný:<ul>\n<li>Karta musí být král</li>\n</ul>\n</li>\n<li>Jinak:<ul>\n<li>Barva přesouvané karty musí být opačná než barva vrchní karty sloupečku, tedy:<ul>\n<li>Červená (♥ nebo ♦) jde dát jen na černou (♠ nebo ♣)</li>\n<li>Černá (♠ nebo ♣) jde dát jen na červenou (♥ nebo ♦)</li>\n</ul>\n</li>\n<li>Hodnota přesouvané karty musí být o 1 nižší než hodnota vrchní karty sloupečku</li>\n</ul>\n</li>\n</ul>\n\n\n " } } }