← Přehled všech hodin

Slovníky a data hry

Cíl hodiny: Naučíš se ukládat pojmenovaná data a chápat rozdíl mezi seznamem (pořadí) a slovníkem (jméno).
Jak stránku používat: vpravo nahoře je tlačítko Prezentace — schová všechno kromě jednoho bloku a přepíná se šipkami. U ukázek a cvičení je kód vlevo editovatelný: uprav ho a klikni na Spustit (nebo Ctrl+Enter), výsledek se objeví vpravo. Běží to přímo v prohlížeči, bez instalace.

1. Pochopení tématu

Blok 1Problém, který slovník řeší1. Pochopení tématu

Nejdřív se podívej na slabinu seznamu:

Co je to třicítka? Životy? Síla? Zlato? Musíš si pamatovat pořadí. A když někdo mezi to vloží další údaj, celý program se rozbije.

Seznam si pamatuje pořadí. Slovník si pamatuje jména. Ve slovníku je jedno, v jakém pořadí to napíšeš.

Analogie: seznam je řada čísel dveří, slovník je jmenovka na dveřích.

Blok 2Základní práce se slovníkem1. Pochopení tématu

Zásadní rozdíl proti seznamu: u slovníku vytvoří přiřazení nový klíč, u seznamu by seznam[5] = x na neexistujícím indexu spadlo.

Blok 3Bezpečné čtení pomocí get1. Pochopení tématu
prisera["sila"]              # KeyError, když klíč neexistuje!
prisera.get("sila")          # None, nespadne
prisera.get("sila", 5)       # 5 - výchozí hodnota

get je opatrná varianta. Když klíč není, nespadne, ale vrátí náhradní hodnotu. Používej ji všude, kde si nejsi jistý, že klíč existuje.

Tohle je nejužitečnější věc z celé hodiny.

Blok 4Procházení slovníku1. Pochopení tématu

items() ti dá obojí najednou. To je nejpohodlnější způsob, jak slovník projít. Zápis se dvěma proměnnými po for znamená „rozbal mi tu dvojici".

Blok 5Slovník jako číselník1. Pochopení tématu

Velmi častý a užitečný vzor — nahrazuje dlouhé if/elif:

# Místo tohohle:
if misto == "Les":
    nebezpeci = 20
elif misto == "Jeskyně":
    nebezpeci = 45
elif misto == "Věž":
    nebezpeci = 70

# Napiš tohle:
NEBEZPECI = {"Les": 20, "Jeskyně": 45, "Věž": 70}
nebezpeci = NEBEZPECI[misto]

Když máš spoustu podmínek, které jen přiřazují hodnotu, nahraď je slovníkem. Je to kratší, přehlednější a přidání dalšího místa je jeden řádek.

Navíc klíče slovníku jdou rovnou do selectbox.

Blok 6Seznam slovníků — nejdůležitější struktura1. Pochopení tématu

Tohle je základ všech skutečných dat.

Seznam drží víc příšer, každý slovník popisuje jednu. Tak vypadají data v každé opravdové hře i aplikaci.

Pozor na uvozovky uvnitř f-stringu: f"{p['jmeno']}" — uvnitř dvojitých použij jednoduché.

Blok 7Vnořený slovník1. Pochopení tématu

Čte se to zleva doprava jako cesta: nejdřív „hrdina", pak z něj „životy".

Blok 8Streamlit a slovníky1. Pochopení tématu

st.dataframe(seznam_slovniku) udělá hotovou tabulku — výsledek uvidíš okamžitě.

Poznámky pro učiteleTechnické pozadí pro učitele1. Pochopení tématu
  • dict je hashovací tabulka, vyhledání podle klíče je O(1) bez ohledu na velikost. Analogie v C#: Dictionary<string, object>.
  • Od Pythonu 3.7 si slovník zachovává pořadí vložení. Nespoléhat na to logicky, ale zobrazování je díky tomu předvídatelné.
  • Klíč musí být neměnný (str, int, tuple). Seznam jako klíč být nemůže.
  • dict je mutovatelný a předává se odkazem — stejná past jako u seznamů. Kopie: d.copy() (mělká) nebo copy.deepcopy(d) (hluboká, u vnořených dat nutná).
  • Seznam slovníků je přesně formát JSON, což využijeme v hodině 14.
