← Přehled všech hodin

Slovníky a data hry

Cíl hodiny: Děti přestanou pamatovat si, co je na které pozici v seznamu, a začnou data pojmenovávat. Odcházejí s programem, který má vlastní ceník obchodu a bestiář příšer.
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). Program se přeloží a spustí přímo v prohlížeči a vpravo se objeví to, co vypsal do konzole. Nic se neinstaluje.
Kde jsme a co dnes přibude: Slovník je poslední velká datová struktura, kterou letos potřebuješ. Pak už se jen staví.

1. Vysvětlení a souvislosti

Poznámky pro učiteleJak celou hodinu vést1. Vysvětlení a souvislosti

Tenhle blok je jen pro vás — dětem ho nepromítejte.

Fáze Co se děje Čas
Rozjezd Připomenutí seznamu, ukázka „co je ta trojka?" 10 min
Výklad + ukázky Bloky 2–8, střídáte mluvení a promítání kódu 40 min
Ukázky pro projekci Pět hotových programů, píšete je živě 20 min
Cvičení Děti pracují samy, vy obcházíte 60 min
Závěr Kdo chce, ukáže svůj bestiář 10 min
Hlavní pedagogický cíl

Dnešek není o nové syntaxi, ale o pojmenování dat. Dítě, které pochopí, že prisera["zivoty"] je čitelnější než prisera[1], udělalo první krok k programování ve velkém.

Druhý cíl je oddělit data od kódu. Až budou mít ceník ve slovníku nahoře v souboru, můžou přidat nové zboží bez sahání do zbytku programu. Tuhle myšlenku zopakujte nahlas alespoň třikrát.

Tři věci, které dnes NEVYSVĚTLUJTE
  1. Jak slovník funguje uvnitř (hashování). Stačí „počítač si k jménu dokáže skočit rovnou, nehledá postupně". Detail je v učitelském bloku na konci.
  2. KeyValuePair<TKey,TValue> jako typ. U foreach pište var a řekněte „dvojice klíč-hodnota". Generika se probírají až u tříd.
  3. out parametr u TryGetValue. Berte to jako hotové zaklínadlo: „zkus najít, a když najdeš, dej mi to do téhle proměnné."

Jak pracovat se smíšenou úrovní. Každé cvičení má tři stupně: Minimum, Rozšíření, Výzva. Slabším stačí, když zvládnou jeden slovník a čtení hranatými závorkami. Rychlíky posílejte na TryGetValue a na vnořené struktury — mají v tom hodinu zábavy.

Blok 1Problém, který slovník řeší1. Vysvětlení a souvislosti

Podívej se na ten kód a odpověz: co je ta osmička?

Životy? Síla? Zlato za zabití? Nevíš to. A za týden to nebudeš vědět ani ty, kdo to napsal.

Seznam si pamatuje pořadí. To je skvělé u inventáře, kde má smysl mluvit o „prvním předmětu". Ale u příšery pořadí nic neznamená — tam potřebuješ jména.

A je tu druhý problém: kdyby někdo doprostřed vložil další údaj, posunou se všechny indexy a celý program se rozbije.

Klikni vlevo na Spustit a objeví se tu výstup programu.

Tady se ptát nemusíš. prisera["sila"] je osmička a je to síla. Tečka.

Slovník (Dictionary) je krabice, ve které má každá hodnota jmenovku. Místo čísla pozice použiješ klíč — a ten si vymýšlíš ty.

Analogie, která dětem sedí: seznam je řada čísel dveří, slovník je jmenovka na dveřích. Když se do domu nastěhuje nový soused, jmenovky ostatních zůstanou stejné.

Všimni si, že v hranatých závorkách je text v uvozovkách, ne číslo.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 2Jak se slovník zapisuje1. Vysvětlení a souvislosti

Zápis vypadá děsivě, ale má jen tři části. Čti ho takhle:

Dictionary<string, int>„slovník, kde klíč je text a hodnota je číslo".

  • <string, int> — první typ je klíč (jmenovka), druhý je hodnota. Tady: jméno zboží → cena.
  • = new Dictionary<string, int> — vyrob nový prázdný slovník.
  • **{ ["meč"] = 90, ... } ** — a rovnou do něj nasyp tyhle dvojice. Za poslední dvojicí čárka být může i nemusí.

cenik.Count řekne, kolik dvojic ve slovníku je. Tady tři.

Pozor na jednu věc, která Python nemá: v C# musí mít všechny hodnoty stejný typ. Do Dictionary<string, int> nedáš text. Když potřebuješ i jméno příšery, buď si ho dej do obyčejné proměnné, nebo udělej druhý slovník typu Dictionary<string, string>.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Jak si to pojmenovat nahlas
  • Dictionary = slovník
  • string v prvním okénku = klíč je text
  • int v druhém okénku = hodnota je číslo
  • ["meč"] = hranaté závorky, uvnitř klíč v uvozovkách

