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