random_zh/random_zh.rs
1use crate::data::Data;
2use rand::{Rng, rng, seq::SliceRandom};
3
4/// Options for the `random_zh` function.
5///
6/// # Fields
7/// - `count` (Optional): The number of random characters to generate. Defaults to 1 if not specified.
8/// - `level_range` (Optional): A range of levels (e.g., `[1, 3]`) to filter the characters.
9/// - `stroke_count_range` (Optional): A range of stroke counts (e.g., `[5, 10]`) to filter the characters.
10/// - `allow_duplicates` (Default: `false`): Whether duplicate characters are allowed in the result.
11pub struct RandomZhOptions {
12 pub count: Option<usize>,
13 pub level_range: Option<(u8, u8)>,
14 pub stroke_count_range: Option<(u8, u8)>,
15 pub allow_duplicates: bool,
16}
17
18impl Default for RandomZhOptions {
19 fn default() -> Self {
20 Self {
21 count: None,
22 level_range: None,
23 stroke_count_range: None,
24 allow_duplicates: false,
25 }
26 }
27}
28
29/// Generates random Chinese characters based on the specified options.
30///
31/// # Arguments
32/// - `options` (RandomZhOptions): Configuration for generating random characters.
33///
34/// # Returns
35/// A `Vec<char>` containing the randomly generated characters.
36///
37/// # Examples
38/// ```
39/// use random_zh::{random_zh, RandomZhOptions};
40///
41/// // Generate 1 random characters.
42/// let chars = random_zh(RandomZhOptions {
43/// ..Default::default()
44/// });
45/// println!("{:?}", chars);
46///
47/// // Generate 5 random characters.
48/// let chars = random_zh(RandomZhOptions {
49/// count: Some(5),
50/// ..Default::default()
51/// });
52/// println!("{:?}", chars);
53///
54/// // Generate characters with a specific level range.
55/// let chars = random_zh(RandomZhOptions {
56/// level_range: Some((1, 1)), // (1, 2), (2, 3), etc.
57/// ..Default::default()
58/// });
59/// println!("{:?}", chars);
60///
61/// // Generate characters with a specific stroke count range.
62/// let chars = random_zh(RandomZhOptions {
63/// stroke_count_range: Some((1, 36)), // (1, 6), (10, 10), etc.
64/// ..Default::default()
65/// });
66///
67/// // Generate characters with a stroke count range and allow duplicates.
68/// let chars = random_zh(RandomZhOptions {
69/// count: Some(50),
70/// level_range: Some((1, 3)),
71/// stroke_count_range: Some((1, 36)),
72/// allow_duplicates: true,
73/// });
74/// println!("{:?}", chars);
75/// ```
76pub fn random_zh(options: RandomZhOptions) -> Vec<char> {
77 // Load data
78 let data = Data::new();
79
80 // Filter characters by level range
81 let mut candidates: Vec<char> = if let Some((min, max)) = options.level_range {
82 data.levels
83 .iter()
84 .filter(|&(level, _)| *level >= min && *level <= max)
85 .flat_map(|(_, chars)| chars.clone())
86 .collect()
87 } else {
88 data.levels
89 .values()
90 .flat_map(|chars| chars.clone())
91 .collect()
92 };
93
94 // Further filter by stroke count range
95 if let Some((min, max)) = options.stroke_count_range {
96 candidates = candidates
97 .into_iter()
98 .filter(|&c| {
99 data.stroke_counts
100 .iter()
101 .any(|(&strokes, chars)| strokes >= min && strokes <= max && chars.contains(&c))
102 })
103 .collect();
104 }
105
106 // Shuffle the candidates
107 let mut rng = rng();
108 candidates.shuffle(&mut rng);
109
110 let count = options.count.unwrap_or(1);
111
112 if options.allow_duplicates {
113 // Allow duplicates: Repeat characters as needed
114 let mut result = Vec::new();
115 for _ in 0..count {
116 if !candidates.is_empty() {
117 let index = rng.random_range(0..candidates.len());
118 result.push(candidates[index]);
119 }
120 }
121 result
122 } else {
123 // No duplicates: Take unique characters only
124 candidates.into_iter().take(count).collect()
125 }
126}