Celé to čti: „slovník z textu na číslo, jménem ceník, a v něm meč za devadesát."

Blok 3Čtení, změna, přidání a mazání1. Vysvětlení a souvislosti

Čtyři operace, které dnes potřebuješ:

Zápis Co dělá
prisera["zivoty"] přečte hodnotu pod klíčem
prisera["zivoty"] = 20; změní existující hodnotu
prisera["zlato"] = 25; přidá nový klíč, když ještě není
prisera.Remove("sila"); smaže klíč i s hodnotou

Všimni si zvláštnosti: přidání a změna se píšou úplně stejně. Slovník se nezlobí — když klíč není, vyrobí ho; když je, přepíše ho.

To je velký rozdíl proti seznamu. Tam by inventar[5] = "meč" na neexistujícím indexu program shodilo.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Co se stane, když klíč neexistuje

Čtení je přísnější než zápis. prisera["magie"], když klíč magie neexistuje, program shodí výjimkou KeyNotFoundException. Je to jedna z nejčastějších chyb dnešní hodiny — a v dalším bloku se naučíš, jak se jí vyhnout.

Blok 4Bezpečné čtení: ContainsKey a TryGetValue1. Vysvětlení a souvislosti

ContainsKey je otázka „máš to?" Vrátí true nebo false a program nespadne. Používej ji vždycky, když klíč pochází od uživatele.

Čti to jako větu: „jestli ceník obsahuje klíč zboží, tak…"

Tohle je nejčastější vzor celé hodiny:

Nejdřív se zeptej, jestli klíč existuje. Teprve pak ho čti.

Zkus si přepsat zbozi na "meč" a spustit znovu.

Klikni vlevo na Spustit a objeví se tu výstup programu.

TryGetValue je zkratka, která dělá dvě věci naráz: podívá se, jestli klíč existuje, a když ano, rovnou ti hodnotu podstrčí do proměnné.

  • out int cena„a hodnotu mi dej ven do nové proměnné cena". Proměnnou nemusíš vyrábět dopředu, vznikne tady.
  • Vrací true, když se to povedlo, jinak false.
  • Když se to nepovede, v proměnné je nula (u čísel).

Proč to existuje, když je ContainsKey? Protože ContainsKey + cenik[klíč] hledá ve slovníku dvakrát. TryGetValue jednou. U ceníku o třech položkách je to jedno, u tisíce položek už ne.

Pro dnešek stačí ContainsKey. TryGetValue je Rozšíření pro ty, komu se líbí, že je kratší.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 5Procházení slovníku: foreach, Keys a Values1. Vysvětlení a souvislosti

foreach přes slovník dává dvojice. Každé kolo dostaneš jednu dvojici klíč + hodnota a ptáš se jí na dvě věci:

  • polozka.Key — klíč (tady jméno příšery),
  • polozka.Value — hodnota (tady životy).

Velká písmena u Key a Value jsou povinná. polozka.key nefunguje.

Programátoři té proměnné většinou říkají kvp (z anglického key-value pair). V cizím kódu uvidíš foreach (var kvp in bestiar) — je to úplně totéž, jen jiné jméno krabice.

Pořadí není zaručené. Slovník ti položky vrátí v nějakém pořadí, ale nesmíš na něj spoléhat. Když potřebuješ pořadí, použij seznam.

Klikni vlevo na Spustit a objeví se tu výstup programu.

Někdy tě zajímá jen jedna polovina slovníku:

  • bestiar.Keys — jenom klíče. Hodí se na výpis nabídky.
  • bestiar.Values — jenom hodnoty. Hodí se na sčítání.

Všimni si v druhém foreach vzoru, kterému se říká akumulátor: před cyklem si připravíš proměnnou na nulu a v každém kole do ní přičteš. Po cyklu v ní máš součet.

Tenhle vzor je základ příští hodiny o cyklech — dnes si ho jen vyzkoušej.

A ještě jedna drobnost: bestiar.ContainsValue(120) se ptá na hodnotu místo na klíč. Používá se zřídka, protože musí projít celý slovník.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 6Slovník jako počítadlo1. Vysvětlení a souvislosti

Tohle je nejužitečnější trik se slovníkem vůbec: počítání, kolikrát se něco objevilo.

Postup je pokaždé stejný:

  1. Začni s prázdným slovníkem — new Dictionary<string, int>(), za kterým nejsou složené závorky, jen kulaté.
  2. Pro každou nalezenou věc se zeptej, jestli už v inventáři je.
  3. Když je, přičti jedničku. Když není, založ ji na jedničce.

V CsQuestu to použiješ na inventář: lektvar 3×, mince 12×. Nemusíš mít seznam s dvanácti mincemi za sebou, stačí jedna dvojice.

