1use serde::{Deserialize, Serialize};
19use std::fmt;
20use std::ops::{Index, IndexMut};
21
22pub trait Cell: Clone + Default {
27 fn is_passable(&self) -> bool;
29 fn set_passable(&mut self) {}
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash, Serialize, Deserialize)]
35pub enum Tile {
36 #[default]
38 Wall,
39 Floor,
41}
42
43impl Tile {
44 pub fn is_wall(&self) -> bool {
46 matches!(self, Tile::Wall)
47 }
48 pub fn is_floor(&self) -> bool {
50 matches!(self, Tile::Floor)
51 }
52}
53
54impl Cell for Tile {
55 fn is_passable(&self) -> bool {
56 self.is_floor()
57 }
58 fn set_passable(&mut self) {
59 *self = Tile::Floor;
60 }
61}
62
63#[derive(Debug, Clone)]
79pub struct Grid<C: Cell = Tile> {
80 width: usize,
81 height: usize,
82 cells: Vec<C>,
83}
84
85impl<C: Cell> Grid<C> {
86 #[must_use]
88 pub fn new(width: usize, height: usize) -> Self {
89 Self {
90 width,
91 height,
92 cells: vec![C::default(); width * height],
93 }
94 }
95
96 #[must_use]
98 #[inline]
99 pub fn width(&self) -> usize {
100 self.width
101 }
102 #[must_use]
104 #[inline]
105 pub fn height(&self) -> usize {
106 self.height
107 }
108
109 #[must_use]
111 #[inline]
112 pub fn in_bounds(&self, x: i32, y: i32) -> bool {
113 x >= 0 && y >= 0 && (x as usize) < self.width && (y as usize) < self.height
114 }
115
116 #[must_use]
118 #[inline]
119 pub fn get(&self, x: i32, y: i32) -> Option<&C> {
120 if self.in_bounds(x, y) {
121 Some(&self.cells[y as usize * self.width + x as usize])
122 } else {
123 None
124 }
125 }
126
127 #[inline]
129 pub fn get_mut(&mut self, x: i32, y: i32) -> Option<&mut C> {
130 if self.in_bounds(x, y) {
131 Some(&mut self.cells[y as usize * self.width + x as usize])
132 } else {
133 None
134 }
135 }
136
137 #[inline]
139 pub fn set(&mut self, x: i32, y: i32, cell: C) -> bool {
140 if self.in_bounds(x, y) {
141 self.cells[y as usize * self.width + x as usize] = cell;
142 true
143 } else {
144 false
145 }
146 }
147
148 pub fn fill(&mut self, cell: C) {
150 self.cells.fill(cell);
151 }
152
153 pub fn fill_rect(&mut self, x: i32, y: i32, w: usize, h: usize, cell: C) {
155 for dy in 0..h {
156 for dx in 0..w {
157 self.set(x + dx as i32, y + dy as i32, cell.clone());
158 }
159 }
160 }
161
162 #[must_use]
164 pub fn count<F: Fn(&C) -> bool>(&self, predicate: F) -> usize {
165 self.cells.iter().filter(|c| predicate(c)).count()
166 }
167
168 pub fn iter(&self) -> impl Iterator<Item = (usize, usize, &C)> {
170 self.cells
171 .iter()
172 .enumerate()
173 .map(move |(i, c)| (i % self.width, i / self.width, c))
174 }
175
176 pub fn flood_fill(&self, sx: usize, sy: usize) -> Vec<(usize, usize)> {
178 let (w, h) = (self.width, self.height);
179 if sx >= w || sy >= h || !self[(sx, sy)].is_passable() {
180 return Vec::new();
181 }
182 let mut visited = vec![false; w * h];
183 let mut stack = vec![(sx, sy)];
184 let mut cells = Vec::new();
185 while let Some((x, y)) = stack.pop() {
186 let idx = y * w + x;
187 if visited[idx] {
188 continue;
189 }
190 visited[idx] = true;
191 cells.push((x, y));
192 if x > 0 && self[(x - 1, y)].is_passable() {
193 stack.push((x - 1, y));
194 }
195 if x + 1 < w && self[(x + 1, y)].is_passable() {
196 stack.push((x + 1, y));
197 }
198 if y > 0 && self[(x, y - 1)].is_passable() {
199 stack.push((x, y - 1));
200 }
201 if y + 1 < h && self[(x, y + 1)].is_passable() {
202 stack.push((x, y + 1));
203 }
204 }
205 cells
206 }
207
208 pub fn flood_regions(&self) -> Vec<Vec<(usize, usize)>> {
210 let (w, h) = (self.width, self.height);
211 let mut visited = vec![false; w * h];
212 let mut regions = Vec::new();
213 for y in 0..h {
214 for x in 0..w {
215 let idx = y * w + x;
216 if !visited[idx] && self[(x, y)].is_passable() {
217 let mut stack = vec![(x, y)];
218 let mut region = Vec::new();
219 while let Some((cx, cy)) = stack.pop() {
220 let ci = cy * w + cx;
221 if visited[ci] {
222 continue;
223 }
224 visited[ci] = true;
225 region.push((cx, cy));
226 if cx > 0 && self[(cx - 1, cy)].is_passable() {
227 stack.push((cx - 1, cy));
228 }
229 if cx + 1 < w && self[(cx + 1, cy)].is_passable() {
230 stack.push((cx + 1, cy));
231 }
232 if cy > 0 && self[(cx, cy - 1)].is_passable() {
233 stack.push((cx, cy - 1));
234 }
235 if cy + 1 < h && self[(cx, cy + 1)].is_passable() {
236 stack.push((cx, cy + 1));
237 }
238 }
239 regions.push(region);
240 }
241 }
242 }
243 regions
244 }
245
246 pub fn neighbors_4(&self, x: usize, y: usize) -> impl Iterator<Item = (usize, usize)> {
248 let (w, h) = (self.width, self.height);
249 let mut n = Vec::with_capacity(4);
250 if x > 0 {
251 n.push((x - 1, y));
252 }
253 if x + 1 < w {
254 n.push((x + 1, y));
255 }
256 if y > 0 {
257 n.push((x, y - 1));
258 }
259 if y + 1 < h {
260 n.push((x, y + 1));
261 }
262 n.into_iter()
263 }
264
265 pub fn neighbors_8(&self, x: usize, y: usize) -> impl Iterator<Item = (usize, usize)> {
267 let (w, h) = (self.width, self.height);
268 let mut n = Vec::with_capacity(8);
269 for dy in -1i32..=1 {
270 for dx in -1i32..=1 {
271 if dx == 0 && dy == 0 {
272 continue;
273 }
274 let nx = x as i32 + dx;
275 let ny = y as i32 + dy;
276 if nx >= 0 && ny >= 0 && (nx as usize) < w && (ny as usize) < h {
277 n.push((nx as usize, ny as usize));
278 }
279 }
280 }
281 n.into_iter()
282 }
283}
284
285impl<C: Cell> Index<(usize, usize)> for Grid<C> {
286 type Output = C;
287 #[inline]
288 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
289 &self.cells[y * self.width + x]
290 }
291}
292
293impl<C: Cell> IndexMut<(usize, usize)> for Grid<C> {
294 #[inline]
295 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
296 &mut self.cells[y * self.width + x]
297 }
298}
299
300impl<C: Cell + PartialEq> PartialEq for Grid<C> {
301 fn eq(&self, other: &Self) -> bool {
302 self.width == other.width && self.height == other.height && self.cells == other.cells
303 }
304}
305
306impl<C: Cell + Eq> Eq for Grid<C> {}
307
308impl fmt::Display for Tile {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 match self {
311 Tile::Wall => write!(f, "#"),
312 Tile::Floor => write!(f, "."),
313 }
314 }
315}
316
317impl fmt::Display for Grid<Tile> {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 for y in 0..self.height {
320 for x in 0..self.width {
321 write!(f, "{}", self[(x, y)])?;
322 }
323 if y + 1 < self.height {
324 writeln!(f)?;
325 }
326 }
327 Ok(())
328 }
329}
330
331pub fn line_points(start: (usize, usize), end: (usize, usize)) -> Vec<(usize, usize)> {
333 let (mut x, mut y) = (start.0 as i32, start.1 as i32);
334 let (tx, ty) = (end.0 as i32, end.1 as i32);
335 let mut points = Vec::new();
336 while x != tx || y != ty {
337 if x >= 0 && y >= 0 {
338 points.push((x as usize, y as usize));
339 }
340 if (x - tx).abs() > (y - ty).abs() {
341 x += if tx > x { 1 } else { -1 };
342 } else {
343 y += if ty > y { 1 } else { -1 };
344 }
345 }
346 if tx >= 0 && ty >= 0 {
347 points.push((tx as usize, ty as usize));
348 }
349 points
350}