From a00d00070e470057c68d8593a401c904123359ad Mon Sep 17 00:00:00 2001 From: Priec Date: Fri, 6 Mar 2026 01:36:58 +0100 Subject: [PATCH] rng a io --- priprava/rust_priprava14.md | 749 ++++++++++++++++++++++++++++++++++++ 1 file changed, 749 insertions(+) create mode 100644 priprava/rust_priprava14.md diff --git a/priprava/rust_priprava14.md b/priprava/rust_priprava14.md new file mode 100644 index 0000000..f666cb9 --- /dev/null +++ b/priprava/rust_priprava14.md @@ -0,0 +1,749 @@ +# rand — krok za krokom + +Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej. + +`Cargo.toml`: +```toml +[dependencies] +rand = "0.8" +``` + +```rust +use rand::Rng; // toto treba skoro vždy +``` + +--- + +## Kapitola 1: Generátor náhodných čísel — thread_rng + +Všetko začína generátorom. V Ruste sa volá `thread_rng()`: + +```rust +use rand::Rng; + +fn main() { + // Vytvor generátor + let mut rng = rand::thread_rng(); + + // Náhodné i32 (celý rozsah) + let cislo: i32 = rng.gen(); + println!("{}", cislo); // napr. -1847294628 + + // Náhodné f64 medzi 0.0 a 1.0 + let desatinne: f64 = rng.gen(); + println!("{}", desatinne); // napr. 0.7382... + + // Náhodné bool + let minca: bool = rng.gen(); + println!("{}", minca); // true alebo false +} +``` + +**`mut rng`** — generátor sa mení pri každom volaní (posúva sa jeho vnútorný stav), preto musí byť `mut`. + +### Úlohy 1 + +**1a.** Vygeneruj 5 náhodných i32 čísel. Vypíš ich. + +**1b.** Vygeneruj 10 náhodných bool hodnôt. Spočítaj koľko bolo true a koľko false. + +**1c.** Čo je zle? +```rust +let rng = rand::thread_rng(); +let cislo: i32 = rng.gen(); +``` + +--- + +## Kapitola 2: gen_range — číslo v rozsahu + +```rust +use rand::Rng; + +let mut rng = rand::thread_rng(); + +// Celé číslo od 1 do 10 (vrátane oboch) +let cislo: i32 = rng.gen_range(1..=10); + +// Celé číslo od 1 do 9 (10 NIE JE zahrnuté) +let cislo: i32 = rng.gen_range(1..10); + +// Float od 0.0 do 1.0 (1.0 nie je zahrnuté) +let cislo: f64 = rng.gen_range(0.0..1.0); + +// Index do vektora +let vektor = vec!["a", "b", "c", "d", "e"]; +let index: usize = rng.gen_range(0..vektor.len()); +let nahodny_prvok = &vektor[index]; +``` + +**`..=`** — inclusive (vrátane konca). `..` — exclusive (bez konca). + +| Zápis | Rozsah | Príklad | +|-------|--------|---------| +| `1..10` | 1 až 9 | kocka bez 10 | +| `1..=10` | 1 až 10 | kocka s 10 | +| `0..vektor.len()` | 0 až posledný index | náhodný index | + +### Úlohy 2 + +**2a.** Simuluj hod kockou (1–6). Hoď 100-krát a spočítaj koľkokrát padlo každé číslo (použi HashMap). + +**2b.** Vygeneruj náhodné heslo — 8 náhodných znakov z abecedy a-z. Hint: vygeneruj číslo 0..26, pripočítaj k `b'a'`, preveď na char. + +**2c.** Napíš funkciu `nahodne_cislo_v_rozsahu(od: i32, do_: i32) -> i32`. Použi `gen_range`. + +--- + +## Kapitola 3: choose — náhodný výber z kolekcie + +Toto je **najdôležitejšie** na skúške. `choose` vyberie náhodný prvok z vektora alebo slice. + +```rust +use rand::seq::SliceRandom; // TOTO TREBA IMPORTOVAŤ! + +let mut rng = rand::thread_rng(); + +let ovocie = vec!["jablko", "hruška", "banán", "pomaranč"]; + +// choose — vráti Option<&&str> (Option lebo Vec môže byť prázdny) +let nahodne = ovocie.choose(&mut rng); +// Some(&"hruška") — náhodný prvok + +match nahodne { + Some(o) => println!("Vybrané: {}", o), + None => println!("Prázdny zoznam"), +} +``` + +**Import:** `use rand::seq::SliceRandom;` — bez tohto `choose` nefunguje! + +### choose s Vec + +```rust +use rand::seq::SliceRandom; + +let slova = vec!["pes".to_string(), "mačka".to_string(), "kôň".to_string()]; +let mut rng = rand::thread_rng(); + +let nahodne: Option<&String> = slova.choose(&mut rng); +// Some(&"mačka") +``` + +### choose s Vec + +```rust +struct Otazka { + text: String, + odpoved: String, +} + +let otazky = vec![ + Otazka { text: "2+2?".into(), odpoved: "4".into() }, + Otazka { text: "Hlavné mesto SR?".into(), odpoved: "Bratislava".into() }, +]; + +let nahodna: Option<&Otazka> = otazky.choose(&mut rng); +if let Some(otazka) = nahodna { + println!("{}", otazka.text); +} +``` + +### choose na skúške — SpravcaHry.vytvor_novu_hru + +```rust +use rand::seq::SliceRandom; +use std::collections::HashMap; + +struct SpravcaHry { + slovnik: HashMap>, +} + +impl SpravcaHry { + fn vytvor_novu_hru(&self, kategoria: &str) -> Option { + // 1. Nájdi kategóriu v slovníku + let slova = self.slovnik.get(kategoria)?; + + // 2. Skontroluj či nie je prázdna + if slova.is_empty() { + return None; + } + + // 3. Vyber náhodné slovo + let mut rng = rand::thread_rng(); + let slovo = slova.choose(&mut rng)?; + + // 4. Vytvor hru s tým slovom + Some(Hra::new(slovo)) + } +} +``` + +Krok po kroku: +``` +slovnik = {"zvierata": ["pes", "mačka", "kôň"], "jedlo": ["pizza", "burger"]} + +kategoria = "zvierata" + → slovnik.get("zvierata") → Some(&["pes", "mačka", "kôň"]) + → slova = &["pes", "mačka", "kôň"] + → slova.choose(&mut rng) → Some(&"mačka") + → Hra::new("mačka") + → Some(Hra { hladane_slovo: "mačka", ... }) + +kategoria = "neexistuje" + → slovnik.get("neexistuje") → None + → ? vráti None z funkcie +``` + +### Úlohy 3 + +**3a.** Máš Vec mien. Vyber náhodné meno a vypíš ho. + +**3b.** Máš HashMap> (kategória → slová). Napíš funkciu: +```rust +fn nahodne_slovo(slovnik: &HashMap>, kategoria: &str) -> Option<&String> +``` + +**3c.** Máš Vec. Vyber 5 náhodných otázok (bez opakovania). Hint: pozri kapitolu 5 (shuffle). + +**3d.** Čo sa stane ak zavoláš `.choose()` na prázdnom vektore? + +--- + +## Kapitola 4: choose_multiple — viac náhodných prvkov + +```rust +use rand::seq::SliceRandom; + +let cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +let mut rng = rand::thread_rng(); + +// Vyber 3 náhodné prvky (BEZ opakovania) +let vybrane: Vec<&i32> = cisla.choose_multiple(&mut rng, 3).collect(); +// napr. [&7, &2, &9] + +// Ak chceš viac ako je prvkov, vráti všetky (v náhodnom poradí) +let vsetky: Vec<&i32> = cisla.choose_multiple(&mut rng, 100).collect(); +// všetkých 10 prvkov v náhodnom poradí +``` + +### Na skúške — výber N otázok + +```rust +struct Kviz { + otazky: Vec, +} + +impl Kviz { + fn nahodnych_n(&self, n: usize) -> Vec<&Otazka> { + let mut rng = rand::thread_rng(); + self.otazky.choose_multiple(&mut rng, n).collect() + } +} +``` + +### Úlohy 4 + +**4a.** Máš 20 študentov. Vyber 5 náhodných na skúšanie. + +**4b.** Máš balíček kariet (Vec). Rozdaj 7 kariet — vyber 7 náhodných. + +--- + +## Kapitola 5: shuffle — zamiešanie + +```rust +use rand::seq::SliceRandom; + +let mut cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +let mut rng = rand::thread_rng(); + +// shuffle — zamieša NA MIESTE (mení Vec) +cisla.shuffle(&mut rng); +// cisla je teraz napr. [7, 2, 9, 1, 5, 3, 10, 4, 8, 6] +``` + +**`&mut self`** — shuffle mení vektor, preto `let mut cisla` a `&mut rng`. + +### Kedy shuffle vs choose_multiple + +| Chcem... | Použi | +|----------|-------| +| 1 náhodný prvok | `choose` | +| N náhodných (bez zmeny originálu) | `choose_multiple` | +| Zamiešať celý zoznam | `shuffle` | +| Prvých N po zamiešaní | `shuffle` + `.iter().take(n)` | + +### Na skúške — zamiešanie otázok/odpovedí + +```rust +impl Kviz { + fn hraj(&mut self) { + let mut rng = rand::thread_rng(); + + // Zamieša poradie otázok + self.otazky.shuffle(&mut rng); + + for otazka in &self.otazky { + println!("{}", otazka.text); + // ... + } + } +} + +// Alebo zamiešaj odpovede ku každej otázke +impl Otazka { + fn zamiesaj_odpovede(&mut self) { + let mut rng = rand::thread_rng(); + self.odpovede.shuffle(&mut rng); + } +} +``` + +### Úlohy 5 + +**5a.** Máš vektor kariet. Zamieša ho. Vypíš prvých 5 (to je "ruka" hráča). + +**5b.** Máš Vec. Zamieša poradie. Vypíš otázky v novom poradí. + +**5c.** Čo je zle? +```rust +let cisla = vec![1, 2, 3, 4, 5]; +cisla.shuffle(&mut rand::thread_rng()); +``` + +--- + +## Kapitola 6: Generovanie náhodných znakov a reťazcov + +```rust +use rand::Rng; +use rand::distributions::Alphanumeric; + +let mut rng = rand::thread_rng(); + +// Náhodný ASCII znak a-z +let znak: char = rng.gen_range(b'a'..=b'z') as char; + +// Náhodný veľký znak A-Z +let znak: char = rng.gen_range(b'A'..=b'Z') as char; + +// Náhodný alfanumerický reťazec (a-z, A-Z, 0-9) +let heslo: String = (0..12) + .map(|_| rng.sample(Alphanumeric) as char) + .collect(); +// napr. "a7Bk9xQ2mF1p" +``` + +### Výber náhodného znaku z reťazca + +```rust +use rand::seq::SliceRandom; + +let abeceda: Vec = "abcdefghijklmnopqrstuvwxyz".chars().collect(); +let mut rng = rand::thread_rng(); + +let nahodny_znak = abeceda.choose(&mut rng); +// Some(&'m') +``` + +### Úlohy 6 + +**6a.** Vygeneruj náhodné heslo dlhé 10 znakov, len z malých písmen a-z. + +**6b.** Vygeneruj náhodné meno: veľké prvé písmeno + 4 malé písmená. + +**6c.** Máš abecedu slovenských znakov (vrátane diakritiky) ako Vec. Vyber 5 náhodných. + +--- + +## Kapitola 7: gen_bool a bernoulli — pravdepodobnosť + +```rust +use rand::Rng; + +let mut rng = rand::thread_rng(); + +// 50% šanca na true +let minca: bool = rng.gen_bool(0.5); + +// 70% šanca na true +let dost_casto: bool = rng.gen_bool(0.7); + +// 10% šanca na true +let zriedka: bool = rng.gen_bool(0.1); + +// 100% true +let vzdy: bool = rng.gen_bool(1.0); + +// 0% true +let nikdy: bool = rng.gen_bool(0.0); +``` + +### Praktické použitie + +```rust +// Šanca na kritický zásah v hre +fn je_kriticky_zasah(sila: f64) -> bool { + let mut rng = rand::thread_rng(); + rng.gen_bool(sila / 100.0) // sila 25 → 25% šanca +} + +// Náhodná udalosť +fn nahodna_udalost() { + let mut rng = rand::thread_rng(); + if rng.gen_bool(0.3) { + println!("Nastala špeciálna udalosť! (30% šanca)"); + } +} +``` + +### Úlohy 7 + +**7a.** Simuluj 1000 hodov mincou. Koľkokrát padol orol (true)? + +**7b.** Napíš funkciu, ktorá vráti "Výhra!" s pravdepodobnosťou 15% a "Skús znova" inak. + +--- + +## Kapitola 8: Kombinácia s IO — interaktívne hry + +### Hádaj číslo + +```rust +use rand::Rng; +use std::io::{self, Write}; + +fn prompt(text: &str) -> String { + print!("{}", text); + io::stdout().flush().unwrap(); + let mut vstup = String::new(); + io::stdin().read_line(&mut vstup).unwrap(); + vstup.trim().to_string() +} + +fn main() { + let mut rng = rand::thread_rng(); + let tajne: i32 = rng.gen_range(1..=100); + let mut pokusy = 0; + + println!("Hádaj číslo od 1 do 100!"); + + loop { + let vstup = prompt("Tvoj tip: "); + let tip: i32 = match vstup.parse() { + Ok(n) => n, + Err(_) => { + println!("Zadaj číslo!"); + continue; + } + }; + + pokusy += 1; + + if tip < tajne { + println!("Viac!"); + } else if tip > tajne { + println!("Menej!"); + } else { + println!("Správne! Uhádol si na {} pokusov.", pokusy); + break; + } + } +} +``` + +### Obesenec s náhodným slovom + +```rust +use rand::seq::SliceRandom; +use std::collections::{HashSet, HashMap}; +use std::io::{self, Write}; + +fn nacitaj_znak() -> Option { + print!("Zadaj písmeno: "); + io::stdout().flush().unwrap(); + let mut vstup = String::new(); + io::stdin().read_line(&mut vstup).ok()?; + vstup.trim().to_lowercase().chars().next() +} + +fn main() { + // Slovník + let slovnik: HashMap<&str, Vec<&str>> = HashMap::from([ + ("zvierata", vec!["pes", "macka", "kon", "krava", "zajac"]), + ("jedlo", vec!["pizza", "burger", "salat", "rizoto"]), + ]); + + // Vyber náhodnú kategóriu a slovo + let mut rng = rand::thread_rng(); + let kategorie: Vec<&&str> = slovnik.keys().collect(); + let kategoria = **kategorie.choose(&mut rng).unwrap(); + let slova = &slovnik[kategoria]; + let slovo = *slova.choose(&mut rng).unwrap(); + + println!("Kategória: {}", kategoria); + + // Stav hry + let mut uhadnute: HashSet = HashSet::new(); + let mut skusane: HashSet = HashSet::new(); + let mut zivoty: u8 = 6; + + loop { + // Zobraz slovo + let zobrazene: String = slovo.chars().map(|c| { + if uhadnute.contains(&c) { c } else { '_' } + }).collect(); + println!("\n{} (životov: {})", zobrazene, zivoty); + + // Výhra? + if slovo.chars().all(|c| uhadnute.contains(&c)) { + println!("Vyhral si! Slovo bolo: {}", slovo); + break; + } + // Prehra? + if zivoty == 0 { + println!("Prehral si! Slovo bolo: {}", slovo); + break; + } + + // Vstup + let Some(pismeno) = nacitaj_znak() else { + println!("Neplatný vstup"); + continue; + }; + + if !skusane.insert(pismeno) { + println!("Toto písmeno si už skúšal!"); + continue; + } + + if slovo.contains(pismeno) { + uhadnute.insert(pismeno); + println!("Správne!"); + } else { + zivoty -= 1; + println!("Zle!"); + } + } +} +``` + +### Úlohy 8 + +**8a.** Napíš hru "hádaj číslo" kde rozsah závisí od obtiažnosti: +- Ľahká: 1–10 +- Stredná: 1–50 +- Ťažká: 1–100 +Použi prompt na výber obtiažnosti. + +**8b.** Napíš jednoduchú kvízovú hru: 5 otázok z náhodne zamiešaného poolu. Každá otázka má 4 odpovede (zamiešané). Hráč zadáva číslo odpovede. + +--- + +## Kapitola 9: Náhodné s kolekciami + +### Náhodný kľúč z HashMap + +```rust +use rand::seq::IteratorRandom; // TOTO pre .choose na iterátore! + +let mut mapa = HashMap::new(); +mapa.insert("a", 1); +mapa.insert("b", 2); +mapa.insert("c", 3); + +let mut rng = rand::thread_rng(); + +// Náhodný kľúč +let kluc = mapa.keys().choose(&mut rng); +// Some(&"b") + +// Náhodný pár +let par = mapa.iter().choose(&mut rng); +// Some((&"a", &1)) +``` + +**Import:** `use rand::seq::IteratorRandom;` — toto umožní `.choose()` na akomkoľvek iterátore, nielen na slice. + +### Náhodný prvok z HashSet + +```rust +use rand::seq::IteratorRandom; + +let mnozina: HashSet = vec!["pes", "mačka", "kôň"] + .into_iter().map(String::from).collect(); + +let mut rng = rand::thread_rng(); +let nahodny = mnozina.iter().choose(&mut rng); +// Some(&"mačka") +``` + +### Úlohy 9 + +**9a.** Máš HashMap kategórií. Vyber náhodnú kategóriu (kľúč), potom náhodné slovo z nej. + +**9b.** Máš HashSet skúšaných písmen. Vyber náhodné písmeno z abecedy, ktoré ešte NIE JE v sete. + +--- + +## Kapitola 10: Kompletný vzor — SpravcaHry zo skúšky + +```rust +use rand::seq::SliceRandom; +use serde::{Serialize, Deserialize}; +use std::collections::HashMap; +use std::path::PathBuf; + +#[derive(Serialize, Deserialize, Default)] +pub struct SpravcaHry { + pub slovnik: HashMap>, +} + +impl SpravcaHry { + pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option { + let raw = std::fs::read_to_string(cesta).ok()?; + serde_json::from_str(&raw).ok() + } + + pub fn uloz_do_suboru(&self, cesta: &PathBuf) -> bool { + let Ok(json) = serde_json::to_string_pretty(&self) else { + return false; + }; + std::fs::write(cesta, json).is_ok() + } + + // NAJDÔLEŽITEJŠIA METÓDA — náhodné slovo z kategórie + pub fn vytvor_novu_hru(&self, kategoria: &str) -> Option { + // 1. Nájdi kategóriu + let slova = self.slovnik.get(kategoria)?; + + // 2. Prázdna kategória → None + if slova.is_empty() { + return None; + } + + // 3. Náhodný výber + let mut rng = rand::thread_rng(); + let slovo = slova.choose(&mut rng)?; + + // 4. Vytvor hru + Some(Hra::new(slovo)) + } + + pub fn pridaj_kategoriu(&mut self, kategoria: &str) -> Result<(), ()> { + if self.slovnik.contains_key(kategoria) { + return Err(()); + } + self.slovnik.insert(kategoria.to_string(), Vec::new()); + Ok(()) + } + + pub fn pridaj_slovo(&mut self, kategoria: &str, slovo: &str) -> Result<(), ()> { + let slova = self.slovnik.get_mut(kategoria).ok_or(())?; + slova.push(slovo.to_string()); + Ok(()) + } +} +``` + +### main.rs s clapom + +```rust +use clap::{Parser, Subcommand}; +use std::path::PathBuf; + +#[derive(Parser)] +struct Args { + #[command(subcommand)] + cmd: Cmd, +} + +#[derive(Subcommand)] +enum Cmd { + PridajKategoriu { + cesta: PathBuf, + kategoria: String, + }, + PridajSlovo { + cesta: PathBuf, + kategoria: String, + slovo: String, + }, + Hraj { + cesta: PathBuf, + kategoria: String, + }, +} + +fn main() { + let args = Args::parse(); + + match args.cmd { + Cmd::PridajKategoriu { cesta, kategoria } => { + let mut spravca = SpravcaHry::nacitaj_zo_suboru(&cesta) + .unwrap_or_default(); + match spravca.pridaj_kategoriu(&kategoria) { + Ok(()) => { + spravca.uloz_do_suboru(&cesta); + println!("Kategória pridaná."); + } + Err(()) => println!("Kategória už existuje."), + } + } + Cmd::PridajSlovo { cesta, kategoria, slovo } => { + let mut spravca = SpravcaHry::nacitaj_zo_suboru(&cesta) + .unwrap_or_default(); + match spravca.pridaj_slovo(&kategoria, &slovo) { + Ok(()) => { + spravca.uloz_do_suboru(&cesta); + println!("Slovo pridané."); + } + Err(()) => println!("Kategória neexistuje."), + } + } + Cmd::Hraj { cesta, kategoria } => { + let spravca = SpravcaHry::nacitaj_zo_suboru(&cesta) + .unwrap_or_default(); + match spravca.vytvor_novu_hru(&kategoria) { + Some(mut hra) => { + hra.hraj(ConsoleIOManager); + } + None => println!("Kategória neexistuje alebo je prázdna."), + } + } + } +} +``` + +### Úlohy 10 + +**10a.** Napíš celý SpravcaHry od nuly bez pozerania. Musíš mať: +- `slovnik: HashMap>` +- `nacitaj_zo_suboru`, `uloz_do_suboru` +- `pridaj_kategoriu`, `pridaj_slovo` +- `vytvor_novu_hru` s `choose` + +**10b.** Napíš main.rs s clapom bez pozerania. Subcommands: +- `pridaj-kategoriu ` +- `pridaj-slovo ` +- `hraj ` + +**10c.** Rozšír SpravcaHry o metódu `nahodna_kategoria(&self) -> Option<&String>` — vyber náhodnú kategóriu. Použi `IteratorRandom`. + +--- + +## Prehľad: čo importovať a kedy + +| Chcem... | Import | Metóda | +|----------|--------|--------| +| Náhodné číslo | `use rand::Rng;` | `rng.gen()`, `rng.gen_range(1..=6)` | +| Náhodný bool | `use rand::Rng;` | `rng.gen_bool(0.5)` | +| Náhodný prvok z Vec/slice | `use rand::seq::SliceRandom;` | `vec.choose(&mut rng)` | +| Viac náhodných prvkov | `use rand::seq::SliceRandom;` | `vec.choose_multiple(&mut rng, n)` | +| Zamiešať Vec | `use rand::seq::SliceRandom;` | `vec.shuffle(&mut rng)` | +| Náhodný z iterátora (HashMap, HashSet) | `use rand::seq::IteratorRandom;` | `iter.choose(&mut rng)` | +| Alfanumerické znaky | `use rand::distributions::Alphanumeric;` | `rng.sample(Alphanumeric)` | + +**Vždy:** `let mut rng = rand::thread_rng();` — vytvor generátor. +**Vždy:** `&mut rng` — predávaj ako meniteľnú referenciu.