Zkrácený zápis inventar[vec]++ dělá totéž jako inventar[vec] = inventar[vec] + 1.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 7Dva slovníky vedle sebe1. Vysvětlení a souvislosti

Protože v C# musí mít slovník jeden typ hodnot, popíšeš složitější věc tak, že si uděláš víc slovníků se stejnými klíči.

  • zivoty["Drak"] → číslo 120
  • popisy["Drak"] → text s popisem

Klíč "Drak" je spojka mezi oběma tabulkami. Když si v jednom slovníku napíšeš klíč s překlepem, druhý ho nenajde — a program spadne. Proto si klíče piš malými písmeny a bez diakritiky, jakmile jich bude víc než pět.

Tohle je zatím trochu kostrbaté. V 16. hodině se naučíš třídy a příšeru popíšeš jedním objektem, který má jméno, životy i popis pohromadě. Dnešní slovníky jsou na to poctivá příprava.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Poznámky pro učiteleTechnické pozadí — jen pro vás1. Vysvětlení a souvislosti

Věci, které dětem dnes neříkejte, ale vy je vědět potřebujete.

Proč je slovník rychlý. Dictionary<TKey,TValue> je hashovací tabulka. Z klíče se spočítá číslo (hash), to určí přihrádku, a v ní se hledá. Vyhledání je proto v průměru O(1) — nezávisle na tom, jestli má slovník deset nebo deset milionů položek. Seznam musí procházet postupně, tedy O(n). Dětem to neříkejte dnes; vrátíme se k tomu u algoritmů ve 12. hodině.

Pořadí položek. Dictionary negarantuje pořadí. V praxi to u malých slovníků vypadá jako pořadí vložení, ale spoléhat se na to nesmíte — po smazání klíče se pořadí rozhodí. Když je pořadí potřeba, existuje SortedDictionary<TKey,TValue> (řadí podle klíče). Pro tuhle hodinu to nepotřebujete.

Rozdíl proti Pythonu. Kdo zná Python, narazí na tři věci:

Python C#
{"a": 1} jde míchat typy všechny hodnoty musí mít stejný typ
d.get("x", 0) TryGetValue nebo ContainsKey
for k, v in d.items() foreach (var kvp in d) + .Key / .Value

out parametr. TryGetValue(klíč, out int cena) používá out proměnnou deklarovanou na místě (C# 7+). Proměnná cena platí i za if blokem. Když klíč nenajde, je v ní default(TValue), tedy 0 pro int a null pro string. Dětem stačí „nula".

Klíče a velikost písmen. cenik["Meč"] a cenik["meč"] jsou dva různé klíče. Kdo chce nerozlišovat, vyrobí slovník jako new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase). Nechte si to jako trik do rukávu, až se někdo bude divit.

Inicializátor { ["a"] = 1 } vs. { {"a", 1} }. Obojí je platné. My držíme první tvar, protože vypadá stejně jako pozdější čtení hranatými závorkami, a to dětem pomáhá.

Dictionary a živé spouštění. Všechno z dnešní hodiny běží v prohlížeči bez problémů — slovníky jsou čistá paměť, žádné soubory ani síť.

2. Ukázky pro projekci

Blok 8Ukázka 1 — Karta jedné příšery2. Ukázky pro projekci
Studenti zkuste změnit
  • Přejmenuj příšeru a změň jí čísla.
  • Přidej čtvrtý údaj (třeba obrana) a vypiš ho.
  • Zkus si přečíst klíč, který neexistuje — co program udělá?
  • Změň zivoty na polovinu pomocí prisera["zivoty"] = prisera["zivoty"] / 2;.
demo/demo1_karta_prisery.cs
Tady se objeví výstupKlikni 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.

Co si z toho odnést: hranaté závorky s textem uvnitř. prisera["sila"] se čte jako „síla té příšery" — a nikdo se nemusí ptát, co znamená osmička.

Blok 9Ukázka 2 — Ceník obchodu a nákup2. Ukázky pro projekci
Studenti zkuste změnit
  • Přidej do ceníku další zboží.
  • Změň poptavka na zboží, které v ceníku není. Co se vypíše?
  • Zdraž všechno zboží: cenik["meč"] = cenik["meč"] + 10;.
  • Přidej kontrolu, jestli má hrdina dost zlata.
demo/demo2_cenik.cs
Tady se objeví výstupKlikni 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.

Co si z toho odnést: ContainsKey je pojistka. Nejdřív se zeptej, jestli klíč existuje, teprve pak ho čti hranatými závorkami.

Blok 10Ukázka 3 — Bestiář a jeho procházení2. Ukázky pro projekci
Studenti zkuste změnit
  • Přidej do bestiáře dvě vlastní příšery.
  • Vypiš jen jména pomocí bestiar.Keys.
  • Spočítej průměrné životy: součet děleno bestiar.Count.
  • Zkus najít nejslabší příšeru místo nejsilnější.
