use crate::data::Data;
use rand::{Rng, rng, seq::SliceRandom};
pub struct RandomZhOptions {
pub count: Option<usize>,
pub level_range: Option<(u8, u8)>,
pub stroke_count_range: Option<(u8, u8)>,
pub allow_duplicates: bool,
}
impl Default for RandomZhOptions {
fn default() -> Self {
Self {
count: None,
level_range: None,
stroke_count_range: None,
allow_duplicates: false,
}
}
}
pub fn random_zh(options: RandomZhOptions) -> Vec<char> {
let data = Data::new();
let mut candidates: Vec<char> = if let Some((min, max)) = options.level_range {
data.levels
.iter()
.filter(|&(level, _)| *level >= min && *level <= max)
.flat_map(|(_, chars)| chars.clone())
.collect()
} else {
data.levels
.values()
.flat_map(|chars| chars.clone())
.collect()
};
if let Some((min, max)) = options.stroke_count_range {
candidates = candidates
.into_iter()
.filter(|&c| {
data.stroke_counts
.iter()
.any(|(&strokes, chars)| strokes >= min && strokes <= max && chars.contains(&c))
})
.collect();
}
let mut rng = rng();
candidates.shuffle(&mut rng);
let count = options.count.unwrap_or(1);
if options.allow_duplicates {
let mut result = Vec::new();
for _ in 0..count {
if !candidates.is_empty() {
let index = rng.random_range(0..candidates.len());
result.push(candidates[index]);
}
}
result
} else {
candidates.into_iter().take(count).collect()
}
}