jr priprava 5

This commit is contained in:
Priec
2026-02-14 15:10:11 +01:00
parent bd3036c63c
commit 1055a7fbf0
11 changed files with 1118 additions and 17 deletions

View File

@@ -0,0 +1,821 @@
# Intenzívna príprava na skúšku z Rustu
## Analýza vzoru skúšok
Z troch skúšok (Knižnica, Obesenec, Milionár) vyplýva **vždy rovnaký vzor**:
1. **Štruktúry** s derives (Serialize, Deserialize, Default, Clone, PartialEq)
2. **Enumy** s derives + Display
3. **Asociované funkcie** (konštruktory `::new`, `::nacitaj_zo_suboru`)
4. **Metódy** na štruktúrach (CRUD operácie, filtrovanie, štatistiky)
5. **JSON serializácia/deserializácia** cez serde
6. **File I/O** s PathBuf → Option<T> alebo bool
7. **CLI aplikácia** s knižnicou `clap` (subcommands + argumenty)
8. **Trait definícia + implementácia** (IOManager, Display)
9. **Iterátory** (filter, find, map, collect)
10. **Option/Result** return typy všade
### Povolené knižnice
- `clap` (derive), `serde` (derive), `serde_json`, `itertools`, `rand`
- `chrono` (serde), `futures`, `color-eyre`, `dotenvy`
---
## BLOK 1: Štruktúry, Enumy, Derives (základ všetkého)
### Cvičenie 1.1 — Filmová databáza
Implementuj nasledovné:
```
Enum Zaner:
- Hodnoty: Akcia, Komedia, Horor, Drama, SciFi, Dokumentarny
- Požadované traity: Default, Display, Serialize, Deserialize, PartialEq, Clone
- Default vráti hodnotu Drama
Štruktúra Film:
- nazov: String
- reziser: String
- rok: u16
- zaner: Zaner
- hodnotenie: f32 (0.0 - 10.0)
- Požadované traity: Default, Serialize, Deserialize, Clone
Štruktúra Filmoteka:
- filmy: Vec<Film>
- Požadované traity: Default, Serialize, Deserialize
```
**Úlohy:**
1. Implementuj `Display` pre `Zaner` (výstup: slovenský názov žánru)
2. Implementuj `Display` pre `Film` (formát: `"Nazov (rok) - Reziser [Zaner] ★hodnotenie"`)
3. Implementuj `Default` pre `Zaner`
### Cvičenie 1.2 — Enum s dátami
```
Enum Stav:
- Aktivny
- Pozastaveny { dovod: String }
- Ukonceny { datum: String, hodnotenie: u8 }
- Požadované traity: Serialize, Deserialize, Clone, PartialEq
```
Implementuj `Display` pre `Stav`:
- Aktivny → "Aktívny"
- Pozastaveny → "Pozastavený: {dovod}"
- Ukonceny → "Ukončený dňa {datum} s hodnotením {hodnotenie}"
---
## BLOK 2: Asociované funkcie a Konštruktory
### Cvičenie 2.1 — ::new a ::nacitaj_zo_suboru
Pre štruktúru `Filmoteka`:
```rust
// Asociovaná funkcia - načíta z JSON súboru
// Parameter: &std::path::PathBuf
// Návratová hodnota: Option<Filmoteka>
// Ak súbor neexistuje → None
// Ak sa nepodarí deserializovať → None
fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Option<Filmoteka>
// Metóda - uloží do JSON súboru
// Parameter: &std::path::PathBuf
// Návratová hodnota: bool (true ak úspech)
fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool
```
**Kľúčové vzory na zapamätanie:**
```rust
// Čítanie súboru
let obsah = std::fs::read_to_string(cesta).ok()?;
let data: T = serde_json::from_str(&obsah).ok()?;
// Zápis do súboru
let json = serde_json::to_string_pretty(&self).ok()?;
std::fs::write(cesta, json).ok()?;
```
### Cvičenie 2.2 — Konštruktor s validáciou
```rust
// Pre štruktúru Film:
// Funkcia ::new berie nazov: &str, reziser: &str, rok: u16, zaner: Zaner, hodnotenie: f32
// Ak hodnotenie nie je v rozsahu 0.0..=10.0, vráti None
// Inak vráti Some(Film)
fn new(nazov: &str, reziser: &str, rok: u16, zaner: Zaner, hodnotenie: f32) -> Option<Film>
```
---
## BLOK 3: Metódy — CRUD + Filtrovanie + Štatistiky
### Cvičenie 3.1 — CRUD operácie (vzor z Knižnica)
Pre `Filmoteka`:
```rust
// Pridaj film. Ak film s rovnakým názvom už existuje → Err(())
fn pridaj_film(&mut self, film: Film) -> Result<(), ()>
// Odstráň film podľa názvu. Ak neexistuje → Err(())
fn odstran_film(&mut self, nazov: &str) -> Result<Film, ()>
```
### Cvičenie 3.2 — Filtrovanie (vzor z Knižnica)
```rust
// Vráti film podľa názvu
fn daj_film_podla_nazvu(&self, nazov: &str) -> Option<&Film>
// Vráti všetky filmy daného režiséra
fn daj_filmy_rezisera(&self, reziser: &str) -> Vec<&Film>
// Vráti všetky filmy daného žánru
fn daj_filmy_podla_zanru(&self, zaner: &Zaner) -> Vec<&Film>
// Vráti filmy s hodnotením vyšším ako zadané
fn daj_filmy_nad_hodnotenie(&self, min: f32) -> Vec<&Film>
```
### Cvičenie 3.3 — Štatistiky (vzor z Knižnica)
```rust
// Pre každý žáner vypíše počet filmov
// Formát: "Žáner: počet filmov"
fn vypis_statistiky_zanrov(&self)
// Priemerné hodnotenie filmov daného režiséra
fn priemerne_hodnotenie_rezisera(&self, reziser: &str) -> Option<f32>
```
**Tip:** Použi `itertools` alebo `HashMap` na zoskupenie:
```rust
use std::collections::HashMap;
let mut mapa: HashMap<&str, Vec<&Film>> = HashMap::new();
for film in &self.filmy {
mapa.entry(&film.reziser).or_default().push(film);
}
```
---
## BLOK 4: Traity (vzor z Obesenec — IOManager)
### Cvičenie 4.1 — Definícia a implementácia traitu
```rust
// Trait pre vstup/výstup
trait IOManager {
fn ziskaj_vstup(&self) -> String;
fn zobraz_spravu(&self, sprava: &str);
}
// Implementuj pre štruktúru ConsoleIO (prázdna štruktúra)
struct ConsoleIO;
impl IOManager for ConsoleIO {
fn ziskaj_vstup(&self) -> String {
let mut vstup = String::new();
std::io::stdin().read_line(&mut vstup).unwrap();
vstup.trim().to_string()
}
fn zobraz_spravu(&self, sprava: &str) {
println!("{}", sprava);
}
}
```
### Cvičenie 4.2 — Trait s generickým parametrom
```rust
// Trait pre validáciu
trait Validator {
fn je_platny(&self) -> bool;
fn chyby(&self) -> Vec<String>;
}
// Implementuj pre Film:
// - hodnotenie musí byť 0.0..=10.0
// - nazov nesmie byť prázdny
// - rok musí byť 1888..=2026
```
---
## BLOK 5: Hra — Game Loop Pattern (vzor z Obesenec + Milionár)
### Cvičenie 5.1 — Kvízová hra
Implementuj jednoduchú kvízovú hru:
```
Štruktúra Odpoved:
- text: String
- je_spravna: bool
- Traity: Serialize, Deserialize, Clone
Štruktúra Otazka:
- text: String
- odpovede: Vec<Odpoved> (presne 4)
- Traity: Serialize, Deserialize, Clone
Štruktúra Kviz:
- otazky: Vec<Otazka>
- aktualne_skore: u32
- Traity: Serialize, Deserialize, Default
```
**Metódy:**
```rust
impl Odpoved {
fn new(text: &str, je_spravna: bool) -> Odpoved
}
impl Otazka {
// Vytvorí otázku. Ak odpovede.len() != 4, vráti None
// Ak žiadna odpoveď nie je správna, vráti None
fn new(text: &str, odpovede: Vec<Odpoved>) -> Option<Otazka>
// Pridá odpoveď. Ak je už 4, vráti false.
fn pridaj_odpoved(&mut self, odpoved: Odpoved) -> bool
}
impl Kviz {
fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Option<Kviz>
fn uloz_do_suboru(&self, cesta: &std::path::PathBuf) -> bool
// Vyberie náhodnú otázku
fn nahodna_otazka(&self) -> Option<&Otazka>
// Vyhodnotí odpoveď (index 0-3), vráti bool
fn vyhodnot(&mut self, otazka: &Otazka, index: usize) -> bool
// Game loop - používa IOManager trait
fn hraj(&mut self, io: &impl IOManager)
}
```
### Cvičenie 5.2 — Implementuj `hraj` metódu
Vzor game loopu (toto sa opakuje na KAŽDEJ skúške):
```rust
fn hraj(&mut self, io: &impl IOManager) {
loop {
// 1. Zobraz stav hry
io.zobraz_spravu(&format!("Skóre: {}", self.aktualne_skore));
// 2. Vyber otázku
let otazka = match self.nahodna_otazka() {
Some(o) => o.clone(),
None => { io.zobraz_spravu("Žiadne otázky!"); return; }
};
// 3. Zobraz otázku + odpovede
io.zobraz_spravu(&otazka.text);
for (i, odp) in otazka.odpovede.iter().enumerate() {
io.zobraz_spravu(&format!(" {}: {}", i + 1, odp.text));
}
// 4. Načítaj vstup
let vstup = io.ziskaj_vstup();
// 5. Spracuj vstup
match vstup.trim().parse::<usize>() {
Ok(n) if n >= 1 && n <= 4 => {
if self.vyhodnot(&otazka, n - 1) {
io.zobraz_spravu("Správne!");
} else {
io.zobraz_spravu("Nesprávne!");
}
}
_ => {
io.zobraz_spravu("Neplatný vstup!");
continue;
}
}
// 6. Kontrola konca
io.zobraz_spravu("Pokračovať? (a/n)");
if io.ziskaj_vstup().trim() == "n" {
break;
}
}
io.zobraz_spravu(&format!("Konečné skóre: {}", self.aktualne_skore));
}
```
---
## BLOK 6: CLI s Clap (toto je na KAŽDEJ skúške za 5-6 bodov!)
### Cvičenie 6.1 — Základný clap vzor
```rust
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "filmoteka")]
struct Cli {
#[command(subcommand)]
prikaz: Prikazy,
}
#[derive(Subcommand)]
enum Prikazy {
/// Pridaj nový film
Pridaj {
/// Cesta k súboru s filmami
cesta: std::path::PathBuf,
/// Názov filmu
nazov: String,
/// Režisér
reziser: String,
/// Rok vydania
rok: u16,
},
/// Odstráň film
Odstran {
cesta: std::path::PathBuf,
nazov: String,
},
/// Zobraz filmy režiséra
FilmyRezisera {
cesta: std::path::PathBuf,
reziser: String,
},
/// Štatistiky
Statistiky {
cesta: std::path::PathBuf,
},
}
fn main() {
let cli = Cli::parse();
match cli.prikaz {
Prikazy::Pridaj { cesta, nazov, reziser, rok } => {
// 1. Načítaj filmotéku zo súboru (alebo vytvor novú)
let mut filmoteka = Filmoteka::nacitaj_zo_suboru(&cesta)
.unwrap_or_default();
// 2. Vytvor film a pridaj
let film = Film { nazov, reziser, rok, ..Default::default() };
match filmoteka.pridaj_film(film) {
Ok(()) => {
filmoteka.uloz_do_suboru(&cesta);
println!("Film pridaný.");
}
Err(()) => println!("Film už existuje."),
}
}
Prikazy::Odstran { cesta, nazov } => {
// podobne...
}
// ... ďalšie príkazy
}
}
```
### Cvičenie 6.2 — Clap s viacerými argumentmi
Vzor príkazu s 3 argumentmi (ako v Milionár a Obesenec):
```rust
#[derive(Subcommand)]
enum Prikazy {
PridajOtazku {
/// Cesta k JSON súboru
cesta: std::path::PathBuf,
/// Text otázky
otazka: String,
},
Hraj {
/// Cesta k JSON súboru
cesta: std::path::PathBuf,
/// Kategória
kategoria: String,
},
}
```
---
## BLOK 7: HashSet + Iterátory (vzor z Obesenec)
### Cvičenie 7.1 — Práca s HashSet
```rust
use std::collections::HashSet;
struct SlovnaHra {
hladane_slovo: String,
uhadnute_pismena: HashSet<char>,
skusane_pismena: HashSet<char>,
pocet_zivotov: u8,
}
impl SlovnaHra {
fn new(slovo: &str) -> SlovnaHra {
SlovnaHra {
hladane_slovo: slovo.to_lowercase(),
uhadnute_pismena: HashSet::new(),
skusane_pismena: HashSet::new(),
pocet_zivotov: 6,
}
}
// Vráti slovo s neuhádnutými písmenami nahradenými '_'
fn daj_slovo_skryto(&self) -> String {
self.hladane_slovo.chars().map(|c| {
if self.uhadnute_pismena.contains(&c) { c } else { '_' }
}).collect()
}
// Tipni písmeno - vráti enum VysledokPokusu
fn tipni_pismeno(&mut self, pismeno: char) -> VysledokPokusu {
let p = pismeno.to_lowercase().next().unwrap();
if self.skusane_pismena.contains(&p) {
return VysledokPokusu::Neplatne;
}
self.skusane_pismena.insert(p);
if self.hladane_slovo.contains(p) {
self.uhadnute_pismena.insert(p);
VysledokPokusu::Uhadnute
} else {
self.pocet_zivotov -= 1;
VysledokPokusu::Neuhadnute
}
}
fn je_koniec_hry(&self) -> bool {
self.pocet_zivotov == 0 || self.je_vyhra()
}
fn je_vyhra(&self) -> bool {
self.hladane_slovo.chars().all(|c| self.uhadnute_pismena.contains(&c))
}
}
```
### Cvičenie 7.2 — Iterátory s impl Iterator
```rust
// Vráti iterátor na uhádnuté písmená
fn daj_uhadnute_pismena(&self) -> impl Iterator<Item = &char> {
self.uhadnute_pismena.iter()
}
// Vráti iterátor na skúšané písmená
fn daj_skusane_pismena(&self) -> impl Iterator<Item = &char> {
self.skusane_pismena.iter()
}
```
---
## BLOK 8: rand — Náhodné generovanie
### Cvičenie 8.1
```rust
use rand::Rng;
use rand::seq::SliceRandom;
// Vyber náhodné slovo z vektora
fn nahodne_slovo(slova: &[String]) -> Option<&String> {
let mut rng = rand::thread_rng();
slova.choose(&mut rng)
}
// Náhodné číslo v rozsahu
fn nahodne_cislo(min: u32, max: u32) -> u32 {
let mut rng = rand::thread_rng();
rng.gen_range(min..=max)
}
// Zamiešaj vektor
fn zamiesaj<T>(vektor: &mut Vec<T>) {
let mut rng = rand::thread_rng();
vektor.shuffle(&mut rng);
}
```
---
## BLOK 9: Nové knižnice — chrono, color-eyre, futures
### Cvičenie 9.1 — chrono (dátumy)
```rust
use chrono::{NaiveDate, Local, Datelike};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone)]
struct Udalost {
nazov: String,
datum: NaiveDate, // chrono s serde feature
}
impl Udalost {
fn new(nazov: &str, rok: i32, mesiac: u32, den: u32) -> Option<Udalost> {
let datum = NaiveDate::from_ymd_opt(rok, mesiac, den)?;
Some(Udalost { nazov: nazov.to_string(), datum })
}
fn je_dnes(&self) -> bool {
self.datum == Local::now().date_naive()
}
fn dni_do_udalosti(&self) -> i64 {
let dnes = Local::now().date_naive();
(self.datum - dnes).num_days()
}
}
```
### Cvičenie 9.2 — color-eyre (error handling)
```rust
use color_eyre::eyre::{Result, eyre, WrapErr};
fn nacitaj_zo_suboru(cesta: &std::path::PathBuf) -> Result<Filmoteka> {
let obsah = std::fs::read_to_string(cesta)
.wrap_err_with(|| format!("Nepodarilo sa otvoriť súbor: {:?}", cesta))?;
let filmoteka: Filmoteka = serde_json::from_str(&obsah)
.wrap_err("Nepodarilo sa deserializovať JSON")?;
Ok(filmoteka)
}
fn main() -> Result<()> {
color_eyre::install()?;
// ... zvyšok kódu s ? operátorom
Ok(())
}
```
---
## BLOK 10: Kompletné cvičné zadanie — Správca úloh (TODO app)
**Toto je simulácia skúšky. Skús to celé implementovať za 90 minút.**
### Zadanie: Správca úloh
Cieľom je implementovať aplikáciu na správu úloh s nasledovnými funkcionalitami:
- pridávanie úloh
- odstraňovanie úloh
- označovanie úloh ako dokončené
- filtrovanie úloh podľa rôznych kritérií
- štatistiky
- načítavanie a ukladanie do súboru vo formáte JSON
#### Enum Priorita
- Nazov: Priorita
- Hodnoty: Nizka, Stredna, Vysoka, Kriticka
- Požadované traity: Default, Display, Serialize, Deserialize, PartialEq, Clone
- Default vráti hodnotu Stredna
#### Enum StavUlohy
- Hodnoty: Nova, Rozpracovana, Dokoncena, Zrusena
- Požadované traity: Default, Display, Serialize, Deserialize, PartialEq, Clone
- Default vráti hodnotu Nova
#### Štruktúra Uloha
- nazov: String
- popis: String
- priorita: Priorita
- stav: StavUlohy
- kategoria: String
- Požadované traity: Default, Serialize, Deserialize, Clone
#### Štruktúra SpravcaUloh
- ulohy: Vec<Uloha>
- Požadované traity: Default, Serialize, Deserialize
#### Funkcia SpravcaUloh::nacitaj_zo_suboru
- Parameter: &PathBuf → Option<SpravcaUloh>
#### Metóda spravca_uloh.uloz_do_suboru
- Parameter: &PathBuf → bool
#### Metóda spravca_uloh.pridaj_ulohu
- Parameter: Uloha → Result<(), ()>
- Err ak úloha s rovnakým názvom existuje
#### Metóda spravca_uloh.odstran_ulohu
- Parameter: &str (názov) → Result<Uloha, ()>
#### Metóda spravca_uloh.oznac_dokoncenu
- Parameter: &str (názov) → Result<(), ()>
- Zmení stav úlohy na Dokoncena
#### Metóda spravca_uloh.daj_ulohy_podla_priority
- Parameter: &Priorita → Vec<&Uloha>
#### Metóda spravca_uloh.daj_ulohy_podla_stavu
- Parameter: &StavUlohy → Vec<&Uloha>
#### Metóda spravca_uloh.daj_ulohy_podla_kategorie
- Parameter: &str → Vec<&Uloha>
#### Metóda spravca_uloh.vypis_statistiky_kategorii
- Pre každú kategóriu vypíše počet úloh
- Formát: "Kategória: počet úloh"
#### Metóda spravca_uloh.vypis_ulohy_podla_priority
- Vypíše všetky úlohy zoskupené podľa priority
#### Ovládanie aplikácie (main.rs s clap)
Príkazy:
- `pridaj` — 2 argumenty: cesta k súboru, názov úlohy. Interaktívne sa opýta na popis, prioritu a kategóriu.
- `odstran` — 2 argumenty: cesta k súboru, názov úlohy
- `dokonci` — 2 argumenty: cesta k súboru, názov úlohy
- `zoznam` — 2 argumenty: cesta k súboru, filter (vsetky/dokoncene/nedokoncene)
- `statistiky` — 1 argument: cesta k súboru
---
## BLOK 11: Ďalšie simulácie skúšok
### Simulácia 2 — Správca kontaktov
```
Enum TypKontaktu: Osobny, Pracovny, Rodina
Štruktúra Kontakt: meno, priezvisko, email, telefon, typ_kontaktu
Štruktúra Adresar: kontakty: Vec<Kontakt>
Metódy:
- nacitaj_zo_suboru, uloz_do_suboru
- pridaj_kontakt (duplicita podľa emailu → Err)
- odstran_kontakt (podľa emailu)
- najdi_podla_mena(&str) → Vec<&Kontakt>
- najdi_podla_typu(&TypKontaktu) → Vec<&Kontakt>
- vypis_kontakty_podla_typu()
CLI: pridaj, odstran, hladaj-meno, hladaj-typ, statistiky
```
### Simulácia 3 — Hudobná knižnica (s chrono)
```
Enum Zaner: Rock, Pop, Jazz, Klasicka, HipHop, Elektronicka
Štruktúra Piesnicka: nazov, interpret, zaner, trvanie_sekundy: u32, datum_pridania: NaiveDate
Štruktúra Playlist: nazov, piesnicky: Vec<Piesnicka>
Štruktúra HudobnaKniznica: playlisty: Vec<Playlist>
Metódy pre Playlist:
- pridaj_piesnicku, odstran_piesnicku
- celkove_trvanie() → u32
- piesnicky_interpreta(&str) → Vec<&Piesnicka>
Metódy pre HudobnaKniznica:
- nacitaj_zo_suboru, uloz_do_suboru
- vytvor_playlist, odstran_playlist
- najdi_piesnicku_v_kniznici(&str) → Vec<(&Playlist, &Piesnicka)>
- statistiky_zanrov()
CLI: vytvor-playlist, pridaj-piesnicku (3 arg: cesta, playlist, piesnicka),
zoznam, statistiky
```
### Simulácia 4 — Hra s kartami (trait + rand)
```
Trait Hratelna {
fn tahaj_kartu(&mut self) -> Option<Karta>;
fn je_koniec(&self) -> bool;
fn daj_skore(&self) -> u32;
}
Enum Farba: Srdce, Karo, Piky, Krize (Display)
Enum Hodnota: Cislo(u8), Dolnik, Hornik, Kral, Eso (Display)
Štruktúra Karta: farba, hodnota
Štruktúra Balicek: karty: Vec<Karta>
Štruktúra HraBlackjack: balicek, hrac_karty, dealer_karty, stav_hry
impl Balicek:
- fn novy() → Balicek // vytvorí 32 kariet
- fn zamiesaj(&mut self)
- fn tahaj(&mut self) -> Option<Karta>
impl HraBlackjack: Hratelna
- fn hraj(&mut self, io: &impl IOManager)
CLI: hraj (cesta k uloženej hre), nove-hry
```
---
## Kľúčové vzory na zapamätanie (cheat sheet)
### 1. Serde JSON čítanie/zápis
```rust
// Čítanie
let obsah = std::fs::read_to_string(&cesta).ok()?;
let data: MojTyp = serde_json::from_str(&obsah).ok()?;
Some(data)
// Zápis
let json = serde_json::to_string_pretty(&self).unwrap_or_default();
std::fs::write(&cesta, json).is_ok()
```
### 2. Vec filtrovanie
```rust
// Referencia
self.polozky.iter().filter(|p| p.nazov == hladany).collect()
// Hľadanie jedného
self.polozky.iter().find(|p| p.nazov == hladany)
// Odstránenie
if let Some(pos) = self.polozky.iter().position(|p| p.nazov == hladany) {
Ok(self.polozky.remove(pos))
} else {
Err(())
}
```
### 3. Display implementácia
```rust
impl std::fmt::Display for MojEnum {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MojEnum::Varianta1 => write!(f, "Text 1"),
MojEnum::Varianta2 => write!(f, "Text 2"),
}
}
}
```
### 4. Clap šablóna
```rust
use clap::{Parser, Subcommand};
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
prikaz: Prikazy,
}
#[derive(Subcommand)]
enum Prikazy {
NazovPrikazu {
cesta: std::path::PathBuf,
argument: String,
},
}
fn main() {
let cli = Cli::parse();
match cli.prikaz {
Prikazy::NazovPrikazu { cesta, argument } => { /* ... */ }
}
}
```
### 5. HashMap štatistiky
```rust
use std::collections::HashMap;
let mut mapa: HashMap<String, usize> = HashMap::new();
for polozka in &self.polozky {
*mapa.entry(polozka.kategoria.clone()).or_insert(0) += 1;
}
for (kluc, pocet) in &mapa {
println!("{}: {}", kluc, pocet);
}
```
### 6. rand
```rust
use rand::seq::SliceRandom;
let mut rng = rand::thread_rng();
let nahodny = vektor.choose(&mut rng);
vektor.shuffle(&mut rng);
```
### 7. Čítanie vstupu z konzoly
```rust
let mut vstup = String::new();
std::io::stdin().read_line(&mut vstup).unwrap();
let vstup = vstup.trim();
// Parsovanie na číslo:
let cislo: usize = vstup.parse().unwrap_or(0);
```
---
## Postup na skúške
1. **Prečítaj celé zadanie** (2 min)
2. **Vytvor `Cargo.toml`** s potrebnými závislosťami (1 min)
3. **Implementuj enumy a štruktúry** s derives v `lib.rs` (10 min)
4. **Implementuj `Display`** pre enumy (5 min)
5. **Implementuj `nacitaj_zo_suboru` + `uloz_do_suboru`** (5 min) — toto je vždy rovnaké!
6. **Implementuj CRUD metódy** (15 min)
7. **Implementuj filtrovacie metódy** (10 min)
8. **Implementuj štatistiky/špeciálne metódy** (10 min)
9. **Implementuj game loop** ak je hra (15 min)
10. **Implementuj CLI v `main.rs`** (15 min)
11. **Testuj s `cargo test`** + manuálne (zvyšok)
**CELKOM: ~90 minút**