1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
//! The linguistic genome - the complete "DNA" of a language.
use crate::culture::{CulturalProfile, Geography};
use crate::phonology::{Consonant, PhonemeInventory, ProsodicSystem, SyllableStructure, Vowel};
/// Word order patterns.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WordOrder {
/// Subject-Verb-Object (English, Mandarin)
SVO,
/// Subject-Object-Verb (Japanese, Turkish)
SOV,
/// Verb-Subject-Object (Irish, Arabic)
VSO,
/// Verb-Object-Subject (Malagasy)
VOS,
/// Object-Verb-Subject (rare)
OVS,
/// Object-Subject-Verb (very rare)
OSV,
}
/// Morphological type of the language.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MorphologyType {
/// Words are typically single morphemes (Chinese, Vietnamese)
Isolating,
/// Words are formed by stringing together morphemes (Turkish, Japanese)
Agglutinative,
/// Morphemes are fused together (Latin, Russian)
Fusional,
}
/// The complete linguistic genome - all parameters needed to generate consistent output.
#[derive(Debug, Clone)]
pub struct LinguisticGenome {
/// The phoneme inventory (available sounds)
pub phoneme_inventory: PhonemeInventory,
/// Allowed syllable patterns
pub syllable_patterns: Vec<SyllableStructure>,
/// Prosodic system (stress, tone)
pub prosody: ProsodicSystem,
/// Morphological type
pub morphology_type: MorphologyType,
/// Word order
pub word_order: WordOrder,
/// Generation seed for determinism
pub seed: u64,
}
impl LinguisticGenome {
/// Generate a genome from cultural parameters and geography.
pub fn from_culture(culture: CulturalProfile, geography: Geography, seed: u64) -> Self {
let phoneme_inventory = Self::generate_phoneme_inventory(&culture, &geography);
let syllable_patterns = Self::generate_syllable_patterns(&culture, &geography);
let word_order = Self::determine_word_order(&culture, seed);
let morphology_type = Self::determine_morphology(&culture);
Self {
phoneme_inventory,
syllable_patterns,
prosody: ProsodicSystem::default(),
morphology_type,
word_order,
seed,
}
}
/// Generate phoneme inventory based on cultural traits and geography.
fn generate_phoneme_inventory(
culture: &CulturalProfile,
geography: &Geography,
) -> PhonemeInventory {
let agreeableness = culture.normalized_agreeableness();
let openness = culture.normalized_openness();
let _emotionality = culture.normalized_emotionality();
// Base consonants that most languages have
let mut stops = vec![
Consonant::new("p"),
Consonant::new("t"),
Consonant::new("k"),
];
let mut fricatives = vec![Consonant::new("s"), Consonant::new("h")];
let mut nasals = vec![Consonant::new("m"), Consonant::new("n")];
let liquids = vec![Consonant::new("l"), Consonant::new("r")];
let glides = vec![];
// Adjust based on geography
match geography {
Geography::Mountains => {
// Add ejectives and glottal stops
stops.push(Consonant::new("kʼ"));
stops.push(Consonant::new("tʼ"));
fricatives.push(Consonant::new("x"));
fricatives.push(Consonant::new("ʃ"));
}
Geography::Coastal => {
// More liquids and soft sounds
fricatives.push(Consonant::new("f"));
fricatives.push(Consonant::new("v"));
}
Geography::Desert => {
// Guttural and emphatic consonants
stops.push(Consonant::new("q"));
fricatives.push(Consonant::new("ʃ"));
fricatives.push(Consonant::new("x"));
fricatives.push(Consonant::new("ħ"));
fricatives.push(Consonant::new("ʕ"));
}
Geography::Forest => {
// Softer sounds, more nasals
fricatives.push(Consonant::new("f"));
nasals.push(Consonant::new("ŋ"));
}
Geography::RiverValley | Geography::Plains => {
// Balanced inventory
stops.push(Consonant::new("b"));
stops.push(Consonant::new("d"));
stops.push(Consonant::new("g"));
fricatives.push(Consonant::new("f"));
fricatives.push(Consonant::new("v"));
fricatives.push(Consonant::new("z"));
fricatives.push(Consonant::new("ʃ"));
fricatives.push(Consonant::new("ʒ"));
}
}
// Base vowels
let mut vowels = vec![
Vowel::new("a"),
Vowel::new("i"),
Vowel::new("u"),
];
// Add more vowels for high openness
if openness > 0.5 {
vowels.push(Vowel::new("e"));
vowels.push(Vowel::new("o"));
}
if openness > 0.7 {
vowels.push(Vowel::new("ə"));
}
// Weight calculation
// High agreeableness = more nasals and liquids
// Low agreeableness = more stops
let nasal_weight = 0.15 + agreeableness * 0.15;
let liquid_weight = 0.15 + agreeableness * 0.15;
let stop_weight = 0.30 - agreeableness * 0.10;
let fricative_weight = 0.25;
let glide_weight = 0.10;
let category_weights = vec![
stop_weight,
fricative_weight,
nasal_weight,
liquid_weight,
glide_weight,
];
PhonemeInventory {
stops,
fricatives,
nasals,
liquids,
glides,
vowels,
category_weights,
}
}
/// Generate syllable patterns based on cultural traits.
fn generate_syllable_patterns(
culture: &CulturalProfile,
geography: &Geography,
) -> Vec<SyllableStructure> {
let openness = culture.normalized_openness();
let emotionality = culture.normalized_emotionality();
let conscientiousness = culture.normalized_conscientiousness();
let mut patterns = vec![
SyllableStructure::CV, // Universal - all languages have this
SyllableStructure::CVC,
];
// High emotionality = more vowels
if emotionality > 0.5 {
patterns.push(SyllableStructure::V);
patterns.push(SyllableStructure::CVV);
}
// High openness = more complex patterns
if openness > 0.5 {
patterns.push(SyllableStructure::CCV);
patterns.push(SyllableStructure::CCVC);
}
if openness > 0.7 {
patterns.push(SyllableStructure::CVCC);
patterns.push(SyllableStructure::VCC);
}
// Low conscientiousness = add some irregular patterns
if conscientiousness < 0.3 {
patterns.push(SyllableStructure::VC);
}
// Geography influences
match geography {
Geography::Mountains => {
// Prefer closed syllables (ending in consonants)
patterns.push(SyllableStructure::CVC);
patterns.push(SyllableStructure::CCVC);
}
Geography::Coastal => {
// More open syllables
patterns.push(SyllableStructure::CV);
patterns.push(SyllableStructure::V);
patterns.push(SyllableStructure::CVV);
}
_ => {}
}
patterns
}
/// Determine word order based on culture.
fn determine_word_order(culture: &CulturalProfile, seed: u64) -> WordOrder {
use crate::seeded_rng::SeededRng;
let conscientiousness = culture.normalized_conscientiousness();
// High conscientiousness tends toward SOV (structured, verb at end)
// Low conscientiousness tends toward VSO or VOS (verb-initial)
// Medium tends toward SVO (most common cross-linguistically)
let mut rng = SeededRng::new(seed.wrapping_mul(7919));
if conscientiousness > 0.7 {
// Prefer SOV
if rng.next() < 0.8 {
WordOrder::SOV
} else {
WordOrder::SVO
}
} else if conscientiousness < 0.3 {
// Prefer VSO
if rng.next() < 0.7 {
WordOrder::VSO
} else {
WordOrder::VOS
}
} else {
// Prefer SVO
if rng.next() < 0.7 {
WordOrder::SVO
} else if rng.next() < 0.5 {
WordOrder::SOV
} else {
WordOrder::VSO
}
}
}
/// Determine morphology type.
fn determine_morphology(culture: &CulturalProfile) -> MorphologyType {
let conscientiousness = culture.normalized_conscientiousness();
let openness = culture.normalized_openness();
// High conscientiousness + high openness = agglutinative (regular but complex)
// High conscientiousness + low openness = isolating (regular and simple)
// Low conscientiousness = fusional (irregular)
if conscientiousness > 0.6 {
if openness > 0.6 {
MorphologyType::Agglutinative
} else {
MorphologyType::Isolating
}
} else {
MorphologyType::Fusional
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_genome_generation() {
let culture = CulturalProfile::new(4.0, 3.0, 2.0, 3.0, 3.0, 4.0);
let genome = LinguisticGenome::from_culture(culture, Geography::Coastal, 12345);
assert!(!genome.phoneme_inventory.vowels.is_empty());
assert!(!genome.syllable_patterns.is_empty());
}
#[test]
fn test_deterministic_word_order() {
let culture = CulturalProfile::new(3.0, 3.0, 3.0, 3.0, 3.0, 3.0);
let genome1 = LinguisticGenome::from_culture(culture, Geography::Plains, 12345);
let genome2 = LinguisticGenome::from_culture(culture, Geography::Plains, 12345);
assert_eq!(genome1.word_order, genome2.word_order);
}
#[test]
fn test_different_geographies() {
let culture = CulturalProfile::new(3.0, 3.0, 3.0, 3.0, 3.0, 3.0);
let coastal = LinguisticGenome::from_culture(culture, Geography::Coastal, 12345);
let mountain = LinguisticGenome::from_culture(culture, Geography::Mountains, 12345);
// Different geographies should produce different phoneme inventories
// Mountains add ejectives to stops, so they should have more stops
assert_ne!(
coastal.phoneme_inventory.stops.len(),
mountain.phoneme_inventory.stops.len()
);
}
}