19 KiB
rand — krok za krokom
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
Cargo.toml:
[dependencies]
rand = "0.8"
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():
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?
let rng = rand::thread_rng();
let cislo: i32 = rng.gen();
Kapitola 2: gen_range — číslo v rozsahu
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.
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
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
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
use rand::seq::SliceRandom;
use std::collections::HashMap;
struct SpravcaHry {
slovnik: HashMap<String, Vec<String>>,
}
impl SpravcaHry {
fn vytvor_novu_hru(&self, kategoria: &str) -> Option<Hra> {
// 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<String, Vec> (kategória → slová). Napíš funkciu:
fn nahodne_slovo(slovnik: &HashMap<String, Vec<String>>, 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
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
struct Kviz {
otazky: Vec<Otazka>,
}
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
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í
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?
let cisla = vec![1, 2, 3, 4, 5];
cisla.shuffle(&mut rand::thread_rng());
Kapitola 6: Generovanie náhodných znakov a reťazcov
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
use rand::seq::SliceRandom;
let abeceda: Vec<char> = "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ť
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
// Š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
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
use rand::seq::SliceRandom;
use std::collections::{HashSet, HashMap};
use std::io::{self, Write};
fn nacitaj_znak() -> Option<char> {
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<char> = HashSet::new();
let mut skusane: HashSet<char> = 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
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
use rand::seq::IteratorRandom;
let mnozina: HashSet<String> = 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
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<String, Vec<String>>,
}
impl SpravcaHry {
pub fn nacitaj_zo_suboru(cesta: &PathBuf) -> Option<SpravcaHry> {
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<Hra> {
// 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
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<String, Vec<String>>nacitaj_zo_suboru,uloz_do_suborupridaj_kategoriu,pridaj_slovovytvor_novu_hruschoose
10b. Napíš main.rs s clapom bez pozerania. Subcommands:
pridaj-kategoriu <cesta> <kategoria>pridaj-slovo <cesta> <kategoria> <slovo>hraj <cesta> <kategoria>
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.