Blok 9Časté chyby1. Pochopení tématu
Chyba Příčina Řešení
KeyError: 'sila' Klíč neexistuje .get("sila", 0)
TypeError: unhashable type: 'list' Seznam jako klíč Použít text nebo tuple
SyntaxError v f-stringu Stejné uvozovky f"{p['jmeno']}"
Změna se projeví i jinde Slovník je odkaz .copy()
dict místo list v selectboxu Chybí list() list(d.keys())
Zapomenutá dvojtečka {"a" 1} {"a": 1}

2. Ukázky pro projekci

Ukázka 1 — Seznam versus slovník

demo/demo1_seznam_vs_slovnik.py
import streamlit as st

st.title("Seznam vs. slovník")

levy, pravy = st.columns(2)

with levy:
    st.subheader("📋 Seznam")
    prisera_l = ["Skřet", 30, 8, 25]
    st.code(str(prisera_l))
    st.write("Co je co?")
    st.code(
        "prisera[0]  ->  'Skřet'\n"
        "prisera[1]  ->  30      ??\n"
        "prisera[2]  ->  8       ??\n"
        "prisera[3]  ->  25      ??"
    )
    st.error("Musíš si pamatovat pořadí.")

with pravy:
    st.subheader("🗂️ Slovník")
    prisera_s = {"jmeno": "Skřet", "zivoty": 30, "sila": 8, "zlato": 25}
    st.json(prisera_s)
    st.code(
        "prisera['jmeno']  ->  'Skřet'\n"
        "prisera['zivoty'] ->  30\n"
        "prisera['sila']   ->  8\n"
        "prisera['zlato']  ->  25"
    )
    st.success("Klíč ti řekne, co to je.")

st.divider()

st.subheader("Vyzkoušej klíč")
klic = st.selectbox("Který klíč přečteme?", list(prisera_s.keys()))
st.code(f"prisera['{klic}']  ->  {prisera_s[klic]!r}")

st.divider()
st.subheader("Bezpečné čtení pomocí get()")
neexistujici = st.text_input("Zkus napsat klíč, který neexistuje", "obrana")
st.code(
    f"prisera['{neexistujici}']            ->  KeyError 💥\n"
    f"prisera.get('{neexistujici}')        ->  {prisera_s.get(neexistujici)}\n"
    f"prisera.get('{neexistujici}', 0)     ->  {prisera_s.get(neexistujici, 0)}"
)

Ukázka 2 — Bestiář ze seznamu slovníků

demo/demo2_bestiar.py
import streamlit as st

st.set_page_config(page_title="Bestiář", page_icon="👹")
st.title("👹 Bestiář")

PRISERY = [
    {"jmeno": "Skřet",   "zivoty": 30,  "sila": 8,  "zlato": 25,  "emoji": "👺"},
    {"jmeno": "Vlk",     "zivoty": 20,  "sila": 12, "zlato": 15,  "emoji": "🐺"},
    {"jmeno": "Kostlivec","zivoty": 40, "sila": 10, "zlato": 40,  "emoji": "💀"},
    {"jmeno": "Trol",    "zivoty": 80,  "sila": 18, "zlato": 90,  "emoji": "🧌"},
    {"jmeno": "Drak",    "zivoty": 200, "sila": 40, "zlato": 500, "emoji": "🐉"},
]

st.subheader("Celá tabulka jedním příkazem")
st.dataframe(PRISERY, use_container_width=True)
st.caption("st.dataframe(PRISERY) - Streamlit si tabulku poskládá sám.")

st.divider()

jmena = []
for p in PRISERY:
    jmena.append(p["jmeno"])

vybrane = st.selectbox("Kterou příšeru prozkoumáš?", jmena)

# najdeme slovník podle jména
nalezena = None
for p in PRISERY:
    if p["jmeno"] == vybrane:
        nalezena = p