demo/demo3_bestiar.cs
Tady se objeví výstupKlikni 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.

Co si z toho odnést: dva vzory, které budeš používat pořád — akumulátor (sčítám do proměnné) a hledání maxima (pamatuju si zatím největší).

Blok 11Ukázka 4 — Inventář jako počítadlo2. Ukázky pro projekci
Studenti zkuste změnit
  • Přidej do nalezy další věci a spusť znovu.
  • Vypiš, kolik má hrdina dohromady kusů všeho.
  • Zkus, co se stane, když nalezy necháš prázdné: { }.
  • Použij inventar[vec]++ místo dlouhého zápisu.
demo/demo4_inventar_pocty.cs
Tady se objeví výstupKlikni 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.

Co si z toho odnést: slovník umí počítat. Vzor „je tam? přičti : není? založ na jedné" potkáš v programování do konce života.

Blok 12Ukázka 5 — Datová vrstva CsQuestu2. Ukázky pro projekci
Studenti zkuste změnit
  • Přidej čtvrté místo a k němu popis i nebezpečí.
  • Změň kde na jiné místo a spusť znovu.
  • Přidej slovník odmeny (místo → zlato) a vypiš ho ve výpisu místa.
  • Zkus zadat místo, které neexistuje — funguje pojistka?
demo/demo5_data_hry.cs
Tady se objeví výstupKlikni 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.

Co si z toho odnést: tři slovníky se stejnými klíči tvoří dohromady data hry. Přidat nové místo znamená dopsat řádek do každého slovníku — a zbytku programu se nedotkneš.

Blok 13Když se něco pokazí2. Ukázky pro projekci
Unhandled exception. System.Collections.Generic.KeyNotFoundException:
The given key 'magie' was not present in the dictionary.

Nejčastější chyba dnešní hodiny. Přečti ji zleva:

  • KeyNotFoundExceptionklíč nenalezen,
  • 'magie' — přesně ten klíč, který jsi chtěl číst,
  • was not present in the dictionary — ve slovníku prostě není.

Příčina bývá jedna ze tří: překlep, velké písmeno ("Magie""magie"), nebo klíč, který se do slovníku ještě nestihl dostat.

Oprava je vždycky stejná: před čtením se zeptej ContainsKey, nebo použij TryGetValue.

Hláška Co to znamená Jak to opravit
KeyNotFoundException klíč ve slovníku není před čtením if (slovnik.ContainsKey(klic))
ArgumentException: An item with the same key has already been added dvakrát stejný klíč v inicializátoru jeden z nich smaž nebo přejmenuj
CS0029: Cannot implicitly convert type 'string' to 'int' dáváš text do Dictionary<string, int> buď oprav hodnotu, nebo udělej slovník <string, string>
CS1061: 'KeyValuePair<...>' does not contain a definition for 'key' malé písmeno musí být .Key a .Value
CS0021: Cannot apply indexing with [] to an expression of type ... indexuješ něco, co není slovník ani seznam zkontroluj jméno proměnné
CS1503: cannot convert from 'int' to 'string' v hranatých závorkách je číslo místo klíče klíč patří do uvozovek: cenik["meč"]
vypíše se jiné pořadí, než čekáš slovník pořadí negarantuje nespoléhej na něj, nebo použij seznam

3. Cvičení

Jak cvičení používat: zadání promítněte. Části Pro učitele a Řešení jsou schované — rozbalí se až kliknutím, takže je můžete mít otevřené a děti je neuvidí, dokud nechcete. Kód ve cvičení i v řešení jde spustit a upravovat přímo tady v prohlížeči.
Blok 14Cvičení 1 — Karta příšery (15 min)3. Cvičení

Tvoje zadání:

Každá příšera v CsQuestu potřebuje kartu. Uděláš ji ze slovníku, aby bylo na první pohled vidět, co které číslo znamená.

  1. Vyrob slovník prisera typu Dictionary<string, int> s klíči "zivoty", "sila" a "zlato".
    💡 Poradit
    Zápis je new Dictionary<string, int> { ["zivoty"] = 30, ... };.
    Klíč patří do uvozovek, hodnota je číslo.
  2. Vypiš kartu — tři řádky ve tvaru Životy: 30.
    💡 Poradit
    Čti hranatými závorkami: prisera["zivoty"].
    Uvnitř $"..." to dej do složených závorek.
  3. Příšera dostala ránu — sniž jí životy o 12 a vypiš nový stav.
    💡 Poradit
    Změna se píše jako přiřazení: prisera["zivoty"] = prisera["zivoty"] - 12;.
  4. Přidej nový klíč "obrana" s hodnotou 4 a vypiš, kolik má karta údajů.
    💡 Poradit
    Přidání vypadá stejně jako změna.
    Počet dvojic zjistíš přes prisera.Count.
  5. Vypiš celou kartu cyklem foreach — každý řádek jako klíč: hodnota.
    💡 Poradit
    foreach (var polozka in prisera) a uvnitř polozka.Key a polozka.Value.
