terrain_forge/algorithms/
rooms.rs1use crate::{Algorithm, Grid, Rng, Tile};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct SimpleRoomsConfig {
7 pub min_room_size: usize,
9 pub max_room_size: usize,
11 pub max_rooms: usize,
13 pub min_spacing: usize,
15}
16
17impl Default for SimpleRoomsConfig {
18 fn default() -> Self {
19 Self {
20 min_room_size: 4,
21 max_room_size: 10,
22 max_rooms: 10,
23 min_spacing: 1,
24 }
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct SimpleRooms {
31 config: SimpleRoomsConfig,
32}
33
34impl SimpleRooms {
35 pub fn new(config: SimpleRoomsConfig) -> Self {
37 Self { config }
38 }
39}
40
41impl Default for SimpleRooms {
42 fn default() -> Self {
43 Self::new(SimpleRoomsConfig::default())
44 }
45}
46
47struct Room {
48 x: usize,
49 y: usize,
50 w: usize,
51 h: usize,
52}
53
54impl Room {
55 fn intersects(&self, other: &Room, spacing: usize) -> bool {
56 let s = spacing as i32;
57 !((self.x as i32 + self.w as i32 + s) < other.x as i32
58 || (other.x as i32 + other.w as i32 + s) < self.x as i32
59 || (self.y as i32 + self.h as i32 + s) < other.y as i32
60 || (other.y as i32 + other.h as i32 + s) < self.y as i32)
61 }
62 fn center(&self) -> (usize, usize) {
63 (self.x + self.w / 2, self.y + self.h / 2)
64 }
65}
66
67impl Algorithm<Tile> for SimpleRooms {
68 fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
69 let mut rng = Rng::new(seed);
70 let mut rooms: Vec<Room> = Vec::new();
71 let cfg = &self.config;
72
73 for _ in 0..cfg.max_rooms * 3 {
74 if rooms.len() >= cfg.max_rooms {
75 break;
76 }
77
78 let w = rng.range_usize(cfg.min_room_size, cfg.max_room_size + 1);
79 let h = rng.range_usize(cfg.min_room_size, cfg.max_room_size + 1);
80 if w + 2 >= grid.width() || h + 2 >= grid.height() {
81 continue;
82 }
83
84 let x = rng.range_usize(1, grid.width() - w - 1);
85 let y = rng.range_usize(1, grid.height() - h - 1);
86 let room = Room { x, y, w, h };
87
88 if rooms.iter().any(|r| r.intersects(&room, cfg.min_spacing)) {
89 continue;
90 }
91
92 grid.fill_rect(x as i32, y as i32, w, h, Tile::Floor);
93
94 if let Some(prev) = rooms.last() {
95 let (cx, cy) = room.center();
96 let (px, py) = prev.center();
97 if rng.chance(0.5) {
98 carve_h(grid, px, cx, py);
99 carve_v(grid, py, cy, cx);
100 } else {
101 carve_v(grid, py, cy, px);
102 carve_h(grid, px, cx, cy);
103 }
104 }
105 rooms.push(room);
106 }
107 }
108
109 fn name(&self) -> &'static str {
110 "SimpleRooms"
111 }
112}
113
114fn carve_h(grid: &mut Grid<Tile>, x1: usize, x2: usize, y: usize) {
115 for x in x1.min(x2)..=x1.max(x2) {
116 grid.set(x as i32, y as i32, Tile::Floor);
117 }
118}
119
120fn carve_v(grid: &mut Grid<Tile>, y1: usize, y2: usize, x: usize) {
121 for y in y1.min(y2)..=y1.max(y2) {
122 grid.set(x as i32, y as i32, Tile::Floor);
123 }
124}