Files
JR-priprava-na-skusku/priprava/rust_priprava14.md
2026-03-06 08:02:25 +01:00

16 KiB
Raw Blame History

rand — krok za krokom (aktuálna verzia)

Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.

Cargo.toml:

[dependencies]
rand = "0.10"

Najjednoduchší import — dáva ti všetko bežné:

use rand::prelude::*;

Kapitola 1: Generátor — rand::rng()

use rand::Rng;

fn main() {
    let mut rng = rand::rng();

    // Náhodné celé číslo (celý rozsah typu)
    let cislo: i32 = rng.random();
    println!("{}", cislo);

    // Náhodné f64 medzi 0.0 a 1.0
    let desatinne: f64 = rng.random();
    println!("{}", desatinne);

    // Náhodné bool
    let minca: bool = rng.random();
    println!("{}", minca);
}

mut rng — generátor mení svoj stav pri každom volaní.

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

1c. Čo je zle?

let rng = rand::rng();
let cislo: i32 = rng.random();

Kapitola 2: random_range — číslo v rozsahu

use rand::Rng;

let mut rng = rand::rng();

// Od 1 do 10 (vrátane oboch)
let cislo: i32 = rng.random_range(1..=10);

// Od 1 do 9 (10 NIE JE zahrnuté)
let cislo: i32 = rng.random_range(1..10);

// Float od 0.0 do 1.0 (1.0 nie je zahrnuté)
let cislo: f64 = rng.random_range(0.0..1.0);

// Náhodný index do vektora
let vektor = vec!["a", "b", "c", "d", "e"];
let index: usize = rng.random_range(0..vektor.len());
let nahodny_prvok = &vektor[index];
Zápis Rozsah Príklad
1..10 1 až 9 bez konca
1..=10 1 až 10 vrátane konca
0..vektor.len() 0 až posledný index náhodný index

Úlohy 2

2a. Simuluj hod kockou (16). Hoď 100-krát, spočítaj výskyty každého čísla (HashMap).

2b. Vygeneruj náhodné heslo — 8 znakov a-z. Hint: rng.random_range(b'a'..=b'z') as char.

2c. Napíš funkciu nahodne_cislo(od: i32, do_: i32) -> i32.


Kapitola 3: choose — náhodný výber z kolekcie

Toto je najdôležitejšie na skúške.

use rand::seq::IndexedRandom;  // TOTO TREBA!

let mut rng = rand::rng();

let ovocie = vec!["jablko", "hruška", "banán", "pomaranč"];

// choose — vráti Option (None ak prázdny Vec)
let nahodne = ovocie.choose(&mut rng);
// Some(&"hruška")

match nahodne {
    Some(o) => println!("Vybrané: {}", o),
    None => println!("Prázdny zoznam"),
}

Import: use rand::seq::IndexedRandom; — bez tohto choose nefunguje!

Alebo použi use rand::prelude::*; — ten to zahŕňa.

choose s Vec

use rand::seq::IndexedRandom;

let slova = vec!["pes".to_string(), "mačka".to_string(), "kôň".to_string()];
let mut rng = rand::rng();

let nahodne: Option<&String> = slova.choose(&mut rng);
// Some(&"mačka")

choose na skúške — SpravcaHry.vytvor_novu_hru

use rand::seq::IndexedRandom;
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
        let slova = self.slovnik.get(kategoria)?;

        // 2. Prázdna → None
        if slova.is_empty() {
            return None;
        }

        // 3. Vyber náhodné slovo
        let mut rng = rand::rng();
        let slovo = slova.choose(&mut rng)?;

        // 4. Vytvor hru
        Some(Hra::new(slovo))
    }
}

Krok po kroku:

slovnik = {"zvierata": ["pes", "mačka", "kôň"]}

kategoria = "zvierata"
  → slovnik.get("zvierata") → Some(&["pes", "mačka", "kôň"])
  → slova.choose(&mut rng) → Some(&"mačka")
  → Hra::new("mačka")

