tetromino_impl/game/
matrix.rs1use std::ops::Index;
5use std::ops::IndexMut;
6
7use crate::Point;
8
9
10#[derive(Clone, Debug, PartialEq)]
12pub(crate) struct Matrix<T> {
13 matrix: Box<[T]>,
15 width: i16,
17 height: i16,
19}
20
21impl<T> Matrix<T> {
22 pub(crate) fn new(width: i16, height: i16) -> Self
25 where
26 T: Default,
27 {
28 assert!(width > 0);
29 assert!(height > 0);
30
31 let mut matrix = Vec::new();
32 let () = matrix.resize_with((width * height) as usize, T::default);
33
34 Self {
35 width,
36 height,
37 matrix: matrix.into_boxed_slice(),
38 }
39 }
40
41 pub(super) fn remove_line(&mut self, line: i16)
43 where
44 T: Copy + Default,
45 {
46 let src_index = self.calculate_index((0, line + 1));
47 let dst_index = self.calculate_index((0, line));
48 let src_range = src_index..;
49 let () = self.matrix.copy_within(src_range, dst_index);
50
51 let src_index = self.calculate_index((0, self.height - 1));
54 let src_range = src_index..src_index + self.width as usize;
55 let () = self.matrix.get_mut(src_range).unwrap().fill(T::default());
56 }
57
58 #[inline]
60 pub(super) fn clear(&mut self)
61 where
62 T: Clone + Default,
63 {
64 let () = self.matrix.fill(T::default());
65 }
66
67 pub(crate) fn iter(&self) -> impl Iterator<Item = (&T, Point<i16>)> {
69 let width = self.width as usize;
70
71 self.matrix.iter().enumerate().map(move |(i, t)| {
72 let x = i % width;
73 let y = i / width;
74 (t, Point::new(x as i16, y as i16))
75 })
76 }
77
78 pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = (&mut T, Point<i16>)> {
81 let width = self.width as usize;
82
83 self.matrix.iter_mut().enumerate().map(move |(i, t)| {
84 let x = i % width;
85 let y = i / width;
86 (t, Point::new(x as i16, y as i16))
87 })
88 }
89
90 pub(crate) fn iter_line(&self, line: i16) -> impl Iterator<Item = &T> {
92 let index = self.calculate_index((0, line));
93 self.matrix[index..index + self.width as usize].iter()
94 }
95
96 pub(crate) fn to_other<U, F>(&self, f: F) -> Matrix<U>
99 where
100 F: Fn(&T) -> U,
101 {
102 Matrix {
103 width: self.width,
104 height: self.height,
105 matrix: self.matrix.iter().map(f).collect(),
106 }
107 }
108
109 #[inline]
110 pub(crate) fn width(&self) -> i16 {
111 self.width
112 }
113
114 #[inline]
115 pub(crate) fn height(&self) -> i16 {
116 self.height
117 }
118
119 fn calculate_index(&self, (x, y): (i16, i16)) -> usize {
120 (x + y * self.width) as _
121 }
122}
123
124impl<T> Index<(i16, i16)> for Matrix<T> {
125 type Output = T;
126
127 fn index(&self, index: (i16, i16)) -> &Self::Output {
128 let index = self.calculate_index(index);
129 &self.matrix[index]
130 }
131}
132
133impl<T> Index<Point<i16>> for Matrix<T> {
134 type Output = T;
135
136 fn index(&self, index: Point<i16>) -> &Self::Output {
137 self.index((index.x, index.y))
138 }
139}
140
141impl<T> IndexMut<(i16, i16)> for Matrix<T> {
142 fn index_mut(&mut self, index: (i16, i16)) -> &mut Self::Output {
143 let index = self.calculate_index(index);
144 &mut self.matrix[index]
145 }
146}
147
148impl<T> IndexMut<Point<i16>> for Matrix<T> {
149 fn index_mut(&mut self, index: Point<i16>) -> &mut Self::Output {
150 self.index_mut((index.x, index.y))
151 }
152}
153
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159
160 #[test]
162 fn index_access() {
163 let mut matrix = Matrix::<Option<usize>>::new(3, 6);
164 assert_eq!(matrix.width(), 3);
165 assert_eq!(matrix.height(), 6);
166
167 matrix.matrix[0] = Some(42);
170 assert_eq!(matrix[(0, 0)], Some(42));
171
172 matrix.matrix[2] = Some(43);
174 assert_eq!(matrix[(2, 0)], Some(43));
175
176 matrix.matrix[15] = Some(44);
178 assert_eq!(matrix[(0, 5)], Some(44));
179
180 matrix.matrix[17] = Some(45);
182 assert_eq!(matrix[(2, 5)], Some(45));
183 }
184
185 #[test]
187 fn line_removal() {
188 let mut matrix = Matrix::<Option<usize>>::new(2, 4);
189 let mut x = 0;
190 let () = matrix.matrix.fill_with(|| {
191 x += 1;
192 Some(x)
193 });
194
195 #[rustfmt::skip]
201 let expected = [
202 Some(1), Some(2),
203 Some(3), Some(4),
204 Some(5), Some(6),
205 Some(7), Some(8),
206 ];
207 assert_eq!(&*matrix.matrix, expected.as_slice());
208
209 let () = matrix.remove_line(0);
210 #[rustfmt::skip]
216 let expected = [
217 Some(3), Some(4),
218 Some(5), Some(6),
219 Some(7), Some(8),
220 None, None,
221 ];
222 assert_eq!(&*matrix.matrix, expected.as_slice());
223 }
224}