Úroveň Co má zvládnout
Minimum slovník se třemi klíči a výpis hranatými závorkami (kroky 1–2)
Rozšíření změna hodnoty, přidání klíče, Count (kroky 3–4)
Výzva výpis přes foreach a zarovnání sloupců přes PadRight (krok 5)
cviceni/cviceni1_karta_prisery.cs
Tady se objeví výstupKlikni 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.
Pro učitele — na co si dát pozor

Očekávaný výsledek: karta se třemi řádky, po ráně 18 životů, po přidání obrany Count čtyři a nakonec výpis čtyř dvojic pod sebou.

Kde se zaseknou: - Píšou prisera[zivoty] bez uvozovek → CS0103: The name 'zivoty' does not exist. Klíč je text, patří do uvozovek. - Píšou prisera.zivoty. To je syntaxe tříd, ne slovníku. - U kroku 5 napíšou polozka.key malým písmenem → CS1061. - Zapomenou, že jmeno není v tom slovníku — ve výpisu přes foreach se pak diví, že tam jméno není. Je to správně: jmeno je string, do Dictionary<string, int> nepatří.

Kdo je hotový dřív: ať přidá druhou příšeru jako druhý slovník a vypíše obě karty pod sebou. Nebo ať zjistí, kolik zlata příšera nese, když ji porazí dvakrát.

Otázka na závěr: „Proč je prisera["sila"] lepší než prisera[1]?" Odpověď, kterou chcete slyšet: protože je z toho vidět, co to číslo znamená, a nerozbije se to, když přidáme další údaj.

Řešení 1 — jedna z možných variant
reseni/reseni1_karta_prisery.cs
Tady se objeví výstupKlikni 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 15Cvičení 2 — Ceník obchodu (20 min)3. Cvičení

Tvoje zadání:

Obchod U tří seker potřebuje ceník. Hrdina do něj sáhne, koupí si zboží a obchod mu poctivě odečte zlato.

  1. Vyrob slovník cenik se čtyřmi druhy zboží a jejich cenami.
    💡 Poradit
    Klíč je jméno zboží, hodnota je cena.
    ["meč"] = 90, a tak dál.
  2. Vypiš celou nabídku cyklem foreach — jméno vlevo, cena vpravo.
    💡 Poradit
    Zarovnání udělá polozka.Key.PadRight(10).
  3. Zjisti, jestli je zboží z proměnné poptavka v ceníku. Když ne, napiš to.
    💡 Poradit
    Použij if (cenik.ContainsKey(poptavka)) a větev else.
  4. Když zboží existuje a hrdina má dost zlata, odečti cenu a vypiš zůstatek.
    💡 Poradit
    Vnořená podmínka: if (zlato >= cena).
    Pak zlato = zlato - cena;.
  5. Nakonec zdraž všechno zboží o 10 zlaťáků a vypiš nový ceník.
    💡 Poradit
    Procházej foreach (string klic in cenik.Keys.ToList()) a uvnitř cenik[klic] = cenik[klic] + 10;.
    ToList() je tam proto, abys mohl slovník měnit během procházení.
Úroveň Co má zvládnout
Minimum ceník a jeho výpis cyklem (kroky 1–2)
Rozšíření ContainsKey a nákup s kontrolou zlata (kroky 3–4)
Výzva hromadné zdražení přes Keys.ToList() (krok 5)
cviceni/cviceni2_cenik.cs
Tady se objeví výstupKlikni 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.
Pro učitele — na co si dát pozor

Očekávaný výsledek: nabídka čtyř položek, štít za 60, po nákupu zbývá 60 zlata, pak ceník o deset dražší.

Kde se zaseknou: - U kroku 5 zapomenou ToList() a dostanou InvalidOperationException: Collection was modified. Vysvětlení pro děti: „nemůžeš přestavovat regál, zatímco po něm chodíš. ToList() si udělá papírový seznam jmen a podle něj pak měníš." - Zkoušejí foreach (var polozka in cenik) { polozka.Value = ... } — to nejde, Value se měnit nedá. Musí přes klíč. - Zapomenou int cena = cenik[poptavka]; a pak píšou cenik[poptavka] třikrát. Funguje to, ale ukažte jim, že proměnná je čitelnější.

Kdo je hotový dřív: ať přidá druhou položku k nákupu, ať zavede slevu pro zboží dražší než 50, nebo ať najde nejlevnější zboží v ceníku.