kategoria = "neexistuje"
  → slovnik.get("neexistuje") → None
  → ? → return None

Úlohy 3

3a. Máš Vec mien. Vyber náhodné a vypíš.

3b. Máš HashMap<String, Vec> (kategória → slová). Napíš funkciu:

fn nahodne_slovo(slovnik: &HashMap<String, Vec<String>>, kategoria: &str) -> Option<&String>

3c. Čo sa stane ak zavoláš .choose() na prázdnom vektore?


Kapitola 4: sample — viac náhodných prvkov

V novej verzii rand sa choose_multiple nahradil metódou sample:

use rand::seq::IndexedRandom;

let cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut rng = rand::rng();

// Vyber 3 náhodné prvky (BEZ opakovania)
let vybrane: Vec<&i32> = cisla.sample(&mut rng, 3).collect();
// napr. [&7, &2, &9]

// Ak chceš viac ako je prvkov, vráti len toľko koľko je
let vsetky: Vec<&i32> = cisla.sample(&mut rng, 100).collect();

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::rng();
        self.otazky.sample(&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.


Kapitola 5: shuffle — zamiešanie

use rand::seq::SliceRandom;  // shuffle je v SliceRandom!

let mut cisla = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut rng = rand::rng();

// shuffle — zamieša NA MIESTE (mení Vec)
cisla.shuffle(&mut rng);
// napr. [7, 2, 9, 1, 5, 3, 10, 4, 8, 6]

Import: use rand::seq::SliceRandom; — shuffle je v SliceRandom, nie IndexedRandom!

Kedy čo

Chcem... Použi Import
1 náhodný prvok .choose() IndexedRandom
N náhodných (bez zmeny originálu) .sample() IndexedRandom
Zamiešať celý zoznam .shuffle() SliceRandom

Na skúške — zamiešanie otázok

use rand::seq::SliceRandom;

impl Kviz {
    fn hraj(&mut self) {
        let mut rng = rand::rng();
        self.otazky.shuffle(&mut rng);

        for otazka in &self.otazky {
            println!("{}", otazka.text);
        }
    }
}

Úlohy 5

5a. Máš vektor kariet. Zamiešaj. Vypíš prvých 5.

5b. Čo je zle?

let cisla = vec![1, 2, 3, 4, 5];
cisla.shuffle(&mut rand::rng());

Kapitola 6: Náhodné znaky a reťazce

use rand::Rng;
use rand::distr::Alphanumeric;  // distr, nie distributions!

let mut rng = rand::rng();

// Náhodný ASCII znak a-z
let znak: char = rng.random_range(b'a'..=b'z') as char;

// Náhodný veľký znak A-Z
let znak: char = rng.random_range(b'A'..=b'Z') as char;

// 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::IndexedRandom;

let abeceda: Vec<char> = "abcdefghijklmnopqrstuvwxyz".chars().collect();
let mut rng = rand::rng();

let nahodny_znak = abeceda.choose(&mut rng);
// Some(&'m')

Úlohy 6

6a. Vygeneruj heslo: 10 znakov, len malé písmená a-z.

6b. Vygeneruj náhodné meno: veľké prvé + 4 malé písmená.


Kapitola 7: random_bool — pravdepodobnosť

use rand::Rng;

let mut rng = rand::rng();

// 50% šanca na true
let minca: bool = rng.random_bool(0.5);

// 70% šanca na true
let dost_casto: bool = rng.random_bool(0.7);

// 10% šanca na true
let zriedka: bool = rng.random_bool(0.1);

Úlohy 7

7a. Simuluj 1000 hodov mincou. Koľkokrát padol orol (true)?

7b. Funkcia vráti "Výhra!" s 15% pravdepodobnosťou, inak "Skús znova".


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::rng();
    let tajne: i32 = rng.random_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::IndexedRandom;
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() {
    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::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);

    let mut uhadnute: HashSet<char> = HashSet::new();
    let mut skusane: HashSet<char> = HashSet::new();
    let mut zivoty: u8 = 6;

    loop {
        let zobrazene: String = slovo.chars().map(|c| {
            if uhadnute.contains(&c) { c } else { '_' }
        }).collect();
        println!("\n{} (životov: {})", zobrazene, zivoty);

        if slovo.chars().all(|c| uhadnute.contains(&c)) {
            println!("Vyhral si! Slovo bolo: {}", slovo);
            break;
        }
        if zivoty == 0 {
            println!("Prehral si! Slovo bolo: {}", slovo);
            break;
        }

        let Some(pismeno) = nacitaj_znak() else {
            println!("Neplatný vstup");
            continue;
        };

        if !skusane.insert(pismeno) {
            println!("Už si skúšal!");
            continue;
        }

        if slovo.contains(pismeno) {
            uhadnute.insert(pismeno);
            println!("Správne!");
        } else {
            zivoty -= 1;
            println!("Zle!");
        }
    }
}

