1pub fn value_noise_2d(x: i32, y: i32, seed: u32) -> f32 {
3 let h = hash2d(x, y, seed);
4 (h & 0xFFFF) as f32 / 65535.0
5}
6
7pub fn smooth_noise_2d(x: f32, y: f32, seed: u32) -> f32 {
9 let ix = x.floor() as i32;
10 let iy = y.floor() as i32;
11 let fx = x - ix as f32;
12 let fy = y - iy as f32;
13
14 let v00 = value_noise_2d(ix, iy, seed);
15 let v10 = value_noise_2d(ix + 1, iy, seed);
16 let v01 = value_noise_2d(ix, iy + 1, seed);
17 let v11 = value_noise_2d(ix + 1, iy + 1, seed);
18
19 let sx = fx * fx * (3.0 - 2.0 * fx);
20 let sy = fy * fy * (3.0 - 2.0 * fy);
21
22 let top = v00 + (v10 - v00) * sx;
23 let bot = v01 + (v11 - v01) * sx;
24 top + (bot - top) * sy
25}
26
27fn hash2d(x: i32, y: i32, seed: u32) -> u32 {
28 let mut h = seed;
29 h = h.wrapping_add(x as u32).wrapping_mul(0x9E3779B9);
30 h = h.wrapping_add(y as u32).wrapping_mul(0x517CC1B7);
31 h ^= h >> 16;
32 h = h.wrapping_mul(0x85EBCA6B);
33 h ^= h >> 13;
34 h = h.wrapping_mul(0xC2B2AE35);
35 h ^= h >> 16;
36 h
37}
38
39pub fn bsp_rooms(
42 width: usize,
43 height: usize,
44 min_room: usize,
45 seed: u32,
46) -> Vec<(usize, usize, usize, usize)> {
47 let mut rooms = Vec::new();
48 let mut rng_state = seed | 1;
49 bsp_split(0, 0, width, height, min_room, &mut rng_state, &mut rooms);
50 rooms
51}
52
53fn xorshift(state: &mut u32) -> u32 {
54 let mut x = *state;
55 x ^= x << 13;
56 x ^= x >> 17;
57 x ^= x << 5;
58 *state = x;
59 x
60}
61
62fn bsp_split(
63 x: usize,
64 y: usize,
65 w: usize,
66 h: usize,
67 min_room: usize,
68 rng: &mut u32,
69 rooms: &mut Vec<(usize, usize, usize, usize)>,
70) {
71 if w < min_room * 2 && h < min_room * 2 {
72 let margin = 1;
73 let rw = min_room.max(w.saturating_sub(margin * 2));
74 let rh = min_room.max(h.saturating_sub(margin * 2));
75 rooms.push((x + margin.min(w / 2), y + margin.min(h / 2), rw.min(w), rh.min(h)));
76 return;
77 }
78 let split_h = if w < min_room * 2 {
79 true
80 } else if h < min_room * 2 {
81 false
82 } else {
83 xorshift(rng) % 2 == 0
84 };
85 if split_h {
86 let split = min_room + (xorshift(rng) as usize % (h - min_room * 2 + 1).max(1));
87 bsp_split(x, y, w, split, min_room, rng, rooms);
88 bsp_split(x, y + split, w, h - split, min_room, rng, rooms);
89 } else {
90 let split = min_room + (xorshift(rng) as usize % (w - min_room * 2 + 1).max(1));
91 bsp_split(x, y, split, h, min_room, rng, rooms);
92 bsp_split(x + split, y, w - split, h, min_room, rng, rooms);
93 }
94}
95
96pub fn drunkard_walk(width: usize, height: usize, steps: usize, seed: u32) -> Vec<Vec<bool>> {
98 let mut grid = vec![vec![false; width]; height];
99 let mut x = width / 2;
100 let mut y = height / 2;
101 let mut rng_state = seed | 1;
102
103 grid[y][x] = true;
104 for _ in 0..steps {
105 let dir = xorshift(&mut rng_state) % 4;
106 match dir {
107 0 if y > 0 => y -= 1,
108 1 if y + 1 < height => y += 1,
109 2 if x > 0 => x -= 1,
110 3 if x + 1 < width => x += 1,
111 _ => {}
112 }
113 grid[y][x] = true;
114 }
115 grid
116}