Otázka na závěr: „Co by bylo potřeba změnit, kdybychom chtěli přidat páté zboží?" Jediný řádek v ceníku — zbytek programu funguje dál. To je celá myšlenka oddělení dat od kódu.

Řešení 2 — jedna z možných variant
reseni/reseni2_cenik.cs
Tady se objeví výstupKlikni 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 16Cvičení 3 — Bestiář království (20 min)3. Cvičení

Tvoje zadání:

Bestiář je kniha, ve které má každá příšera řádek. Ty ji teď naprogramuješ a spočítáš z ní statistiky.

  1. Vyrob slovník bestiar s pěti příšerami a jejich životy.
    💡 Poradit
    Klíč je jméno příšery, hodnota jsou životy.
    Např. ["Skřet"] = 30,.
  2. Vypiš celý bestiář cyklem foreach se zarovnanými sloupci.
    💡 Poradit
    polozka.Key.PadRight(12) a polozka.Value.ToString().PadLeft(4).
  3. Spočítej součet všech životů a průměr na jednu příšeru.
    💡 Poradit
    Před cyklem int celkem = 0;, uvnitř přičítej.
    Průměr je celkem / bestiar.Count.
  4. Najdi nejsilnější příšeru — tu s nejvíc životy.
    💡 Poradit
    Pamatuj si nejvic a nejsilnejsi.
    Když polozka.Value > nejvic, přepiš obojí.
  5. Přidej druhý slovník odmeny (jméno → zlato) a vypiš spojený přehled.
    💡 Poradit
    Oba slovníky mají stejné klíče.
    V cyklu pak čti odmeny[polozka.Key].
Úroveň Co má zvládnout
Minimum bestiář a jeho výpis cyklem (kroky 1–2)
Rozšíření součet, průměr a hledání maxima (kroky 3–4)
Výzva dva slovníky se společnými klíči (krok 5)
cviceni/cviceni3_bestiar.cs
Tady se objeví výstupKlikni 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.
Pro učitele — na co si dát pozor

Očekávaný výsledek: pět řádků bestiáře, celkem 297 HP, průměr 59, nejsilnější Drak se 120 HP, a nakonec tabulka s odměnami.

Kde se zaseknou: - int nejvic = 0; funguje jen proto, že životy jsou kladné. Zeptejte se rychlíků, co by se stalo, kdyby příšery mohly mít záporné životy. Správná odpověď: začít první položkou, ne nulou. - Průměr vyjde jako celé číslo (59, ne 59,4). To je v pořádku — dělení dvou int v C# zahazuje zbytek. Kdo chce přesně, přepíše na (double)celkem / bestiar.Count. - Ve výpisu s PadLeft zapomenou .ToString(). int sám PadLeft neumí. - V kroku 5 čtou odmeny[polozka.Key] bez pojistky. Funguje to, dokud mají oba slovníky stejné klíče — ať jednu odměnu smažou a uvidí KeyNotFoundException.

Kdo je hotový dřív: ať najde i nejslabší příšeru, ať spočítá poměr „zlato na jeden život", nebo ať vypíše jen příšery nad 40 HP.

Otázka na závěr: „Proč jsou v obou slovnících stejné klíče?" Protože klíč je spojka mezi tabulkami. Kdyby se v jedné psalo "Drak" a v druhé "drak", nenajde se nic.

Řešení 3 — jedna z možných variant
reseni/reseni3_bestiar.cs
Tady se objeví výstupKlikni 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 17Cvičení 4 — Batoh, který umí počítat (20 min)3. Cvičení

Tvoje zadání:

Po výpravě vysypeš batoh na stůl. Program z hromady věcí udělá přehledný seznam: co a kolikrát.

  1. Založ prázdný slovník batoh typu Dictionary<string, int>.
    💡 Poradit
    Prázdný slovník je new Dictionary<string, int>(); — kulaté závorky, žádné složené.
  2. Projdi pole nalezy a spočítej, kolikrát se která věc objevila.
    💡 Poradit
    Když batoh.ContainsKey(vec), přičti jedničku, jinak nastav na 1.
  3. Vypiš batoh — u každé věci počet a pruh ze znaků .
    💡 Poradit
    Pruh vyrobíš přes new string('▪', polozka.Value).
  4. Pomocí TryGetValue zjisti, kolik má hrdina lektvarů.
    💡 Poradit
    if (batoh.TryGetValue("lektvar", out int pocet)) a v else napiš, že žádný nemá.
  5. Vyhoď z batohu všechno, čeho je jen jeden kus, a vypiš, co zbylo.
    💡 Poradit
    Projdi batoh.Keys.ToList() a když batoh[klic] == 1, zavolej batoh.Remove(klic).