if nalezena:
    st.header(f"{nalezena['emoji']} {nalezena['jmeno']}")

    a, b, c = st.columns(3)
    a.metric("❤️ Životy", nalezena["zivoty"])
    b.metric("💪 Síla", nalezena["sila"])
    c.metric("💰 Zlato", nalezena["zlato"])

    st.progress(min(nalezena["sila"] / 40, 1.0))
    st.json(nalezena)

Ukázka 3 — Slovník místo dlouhých podmínek

demo/demo3_ciselnik.py
import streamlit as st

st.title("Slovník nahradí if/elif")

MISTA = {
    "Les":     {"nebezpeci": 20, "odmena": 30,  "emoji": "🌲", "korist": "lano"},
    "Jeskyně": {"nebezpeci": 45, "odmena": 80,  "emoji": "🕳️", "korist": "klíč"},
    "Věž":     {"nebezpeci": 70, "odmena": 200, "emoji": "🏰", "korist": "prsten"},
    "Bažina":  {"nebezpeci": 55, "odmena": 120, "emoji": "🐊", "korist": "amulet"},
}

st.code(
    "# Místo 8 řádků if/elif stačí:\n"
    "data = MISTA[misto]\n"
    "nebezpeci = data['nebezpeci']"
)

st.divider()

misto = st.selectbox("Kam půjdeš?", list(MISTA.keys()))
data = MISTA[misto]

st.header(f"{data['emoji']} {misto}")

a, b, c = st.columns(3)
a.metric("⚠️ Nebezpečí", data["nebezpeci"])
b.metric("💎 Odměna", data["odmena"])
c.metric("🎁 Kořist", data["korist"])

st.divider()

st.subheader("Všechna místa najednou")
for nazev, info in MISTA.items():
    st.write(
        f"{info['emoji']} **{nazev}** — nebezpečí {info['nebezpeci']}, "
        f"odměna {info['odmena']} zlata, kořist: {info['korist']}"
    )

3. Cvičení na hodinu

Blok 10Cvičení 1 — Karta příšery (15 min)3. Cvičení na hodinu

Tvoje zadání:

  1. Vytvoř slovník prisera s klíči jmeno, zivoty, sila, zlato a emoji
  2. Vypiš každý údaj zvlášť pomocí f-stringu
  3. Zobraz životy a sílu pomocí st.metric ve sloupcích
  4. Přidej st.selectbox s klíči slovníku a vypiš vybranou hodnotu
  5. Ukaž rozdíl mezi prisera["neco"] a prisera.get("neco", "nemá")
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4 s list(prisera.keys())
Výzva Bod 5 + procházení přes .items() a výpis celé karty cyklem
cviceni/cviceni1_karta.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Tip — na co si dát pozor

Očekávaný výsledek: karta příšery se všemi údaji.

Řešení 1 — jedna z možných variant
reseni/reseni1_karta.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 11Cvičení 2 — Ceník obchodu (20 min)3. Cvičení na hodinu

Tvoje zadání:

  1. Vytvoř slovník CENY s aspoň šesti předměty a jejich cenami
  2. Přidej st.selectbox s klíči a zobraz cenu vybraného předmětu
  3. Přidej st.number_input na počet kusů a spočítej celkovou cenu
  4. Vypiš celý ceník cyklem přes .items() zarovnaný f-stringem
  5. Přidej slevu 10 % při nákupu tří a více kusů
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + najít nejdražší předmět pomocí max(CENY, key=CENY.get)
cviceni/cviceni2_cenik.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Tip — na co si dát pozor

Očekávaný výsledek: funkční ceník s výpočtem ceny nákupu.

Řešení 2 — jedna z možných variant
reseni/reseni2_cenik.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 12Cvičení 3 — Vlastní bestiář (20 min)3. Cvičení na hodinu

Tvoje zadání:

  1. Vytvoř seznam aspoň čtyř slovníků popisujících příšery
  2. Zobraz je jako tabulku pomocí st.dataframe
  3. Přidej st.slider na maximální sílu a vypiš jen příšery slabší než limit
  4. Spočítej, kolik příšer prošlo filtrem a jaké je jejich celkové zlato
  5. Přidej formulář na přidání vlastní příšery do session_state
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4 s cyklem a podmínkou
Výzva Bod 5 s st.form
cviceni/cviceni3_bestiar.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Tip — na co si dát pozor

