1use std::ops::{Index, IndexMut};
4
5pub trait Cell: Clone + Default {
7 fn is_passable(&self) -> bool;
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
12pub enum Tile {
13 #[default]
14 Wall,
15 Floor,
16}
17
18impl Tile {
19 pub fn is_wall(&self) -> bool { matches!(self, Tile::Wall) }
20 pub fn is_floor(&self) -> bool { matches!(self, Tile::Floor) }
21}
22
23impl Cell for Tile {
24 fn is_passable(&self) -> bool { self.is_floor() }
25}
26
27#[derive(Debug, Clone)]
29pub struct Grid<C: Cell = Tile> {
30 width: usize,
31 height: usize,
32 cells: Vec<C>,
33}
34
35impl<C: Cell> Grid<C> {
36 pub fn new(width: usize, height: usize) -> Self {
37 Self {
38 width,
39 height,
40 cells: vec![C::default(); width * height],
41 }
42 }
43
44 pub fn width(&self) -> usize { self.width }
45 pub fn height(&self) -> usize { self.height }
46
47 pub fn in_bounds(&self, x: i32, y: i32) -> bool {
48 x >= 0 && y >= 0 && (x as usize) < self.width && (y as usize) < self.height
49 }
50
51 pub fn get(&self, x: i32, y: i32) -> Option<&C> {
52 if self.in_bounds(x, y) {
53 Some(&self.cells[y as usize * self.width + x as usize])
54 } else {
55 None
56 }
57 }
58
59 pub fn get_mut(&mut self, x: i32, y: i32) -> Option<&mut C> {
60 if self.in_bounds(x, y) {
61 Some(&mut self.cells[y as usize * self.width + x as usize])
62 } else {
63 None
64 }
65 }
66
67 pub fn set(&mut self, x: i32, y: i32, cell: C) -> bool {
68 if self.in_bounds(x, y) {
69 self.cells[y as usize * self.width + x as usize] = cell;
70 true
71 } else {
72 false
73 }
74 }
75
76 pub fn fill(&mut self, cell: C) {
77 self.cells.fill(cell);
78 }
79
80 pub fn fill_rect(&mut self, x: i32, y: i32, w: usize, h: usize, cell: C) {
81 for dy in 0..h {
82 for dx in 0..w {
83 self.set(x + dx as i32, y + dy as i32, cell.clone());
84 }
85 }
86 }
87
88 pub fn count<F: Fn(&C) -> bool>(&self, predicate: F) -> usize {
89 self.cells.iter().filter(|c| predicate(c)).count()
90 }
91
92 pub fn iter(&self) -> impl Iterator<Item = (usize, usize, &C)> {
93 self.cells.iter().enumerate().map(move |(i, c)| {
94 (i % self.width, i / self.width, c)
95 })
96 }
97}
98
99impl<C: Cell> Index<(usize, usize)> for Grid<C> {
100 type Output = C;
101 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
102 &self.cells[y * self.width + x]
103 }
104}
105
106impl<C: Cell> IndexMut<(usize, usize)> for Grid<C> {
107 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
108 &mut self.cells[y * self.width + x]
109 }
110}
111
112impl<C: Cell + PartialEq> PartialEq for Grid<C> {
113 fn eq(&self, other: &Self) -> bool {
114 self.width == other.width && self.height == other.height && self.cells == other.cells
115 }
116}
117
118impl<C: Cell + Eq> Eq for Grid<C> {}