Úroveň Co má zvládnout
Minimum prázdný slovník a počítání výskytů (kroky 1–2)
Rozšíření výpis s pruhy a TryGetValue (kroky 3–4)
Výzva bezpečné mazání během procházení (krok 5)
cviceni/cviceni4_batoh.cs
Tady se objeví výstupKlikni 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.
Pro učitele — na co si dát pozor

Očekávaný výsledek: mince 4×, lektvar 3×, pírko 1×, kámen 1×. Po vyhození zbydou dva druhy věcí.

Kde se zaseknou: - Napíšou new Dictionary<string, int> {} se složenými závorkami. Funguje to taky, ale ať si zvyknou na () — u prázdného slovníku je to čitelnější. - U kroku 5 zapomenou ToList()InvalidOperationException. Je to stejná chyba jako ve cvičení 2, tentokrát u mazání. Zopakujte přirovnání s regálem. - TryGetValue je pro ně nové. Zdůrazněte, že out int pocetLektvaru proměnnou vyrábí, nemusí být deklarovaná dopředu. - Někdo zkusí batoh.Remove(polozka.Key) přímo uvnitř foreach (var polozka in batoh). Spadne to okamžitě — dobrá příležitost ukázat, že chybová hláška říká pravdu velmi přesně.

Kdo je hotový dřív: ať spočítá celkový počet kusů (ne druhů), ať najde nejčastější věc, nebo ať batoh vypíše seřazený podle počtu (batoh.OrderByDescending(p => p.Value)).

Otázka na závěr: „Kolik řádků by program měl, kdybychom mince počítali bez slovníku, každou zvlášť?" Slovník tuhle práci schová do tří řádků a funguje i na věci, o kterých jsme dopředu nevěděli.

Řešení 4 — jedna z možných variant
reseni/reseni4_batoh.cs
Tady se objeví výstupKlikni 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 18Cvičení 5 — CsQuest: data hry (25 min)3. Cvičení

Tvoje zadání:

Velké finále hodiny. Postavíš datovou vrstvu CsQuestu: mapu míst, jejich popisy, nebezpečí a počítadlo návštěv. Tohle je kus programu, se kterým budeš pracovat i příští hodiny.

  1. Vyrob slovník popisy typu Dictionary<string, string> se třemi místy.
    💡 Poradit
    Tentokrát je hodnota text: Dictionary<string, string>.
  2. Přidej slovník nebezpeci (stejné klíče, hodnota 1–10) a vypiš mapu s hvězdičkami.
    💡 Poradit
    Hvězdičky: new string('★', polozka.Value).
    Klíče musí být přesně stejné jako v popisy.
  3. Pro místo v proměnné kde vypiš popis a nebezpečí — s pojistkou ContainsKey.
    💡 Poradit
    if (popisy.ContainsKey(kde)) … jinak napiš, že místo na mapě není.
  4. Založ slovník navstiveno a zaznamenej do něj cestu z pole trasa.
    💡 Poradit
    Stejný vzor jako u batohu: je tam? přičti. Není? nastav na 1.
  5. Vypiš deník výpravy a najdi místo, kde byl hrdina nejčastěji.
    💡 Poradit
    Projdi navstiveno a pamatuj si maximum — stejně jako u nejsilnější příšery.
Úroveň Co má zvládnout
Minimum slovník popisů a výpis mapy (kroky 1–2)
Rozšíření bezpečné čtení aktuálního místa (krok 3)
Výzva počítadlo návštěv a hledání maxima (kroky 4–5)
cviceni/cviceni5_data_hry.cs
Tady se objeví výstupKlikni 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.
Pro učitele — na co si dát pozor

Očekávaný výsledek: mapa se třemi řádky hvězdiček, popis dolu, deník les 3×, dul 2×, vez 1× a hláška, že nejraději chodí do lesa.

Kde se zaseknou: - Míchají diakritiku: v popisy mají klíč "důl", v nebezpeci "dul". Pak nebezpeci[kde] spadne. Proto v zadání záměrně používáme klíče bez diakritiky — je to praktické pravidlo, ne náhoda. - Zapomenou, že popisy je Dictionary<string, string>, a zkusí do něj dát číslo → CS0029. - U hledání maxima dají výpis a porovnání do dvou samostatných cyklů. Funguje to; ukažte, že jeden cyklus zvládne obojí. - trasa.Length versus popisy.Count — pole má Length, slovník Count. Dobré místo si to připomenout.

Kdo je hotový dřív: - přidat čtvrté místo (musí dopsat do obou slovníků), - spočítat celkové „nastřádané nebezpečí" trasy (za každý krok přičti nebezpeci[misto]), - vypsat místa, kde hrdina ještě nebyl (projít popisy.Keys a testovat navstiveno.ContainsKey).

Otázka na závěr: „Kolik slovníků by hra potřebovala, kdyby mělo každé místo i odměnu, obrázek a seznam příšer?" Odpověď: čtyři, pět, šest… a právě proto se v 16. hodině naučíme třídy, kde bude jedno místo jedním objektem.

