1use super::Rng;
7use super::history::Civilization;
8
9#[derive(Debug, Clone)]
11pub struct Phonology {
12 pub consonants: Vec<char>,
13 pub vowels: Vec<char>,
14 pub syllable_patterns: Vec<String>,
16 pub forbidden_clusters: Vec<String>,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum WordClass { Noun, Verb, Adjective, Adverb, Preposition, Article, Pronoun, Conjunction }
23
24#[derive(Debug, Clone)]
26pub struct Word {
27 pub form: String,
28 pub class: WordClass,
29 pub meaning: String,
30 pub root: String,
31}
32
33#[derive(Debug, Clone)]
35pub struct Morphology {
36 pub plural_suffix: String,
37 pub past_suffix: String,
38 pub future_prefix: String,
39 pub negation_prefix: String,
40 pub diminutive_suffix: String,
41 pub augmentative_suffix: String,
42 pub adjective_suffix: String,
43 pub adverb_suffix: String,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum WordOrder { SVO, SOV, VSO, VOS, OVS, OSV }
49
50#[derive(Debug, Clone)]
52pub struct Syntax {
53 pub word_order: WordOrder,
54 pub adjective_before_noun: bool,
55 pub postpositions: bool,
56 pub head_final: bool,
57}
58
59#[derive(Debug, Clone)]
61pub struct Language {
62 pub id: u32,
63 pub name: String,
64 pub phonology: Phonology,
65 pub morphology: Morphology,
66 pub syntax: Syntax,
67 pub vocabulary: Vec<Word>,
68 pub owner_civ: u32,
69}
70
71impl Language {
72 pub fn generate_word(&self, rng: &mut Rng, syllables: usize) -> String {
74 let mut word = String::new();
75 for _ in 0..syllables {
76 if let Some(pattern) = rng.pick(&self.phonology.syllable_patterns) {
77 for ch in pattern.chars() {
78 match ch {
79 'C' => {
80 if let Some(&c) = rng.pick(&self.phonology.consonants) {
81 word.push(c);
82 }
83 }
84 'V' => {
85 if let Some(&v) = rng.pick(&self.phonology.vowels) {
86 word.push(v);
87 }
88 }
89 _ => word.push(ch),
90 }
91 }
92 }
93 }
94 word
95 }
96
97 pub fn pluralize(&self, word: &str) -> String {
99 format!("{}{}", word, self.morphology.plural_suffix)
100 }
101
102 pub fn past_tense(&self, word: &str) -> String {
104 format!("{}{}", word, self.morphology.past_suffix)
105 }
106
107 pub fn simple_sentence(&self, subject: &str, verb: &str, object: &str) -> String {
109 match self.syntax.word_order {
110 WordOrder::SVO => format!("{} {} {}", subject, verb, object),
111 WordOrder::SOV => format!("{} {} {}", subject, object, verb),
112 WordOrder::VSO => format!("{} {} {}", verb, subject, object),
113 WordOrder::VOS => format!("{} {} {}", verb, object, subject),
114 WordOrder::OVS => format!("{} {} {}", object, verb, subject),
115 WordOrder::OSV => format!("{} {} {}", object, subject, verb),
116 }
117 }
118}
119
120pub fn generate(num_languages: usize, civs: &[Civilization], rng: &mut Rng) -> Vec<Language> {
122 let mut languages = Vec::with_capacity(num_languages);
123
124 for i in 0..num_languages {
125 let phonology = generate_phonology(rng);
126 let morphology = generate_morphology(&phonology, rng);
127 let syntax = generate_syntax(rng);
128
129 let mut lang = Language {
130 id: i as u32,
131 name: String::new(),
132 phonology,
133 morphology,
134 syntax,
135 vocabulary: Vec::new(),
136 owner_civ: civs.get(i).map(|c| c.id).unwrap_or(i as u32),
137 };
138
139 let concepts = [
141 ("sun", WordClass::Noun), ("moon", WordClass::Noun), ("water", WordClass::Noun),
142 ("fire", WordClass::Noun), ("earth", WordClass::Noun), ("sky", WordClass::Noun),
143 ("mountain", WordClass::Noun), ("river", WordClass::Noun), ("forest", WordClass::Noun),
144 ("sea", WordClass::Noun), ("wind", WordClass::Noun), ("stone", WordClass::Noun),
145 ("tree", WordClass::Noun), ("star", WordClass::Noun), ("rain", WordClass::Noun),
146 ("snow", WordClass::Noun), ("life", WordClass::Noun), ("death", WordClass::Noun),
147 ("war", WordClass::Noun), ("peace", WordClass::Noun), ("king", WordClass::Noun),
148 ("god", WordClass::Noun), ("hero", WordClass::Noun), ("beast", WordClass::Noun),
149 ("sword", WordClass::Noun), ("shield", WordClass::Noun), ("home", WordClass::Noun),
150 ("walk", WordClass::Verb), ("fight", WordClass::Verb), ("speak", WordClass::Verb),
151 ("see", WordClass::Verb), ("hear", WordClass::Verb), ("make", WordClass::Verb),
152 ("give", WordClass::Verb), ("take", WordClass::Verb), ("live", WordClass::Verb),
153 ("die", WordClass::Verb), ("love", WordClass::Verb), ("hate", WordClass::Verb),
154 ("big", WordClass::Adjective), ("small", WordClass::Adjective),
155 ("old", WordClass::Adjective), ("new", WordClass::Adjective),
156 ("good", WordClass::Adjective), ("bad", WordClass::Adjective),
157 ("dark", WordClass::Adjective), ("bright", WordClass::Adjective),
158 ];
159
160 for (meaning, class) in &concepts {
161 let syllables = rng.range_usize(1, 4);
162 let form = lang.generate_word(rng, syllables);
163 lang.vocabulary.push(Word {
164 form: form.clone(),
165 class: *class,
166 meaning: meaning.to_string(),
167 root: form,
168 });
169 }
170
171 lang.name = lang.generate_word(rng, 2);
173 lang.name = capitalize(&lang.name);
174
175 languages.push(lang);
176 }
177
178 languages
179}
180
181fn generate_phonology(rng: &mut Rng) -> Phonology {
182 let all_consonants: Vec<char> = "ptknmslrwjfvbdgzhʃ".chars().collect();
183 let all_vowels: Vec<char> = "aeiouəæɛɔ".chars().collect();
184
185 let num_c = rng.range_usize(8, 16);
187 let num_v = rng.range_usize(3, 7);
188 let mut consonants: Vec<char> = all_consonants.clone();
189 rng.shuffle(&mut consonants);
190 consonants.truncate(num_c);
191 let mut vowels: Vec<char> = all_vowels.clone();
192 rng.shuffle(&mut vowels);
193 vowels.truncate(num_v);
194
195 let all_patterns = vec![
196 "CV".to_string(), "CVC".to_string(), "VC".to_string(), "V".to_string(),
197 "CCV".to_string(), "CVCC".to_string(), "CCVC".to_string(),
198 ];
199 let num_patterns = rng.range_usize(2, 5);
200 let mut patterns = all_patterns.clone();
201 rng.shuffle(&mut patterns);
202 patterns.truncate(num_patterns);
203 if !patterns.contains(&"CV".to_string()) { patterns.push("CV".to_string()); }
205
206 Phonology { consonants, vowels, syllable_patterns: patterns, forbidden_clusters: Vec::new() }
207}
208
209fn generate_morphology(phon: &Phonology, rng: &mut Rng) -> Morphology {
210 let gen_suffix = |rng: &mut Rng, phon: &Phonology| -> String {
211 let v = phon.vowels[rng.next_u64() as usize % phon.vowels.len()];
212 let c = phon.consonants[rng.next_u64() as usize % phon.consonants.len()];
213 if rng.coin(0.5) { format!("{}{}", v, c) } else { format!("{}", v) }
214 };
215
216 Morphology {
217 plural_suffix: gen_suffix(rng, phon),
218 past_suffix: gen_suffix(rng, phon),
219 future_prefix: gen_suffix(rng, phon),
220 negation_prefix: gen_suffix(rng, phon),
221 diminutive_suffix: gen_suffix(rng, phon),
222 augmentative_suffix: gen_suffix(rng, phon),
223 adjective_suffix: gen_suffix(rng, phon),
224 adverb_suffix: gen_suffix(rng, phon),
225 }
226}
227
228fn generate_syntax(rng: &mut Rng) -> Syntax {
229 let order = match rng.range_u32(0, 6) {
230 0 => WordOrder::SVO,
231 1 => WordOrder::SOV,
232 2 => WordOrder::VSO,
233 3 => WordOrder::VOS,
234 4 => WordOrder::OVS,
235 _ => WordOrder::OSV,
236 };
237 Syntax {
238 word_order: order,
239 adjective_before_noun: rng.coin(0.5),
240 postpositions: matches!(order, WordOrder::SOV | WordOrder::OSV),
241 head_final: matches!(order, WordOrder::SOV | WordOrder::OVS),
242 }
243}
244
245fn capitalize(s: &str) -> String {
246 let mut c = s.chars();
247 match c.next() {
248 None => String::new(),
249 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn test_generate_languages() {
259 let civs = vec![]; let mut rng = Rng::new(42);
261 let langs = generate(3, &civs, &mut rng);
262 assert_eq!(langs.len(), 3);
263 for lang in &langs {
264 assert!(!lang.name.is_empty());
265 assert!(!lang.vocabulary.is_empty());
266 assert!(!lang.phonology.consonants.is_empty());
267 assert!(!lang.phonology.vowels.is_empty());
268 }
269 }
270
271 #[test]
272 fn test_word_generation() {
273 let mut rng = Rng::new(42);
274 let civs = vec![];
275 let langs = generate(1, &civs, &mut rng);
276 let word = langs[0].generate_word(&mut rng, 3);
277 assert!(!word.is_empty());
278 }
279
280 #[test]
281 fn test_sentence_construction() {
282 let mut rng = Rng::new(42);
283 let civs = vec![];
284 let langs = generate(1, &civs, &mut rng);
285 let sentence = langs[0].simple_sentence("warrior", "fights", "beast");
286 assert!(sentence.contains("warrior"));
287 assert!(sentence.contains("fights"));
288 assert!(sentence.contains("beast"));
289 }
290}