# 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.