Řešení 5 — jedna z možných variant
reseni/reseni5_data_hry.cs
Tady se objeví výstupKlikni 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 19Domácí úkol na příští hodinu4. Domácí úkol

Rozšiř svůj Program.cs o datovou vrstvu CsQuestu:

  • slovník cenik s alespoň pěti druhy zboží a cenami,
  • slovník bestiar s alespoň čtyřmi příšerami a jejich životy,
  • druhý slovník odmeny se stejnými klíči jako bestiář,
  • výpis obou tabulek cyklem foreach se zarovnanými sloupci,
  • a nákup, který se zeptá uživatele na zboží, ověří ho přes ContainsKey a odečte zlato.

Ulož snímek obrazovky (nebo soubor Program.cs) a přines na příští hodinu.

Pro učitele

Úkol je schválně otevřený. Cílem je, aby si dítě doma znovu otevřelo editor a samo si vymyslelo obsah tabulek — ceník i bestiář jsou vděčné téma, protože si do nich každý dá to svoje.

Na začátku příští hodiny promítněte dva tři odevzdané bestiáře. Ptejte se na obsah, ne na syntaxi. Kdo úkol nemá, nic se neděje — 9. hodina o cyklech navazuje na foreach, který se dnes dělal na hodině.

Nejčastější problém v odevzdaných úkolech bude čtení neexistujícího klíče. Mějte hlášku KeyNotFoundException připravenou na plátně, ať ji poznají.

Kdo nemá doma .NET, udělá úkol přímo tady v prohlížeči a pošle zkopírovaný text.

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.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Program čte z konzole. Co sem napíšeš, to „odpoví" na každé Console.ReadLine() — jeden řádek na jedno čtení.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 20Oficiální dokumentace4. Domácí úkol

Oficiální dokumentace je místo, kam se programátoři chodí podívat, když si chtějí něco ověřit nebo zjistit víc detailů. Je většinou v angličtině, ale to nevadí — zkus se orientovat podle názvu příkazu a podle ukázek kódu.

Co jsme použili Oficiální dokumentace Co tam najdeš
Dictionary<TKey,TValue> Dictionary celý slovník se všemi metodami
slovnik[klíč] Indexer Item[] čtení a zápis hranatými závorkami
ContainsKey ContainsKey ověření, jestli klíč existuje
TryGetValue TryGetValue bezpečné čtení jedním krokem
Remove Remove smazání klíče i s hodnotou
Count Count počet dvojic ve slovníku
Keys / Values Keys procházení jen klíčů nebo jen hodnot
KeyValuePair KeyValuePair dvojice, kterou dává foreach
foreach Příkaz foreach procházení kolekcí
out Modifikátor out jak funguje out int cena
KeyNotFoundException KeyNotFoundException výjimka při čtení neexistujícího klíče
Inicializátory kolekcí Object and Collection Initializers zápis { ["a"] = 1 }
Jak s dokumentací pracovat na hodině

Stránka Dictionary<TKey,TValue> je na první pohled děsivá — je v ní přes třicet metod. Ukažte dětem, že se dá prohledat prohlížečem (Ctrl+F) a že v praxi potřebují čtyři: indexer, ContainsKey, Count a Remove.

Ve VS Code funguje i doplňování: napsat cenik. a podívat se, co nabídne, je rychlejší než hledat v dokumentaci. Naučte je to.

5. Umíme informatiku

Blok 21Navazující cvičení na Umíme informatiku5. Umíme informatiku

Pro rychlejší studenty, kteří dokončí cvičení dřív, nebo na posledních 10–15 minut.

Cvičení Odkaz Proč se hodí
Programování — seznamy a data umimeinformatiku.cz Práce s kolekcemi a čtení kódu, který data prochází
Proměnné a výrazy umimeinformatiku.cz Co je v krabici po několika přiřazeních — u slovníku totéž, jen s klíčem
Šifry a kódování umimeinformatiku.cz Substituční šifra je doslova slovník: znak → znak

Šifry jsou tu obzvlášť vhodné, protože substituční šifra je přesně to, co jsme dnes dělali — tabulka, kde se z jednoho klíče čte jedna hodnota. Dětem to většinou docvakne až tady.

Jak to zařadit

Nedávejte to celé třídě naráz. Použijte to jako záložní aktivitu pro tři až pět nejrychlejších dětí, aby nerušily ostatní. Mějte odkaz připravený v záložkách prohlížeče.

Dobrá alternativa pro rychlíky přímo v kódu: ať si udělají slovník Dictionary<char, char> jako jednoduchou šifru a zkusí zašifrovat své jméno. Zabaví je to na deset minut a spojí to dnešní hodinu s minulou o řetězcích.