1use std::{
2 array,
3 ops::{Index, IndexMut},
4};
5
6pub struct Grid<T> {
7 width: usize,
8 height: usize,
9 buffer: Vec<T>,
10}
11
12impl<T: Default + Clone> Grid<T> {
13 pub fn from_defaults(width: usize, height: usize) -> Self {
14 Self {
15 width,
16 height,
17 buffer: vec![Default::default(); width * height],
18 }
19 }
20}
21
22impl<T> Index<(usize, usize)> for Grid<T> {
23 type Output = T;
24
25 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
26 assert!(x < self.width);
27 assert!(y < self.height);
28 &self.buffer[y * self.width + x]
29 }
30}
31impl<T> IndexMut<(usize, usize)> for Grid<T> {
32 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
33 assert!(x < self.width);
34 assert!(y < self.height);
35 &mut self.buffer[y * self.width + x]
36 }
37}
38
39impl<T> Grid<T> {
40 pub fn from_fn(width: usize, height: usize, fun: &mut impl FnMut(usize, usize) -> T) -> Self {
41 let mut buffer = Vec::with_capacity(width * height);
42
43 for y in 0..height {
44 for x in 0..width {
45 buffer.push(fun(x, y));
46 }
47 }
48
49 Self {
50 width,
51 height,
52 buffer,
53 }
54 }
55 pub fn width(&self) -> usize {
56 self.width
57 }
58 pub fn height(&self) -> usize {
59 self.height
60 }
61 pub fn map_once<U, F>(self, mapper: F) -> Grid<U>
62 where
63 F: FnMut(T) -> U,
64 {
65 let buffer = self.buffer.into_iter().map(mapper).collect();
66 Grid {
67 width: self.width,
68 height: self.height,
69 buffer,
70 }
71 }
72 pub fn map<U, F>(&self, mapper: F) -> Grid<U>
73 where
74 F: FnMut(&T) -> U,
75 {
76 let buffer = self.buffer.iter().map(mapper).collect();
77 Grid {
78 width: self.width,
79 height: self.height,
80 buffer,
81 }
82 }
83}
84impl<T: Clone> Grid<T> {
85 pub fn map_mut<F>(&mut self, mut mapper: F) -> &mut Grid<T>
86 where
87 F: FnMut(T) -> T,
88 {
89 self.buffer.iter_mut().for_each(|v| {
90 let old = v.clone();
91 let new = mapper(old);
92 *v = new;
93 });
94 self
95 }
96 pub fn map_with_neighbors<U, F>(&self, mut mapper: F, default: T) -> Grid<U>
97 where
98 F: FnMut(&[[T; 3]; 3]) -> U,
99 U: Default,
100 {
101 let (width, height) = (self.width, self.height);
102 let mut buffer = Vec::with_capacity(width * height);
103 let mut neighborhood = array::from_fn(|_| array::from_fn(|_| default.clone()));
104 for y in 0..self.height {
105 for x in 0..self.width {
106 for oy in 0..3 {
107 for ox in 0..3 {
108 let x = x as isize + ox as isize - 1;
109 let y = y as isize + oy as isize - 1;
110 neighborhood[ox][oy] =
111 if x > 0 && x < width as _ && y > 0 && y < height as _ {
112 self[(x as _, y as _)].clone()
113 } else {
114 default.clone()
115 };
116 }
117 }
118 buffer.push(mapper(&neighborhood));
119 }
120 }
121 Grid {
122 width,
123 height,
124 buffer,
125 }
126 }
127}
128
129use core::ops::*;
134macro_rules! impl_binop {
135 ($($Trait:ident => $fun:ident),*) => {$(
136 impl<'a, R: 'static, T: $Trait<&'a R>> $Trait<&'a Grid<R>> for Grid<T> {
137 type Output = Grid<T::Output>;
138 fn $fun(self, rhs: &'a Grid<R>) -> Self::Output {
139 assert_eq!(self.width, rhs.width);
140 assert_eq!(self.height, rhs.height);
141 let buffer = self.buffer.into_iter().zip(rhs.buffer.iter()).map(|(l, r)| l.$fun(r)).collect::<Vec<_>>();
142 Grid {
143 width: self.width,
144 height: self.height,
145 buffer
146 }
147 }
148 }
149 )*};
150}
151macro_rules! impl_assign {
152 ($($Trait:ident => $fun:ident),*) => {$(
153 impl<'a, R, T: $Trait<&'a R>> $Trait<&'a Grid<R>> for Grid<T> {
154 fn $fun(&mut self, rhs: &'a Grid<R>) {
155 assert_eq!(self.width, rhs.width);
156 assert_eq!(self.height, rhs.height);
157 self.buffer.iter_mut().zip(rhs.buffer.iter()).for_each(|(l, r)| l.$fun(r));
158 }
159 }
160 )*};
161}
162macro_rules! impl_unop {
163 ($($Trait:ident => $fun:ident),*) => {$(
164 impl<'a, T: $Trait> $Trait for Grid<T> {
165 type Output = Grid<T::Output>;
166 fn $fun(self) -> Self::Output {
167 let buffer = self.buffer.into_iter().map($Trait::$fun).collect::<Vec<_>>();
168 Grid {
169 width: self.width,
170 height: self.height,
171 buffer
172 }
173 }
174 }
175 )*};
176}
177
178impl_assign!(
179 AddAssign => add_assign,
180 BitAndAssign => bitand_assign,
181 BitOrAssign => bitor_assign,
182 BitXorAssign => bitxor_assign,
183 DivAssign => div_assign,
184 MulAssign => mul_assign,
185 RemAssign => rem_assign,
186 ShlAssign => shl_assign,
187 ShrAssign => shr_assign,
188 SubAssign => sub_assign
189);
190impl_binop!(
191 Add => add,
192 Sub => sub,
193 Mul => mul,
194 Div => div,
195 Rem => rem,
196 Shr => shr,
197 Shl => shl,
198 BitAnd => bitand,
199 BitOr => bitor,
200 BitXor => bitxor
201);
202impl_unop!(
203 Neg => neg,
204 Not => not
205);