Očekávaný výsledek: filtrovatelný bestiář, který se dá rozšiřovat.

Řešení 3 — jedna z možných variant
reseni/reseni3_bestiar.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 13Cvičení 4 — Hrdina jako slovník (20 min)3. Cvičení na hodinu

Tvoje zadání:

  1. Nahraď jednotlivé proměnné hrdiny jedním slovníkem v session_state
  2. Klíče: jmeno, zivoty, zlato, uroven, zkusenosti
  3. Přidej tlačítko „Získat zkušenosti (+25)"
  4. Když zkušenosti přesáhnou 100, zvyš úroveň a odečti 100
  5. Vypiš celého hrdinu pomocí st.json a .items()
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4 s postupem na vyšší úroveň
Výzva Bod 5 + přidat maximum životů rostoucí s úrovní
cviceni/cviceni4_hrdina_slovnik.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Tip — na co si dát pozor

Očekávaný výsledek: hrdina, který se vyvíjí a jehož data jsou na jednom místě.

Řešení 4 — jedna z možných variant
reseni/reseni4_hrdina_slovnik.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 14Cvičení 5 — PyQuest: data hry (25 min)3. Cvičení na hodinu

Tvoje zadání:

  1. Přesuň všechna místa do slovníku MISTA (nebezpeci, odmena, korist, emoji, popis)
  2. Odstraň dlouhé if/elif a nahraď je čtením ze slovníku
  3. Přesuň hrdinu do jednoho slovníku st.session_state.hrdina
  4. Přidej PREDMETY se slovníkem cen a použij ho v obchodu
  5. Zobraz přehled všech míst tabulkou pomocí st.dataframe
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 + přidat páté místo bez úpravy zbytku kódu
cviceni/cviceni5_pyquest_data.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Tip — na co si dát pozor

Očekávaný výsledek: přidání nového místa je jeden řádek ve slovníku.

Řešení 5 — jedna z možných variant
reseni/reseni5_pyquest_data.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

4. Domácí úkol

Blok 15Domácí úkol na příští hodinu4. Domácí úkol

Vytvoř slovník KOUZLA, kde klíč je název kouzla a hodnota je slovník s manou, poškozením a popisem. Přidej do hry možnost seslat kouzlo, které stojí manu a udělá poškození. Nové kouzlo musí jít přidat jedním řádkem ve slovníku.

Zobrazit ukázkové řešení domácího úkolu

Toto je jedna z možných variant, jak mohl úkol dopadnout. Tvoje řešení se může lišit a to je v pořádku.

domaci/domaci_ukol08.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 16Oficiální dokumentace4. Domácí úkol

Oficiální dokumentace je užitečná ve chvíli, kdy si chceš ověřit, jak se slovníky čtou, mění nebo bezpečně procházejí. Je v angličtině, ale stačí sledovat názvy metod, příklady a krátké ukázky použití.

Co jsme použili Oficiální dokumentace Co tam najdeš
dict dict co je slovník, jak fungují klíče a hodnoty
dict.get() dict.get bezpečné čtení hodnoty i s výchozí hodnotou
dict.keys() dict.keys získání všech klíčů slovníku
dict.values() dict.values získání všech hodnot slovníku
dict.items() dict.items procházení dvojic klíč–hodnota
del The del statement mazání položek podle klíče
in u slovníků Membership test operations ověření, jestli klíč ve slovníku existuje
st.json st.json hezký výpis slovníku nebo JSON dat
st.dataframe st.dataframe tabulku ze seznamu slovníků
st.selectbox st.selectbox výběr položky ze seznamu klíčů nebo názvů

5. Umíme informatiku

Blok 17Navazující cvičení na Umíme informatiku5. Umíme informatiku
Cvičení Odkaz Proč se hodí
Tabulky umimeinformatiku.cz Data jako záznamy a sloupce
Kódování a modelování umimeinformatiku.cz Reprezentace informací
Programování v Pythonu umimeinformatiku.cz Datové struktury
Algoritmické myšlení umimeinformatiku.cz Vyhledávání v datech