Úlohy 8

8a. Napíš "hádaj číslo" s obtiažnosťou: ľahká (110), stredná (150), ťažká (1100).

8b. Napíš kvízovú hru: 5 otázok z náhodne zamiešaného poolu, hráč zadáva číslo odpovede.


Kapitola 9: Náhodné z HashMap a HashSet

Pre iterátory (nie slice) treba IteratorRandom:

use rand::seq::IteratorRandom;  // 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::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))
// HashSet — rovnako
use rand::seq::IteratorRandom;

let mnozina: HashSet<String> = vec!["pes", "mačka", "kôň"]
    .into_iter().map(String::from).collect();

let mut rng = rand::rng();
let nahodny = mnozina.iter().choose(&mut rng);
// Some(&"mačka")

Úlohy 9

9a. Máš HashMap kategórií. Vyber náhodnú kategóriu, potom náhodné slovo z nej.

9b. Máš HashSet skúšaných písmen. Vyber písmeno z abecedy, ktoré ešte NIE JE v sete.


Kapitola 10: Kompletný vzor — SpravcaHry zo skúšky

use rand::seq::IndexedRandom;
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()
    }

    pub fn vytvor_novu_hru(&self, kategoria: &str) -> Option<Hra> {
        let slova = self.slovnik.get(kategoria)?;
        if slova.is_empty() {
            return None;
        }
        let mut rng = rand::rng();
        let slovo = slova.choose(&mut rng)?;
        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.

10b. Napíš main.rs s clapom bez pozerania.

10c. Rozšír o metódu nahodna_kategoria(&self) -> Option<&String>. Použi IteratorRandom.


Prehľad: čo importovať a kedy

Chcem... Import Metóda
Náhodné číslo use rand::Rng; rng.random()
Číslo v rozsahu use rand::Rng; rng.random_range(1..=6)
Náhodný bool use rand::Rng; rng.random_bool(0.5)
Náhodný prvok z Vec use rand::seq::IndexedRandom; vec.choose(&mut rng)
N náhodných prvkov use rand::seq::IndexedRandom; vec.sample(&mut rng, n)
Zamiešať Vec use rand::seq::SliceRandom; vec.shuffle(&mut rng)
Náhodný z iterátora use rand::seq::IteratorRandom; iter.choose(&mut rng)
Alfanumerické znaky use rand::distr::Alphanumeric; rng.sample(Alphanumeric) as char
Všetko naraz use rand::prelude::*; zahŕňa Rng, IndexedRandom, SliceRandom

Vždy: let mut rng = rand::rng();

Zmeny oproti starým verziám (0.8)

Ak niekde vidíš starý kód, tu je preklad:

Staré (rand 0.8) Nové (rand 0.9+)
rand::thread_rng() rand::rng()
rng.gen() rng.random()
rng.gen_range(1..=6) rng.random_range(1..=6)
rng.gen_bool(0.5) rng.random_bool(0.5)
use rand::distributions:: use rand::distr::
vec.choose_multiple(&mut rng, n) vec.sample(&mut rng, n)
use rand::seq::SliceRandom; (pre choose) use rand::seq::IndexedRandom;