1pub mod tectonics;
8pub mod erosion;
9pub mod climate;
10pub mod biomes;
11pub mod rivers;
12pub mod caves;
13pub mod settlements;
14pub mod history;
15pub mod language;
16pub mod mythology;
17pub mod artifacts;
18pub mod genetics;
19
20#[derive(Debug, Clone, Copy)]
22pub struct WorldSeed(pub u64);
23
24impl WorldSeed {
25 pub fn new(seed: u64) -> Self { Self(seed) }
26 pub fn derive(&self, system_id: u32) -> u64 {
28 let mut h = self.0;
29 h ^= system_id as u64;
30 h = h.wrapping_mul(0x517CC1B727220A95);
31 h ^= h >> 32;
32 h
33 }
34}
35
36#[derive(Debug, Clone)]
38pub struct Rng {
39 s: [u64; 4],
40}
41
42impl Rng {
43 pub fn new(seed: u64) -> Self {
44 let mut s = [seed, seed ^ 0xDEADBEEF, seed.wrapping_mul(6364136223846793005), seed ^ 0xCAFEBABE];
45 let mut r = Self { s };
47 for _ in 0..20 { r.next_u64(); }
48 r
49 }
50
51 pub fn next_u64(&mut self) -> u64 {
52 let result = self.s[1].wrapping_mul(5).rotate_left(7).wrapping_mul(9);
53 let t = self.s[1] << 17;
54 self.s[2] ^= self.s[0];
55 self.s[3] ^= self.s[1];
56 self.s[1] ^= self.s[2];
57 self.s[0] ^= self.s[3];
58 self.s[2] ^= t;
59 self.s[3] = self.s[3].rotate_left(45);
60 result
61 }
62
63 pub fn next_f32(&mut self) -> f32 {
64 (self.next_u64() >> 40) as f32 / (1u64 << 24) as f32
65 }
66
67 pub fn next_f64(&mut self) -> f64 {
68 (self.next_u64() >> 11) as f64 / (1u64 << 53) as f64
69 }
70
71 pub fn range_u32(&mut self, min: u32, max: u32) -> u32 {
72 if min >= max { return min; }
73 min + (self.next_u64() % (max - min) as u64) as u32
74 }
75
76 pub fn range_f32(&mut self, min: f32, max: f32) -> f32 {
77 min + self.next_f32() * (max - min)
78 }
79
80 pub fn range_usize(&mut self, min: usize, max: usize) -> usize {
81 if min >= max { return min; }
82 min + (self.next_u64() as usize % (max - min))
83 }
84
85 pub fn gaussian(&mut self) -> f64 {
86 let u1 = self.next_f64().max(1e-15);
87 let u2 = self.next_f64();
88 (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos()
89 }
90
91 pub fn shuffle<T>(&mut self, slice: &mut [T]) {
92 for i in (1..slice.len()).rev() {
93 let j = self.next_u64() as usize % (i + 1);
94 slice.swap(i, j);
95 }
96 }
97
98 pub fn pick<'a, T>(&mut self, slice: &'a [T]) -> Option<&'a T> {
99 if slice.is_empty() { return None; }
100 Some(&slice[self.next_u64() as usize % slice.len()])
101 }
102
103 pub fn coin(&mut self, probability: f32) -> bool {
104 self.next_f32() < probability
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
110pub struct GridPos {
111 pub x: i32,
112 pub y: i32,
113}
114
115impl GridPos {
116 pub fn new(x: i32, y: i32) -> Self { Self { x, y } }
117
118 pub fn neighbors4(&self) -> [GridPos; 4] {
119 [
120 GridPos::new(self.x - 1, self.y),
121 GridPos::new(self.x + 1, self.y),
122 GridPos::new(self.x, self.y - 1),
123 GridPos::new(self.x, self.y + 1),
124 ]
125 }
126
127 pub fn neighbors8(&self) -> [GridPos; 8] {
128 [
129 GridPos::new(self.x - 1, self.y - 1),
130 GridPos::new(self.x, self.y - 1),
131 GridPos::new(self.x + 1, self.y - 1),
132 GridPos::new(self.x - 1, self.y),
133 GridPos::new(self.x + 1, self.y),
134 GridPos::new(self.x - 1, self.y + 1),
135 GridPos::new(self.x, self.y + 1),
136 GridPos::new(self.x + 1, self.y + 1),
137 ]
138 }
139
140 pub fn distance_sq(&self, other: &GridPos) -> i32 {
141 let dx = self.x - other.x;
142 let dy = self.y - other.y;
143 dx * dx + dy * dy
144 }
145}
146
147#[derive(Debug, Clone)]
149pub struct Grid2D {
150 pub width: usize,
151 pub height: usize,
152 pub data: Vec<f32>,
153}
154
155impl Grid2D {
156 pub fn new(width: usize, height: usize) -> Self {
157 Self { width, height, data: vec![0.0; width * height] }
158 }
159
160 pub fn filled(width: usize, height: usize, value: f32) -> Self {
161 Self { width, height, data: vec![value; width * height] }
162 }
163
164 #[inline]
165 pub fn idx(&self, x: usize, y: usize) -> usize { y * self.width + x }
166
167 #[inline]
168 pub fn get(&self, x: usize, y: usize) -> f32 {
169 self.data[y * self.width + x]
170 }
171
172 #[inline]
173 pub fn set(&mut self, x: usize, y: usize, v: f32) {
174 self.data[y * self.width + x] = v;
175 }
176
177 #[inline]
178 pub fn get_clamped(&self, x: i32, y: i32) -> f32 {
179 let cx = x.clamp(0, self.width as i32 - 1) as usize;
180 let cy = y.clamp(0, self.height as i32 - 1) as usize;
181 self.data[cy * self.width + cx]
182 }
183
184 pub fn add(&mut self, x: usize, y: usize, v: f32) {
185 self.data[y * self.width + x] += v;
186 }
187
188 pub fn min_value(&self) -> f32 { self.data.iter().cloned().fold(f32::MAX, f32::min) }
189 pub fn max_value(&self) -> f32 { self.data.iter().cloned().fold(f32::MIN, f32::max) }
190
191 pub fn normalize(&mut self) {
192 let min = self.min_value();
193 let max = self.max_value();
194 let range = (max - min).max(1e-9);
195 for v in &mut self.data { *v = (*v - min) / range; }
196 }
197
198 pub fn sample(&self, x: f32, y: f32) -> f32 {
200 let x0 = (x.floor() as i32).clamp(0, self.width as i32 - 2) as usize;
201 let y0 = (y.floor() as i32).clamp(0, self.height as i32 - 2) as usize;
202 let tx = x.fract().clamp(0.0, 1.0);
203 let ty = y.fract().clamp(0.0, 1.0);
204 let v00 = self.get(x0, y0);
205 let v10 = self.get(x0 + 1, y0);
206 let v01 = self.get(x0, y0 + 1);
207 let v11 = self.get(x0 + 1, y0 + 1);
208 let a = v00 + tx * (v10 - v00);
209 let b = v01 + tx * (v11 - v01);
210 a + ty * (b - a)
211 }
212
213 pub fn gradient(&self, x: usize, y: usize) -> (f32, f32) {
215 let left = self.get_clamped(x as i32 - 1, y as i32);
216 let right = self.get_clamped(x as i32 + 1, y as i32);
217 let down = self.get_clamped(x as i32, y as i32 - 1);
218 let up = self.get_clamped(x as i32, y as i32 + 1);
219 ((right - left) * 0.5, (up - down) * 0.5)
220 }
221}
222
223#[derive(Debug, Clone)]
225pub struct WorldGenParams {
226 pub seed: WorldSeed,
227 pub grid_size: usize,
228 pub num_plates: usize,
229 pub erosion_iterations: usize,
230 pub climate_iterations: usize,
231 pub history_years: usize,
232 pub num_civilizations: usize,
233 pub num_languages: usize,
234 pub sea_level: f32,
235}
236
237impl Default for WorldGenParams {
238 fn default() -> Self {
239 Self {
240 seed: WorldSeed(42),
241 grid_size: 256,
242 num_plates: 12,
243 erosion_iterations: 50000,
244 climate_iterations: 100,
245 history_years: 5000,
246 num_civilizations: 8,
247 num_languages: 6,
248 sea_level: 0.4,
249 }
250 }
251}
252
253#[derive(Debug, Clone)]
255pub struct GeneratedWorld {
256 pub params: WorldGenParams,
257 pub heightmap: Grid2D,
258 pub plates: tectonics::PlateMap,
259 pub temperature: Grid2D,
260 pub precipitation: Grid2D,
261 pub biome_map: biomes::BiomeMap,
262 pub river_network: rivers::RiverNetwork,
263 pub cave_systems: Vec<caves::CaveSystem>,
264 pub settlements: Vec<settlements::Settlement>,
265 pub civilizations: Vec<history::Civilization>,
266 pub languages: Vec<language::Language>,
267 pub myths: Vec<mythology::Myth>,
268 pub artifacts: Vec<artifacts::Artifact>,
269}
270
271pub fn generate_world(params: WorldGenParams) -> GeneratedWorld {
273 let mut rng = Rng::new(params.seed.0);
274 let sz = params.grid_size;
275
276 let (heightmap, plates) = tectonics::generate(sz, params.num_plates, &mut rng);
278
279 let heightmap = erosion::erode(heightmap, params.erosion_iterations, &mut rng);
281
282 let (temperature, precipitation) = climate::simulate(&heightmap, params.climate_iterations, &mut rng);
284
285 let biome_map = biomes::classify(&heightmap, &temperature, &precipitation, params.sea_level);
287
288 let river_network = rivers::generate(&heightmap, &precipitation, params.sea_level);
290
291 let cave_systems = caves::generate(sz, 5, &mut rng);
293
294 let settlements = settlements::place(
296 &heightmap, &biome_map, &river_network, params.num_civilizations * 3, &mut rng,
297 );
298
299 let civilizations = history::simulate(
301 &settlements, &biome_map, params.history_years, params.num_civilizations, &mut rng,
302 );
303
304 let languages = language::generate(params.num_languages, &civilizations, &mut rng);
306
307 let myths = mythology::generate(&civilizations, &languages, &mut rng);
309
310 let artifacts = artifacts::generate(&civilizations, &myths, &mut rng);
312
313 GeneratedWorld {
314 params,
315 heightmap,
316 plates,
317 temperature,
318 precipitation,
319 biome_map,
320 river_network,
321 cave_systems,
322 settlements,
323 civilizations,
324 languages,
325 myths,
326 artifacts,
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_rng_deterministic() {
336 let mut a = Rng::new(42);
337 let mut b = Rng::new(42);
338 for _ in 0..100 {
339 assert_eq!(a.next_u64(), b.next_u64());
340 }
341 }
342
343 #[test]
344 fn test_rng_range() {
345 let mut r = Rng::new(123);
346 for _ in 0..1000 {
347 let v = r.range_f32(0.0, 1.0);
348 assert!(v >= 0.0 && v <= 1.0);
349 }
350 }
351
352 #[test]
353 fn test_grid2d() {
354 let mut g = Grid2D::new(4, 4);
355 g.set(2, 3, 1.0);
356 assert_eq!(g.get(2, 3), 1.0);
357 assert_eq!(g.get(0, 0), 0.0);
358 }
359
360 #[test]
361 fn test_grid2d_normalize() {
362 let mut g = Grid2D::new(4, 4);
363 g.set(0, 0, -5.0);
364 g.set(3, 3, 10.0);
365 g.normalize();
366 assert!((g.get(0, 0) - 0.0).abs() < 0.01);
367 assert!((g.get(3, 3) - 1.0).abs() < 0.01);
368 }
369
370 #[test]
371 fn test_world_seed_derive() {
372 let seed = WorldSeed(42);
373 let a = seed.derive(1);
374 let b = seed.derive(2);
375 assert_ne!(a, b);
376 }
377}