board.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. use crate::{Coord, Rect};
  2. /// A `Board` represents a two-dimensional grid with a fixed width and
  3. /// height. Indexing always starts from (0, 0)
  4. #[derive(PartialEq, Eq, Debug)]
  5. pub struct Board<T> {
  6. width: usize,
  7. height: usize,
  8. storage: Vec<T>,
  9. }
  10. impl<T> Board<T> {
  11. pub fn new_from(width: usize, height: usize, mut func: impl FnMut(usize, usize) -> T) -> Board<T> {
  12. let mut storage = Vec::with_capacity(width * height);
  13. for y in 0..height {
  14. for x in 0..width {
  15. storage.push(func(x, y))
  16. }
  17. }
  18. Board { width, height, storage }
  19. }
  20. /// Returns a reference to an element at the given location, or
  21. /// `None` if the location is out of bounds.
  22. pub fn get(&self, x: usize, y: usize) -> Option<&T> {
  23. if !self.contains([x, y]) {
  24. return None;
  25. }
  26. let idx = x + self.width * y;
  27. self.storage.get(idx)
  28. }
  29. /// Returns a mutable reference to an element at the given
  30. /// location, or `None` if the location is out of bounds.
  31. pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut T> {
  32. if !self.contains([x, y]) {
  33. return None;
  34. }
  35. let idx = x + self.width * y;
  36. self.storage.get_mut(idx)
  37. }
  38. /// Returns the width of the board
  39. pub fn width(&self) -> usize {
  40. self.width
  41. }
  42. /// Returns the height of the board
  43. pub fn height(&self) -> usize {
  44. self.height
  45. }
  46. /// Returns `true` if the given position is in-bounds in the
  47. /// board; otherwise returns false
  48. pub fn contains(&self, pos: impl Into<Coord>) -> bool {
  49. let pos = pos.into();
  50. pos.x < self.width && pos.y < self.height
  51. }
  52. pub fn contains_rect(&self, rect: Rect) -> bool {
  53. let max_x = rect.width() + rect.x() - 1;
  54. let max_y = rect.height() + rect.y() - 1;
  55. println!("checking if ({}, {}) is contained", max_x, max_y);
  56. self.contains([max_x, max_y])
  57. }
  58. /// Returns an iterator over the board in row-major order; this
  59. /// iterator returns not only the values contained in the board,
  60. /// but also their indices.
  61. pub fn iter(&self) -> BoardIter<T> {
  62. BoardIter {
  63. n: 0,
  64. width: self.width,
  65. iter: self.storage.iter(),
  66. }
  67. }
  68. /// Returns an iterator over the board in row-major order; this
  69. /// iterator returns not only the values contained in the board,
  70. /// but also their indices.
  71. pub fn iter_mut(&mut self) -> BoardIterMut<T> {
  72. BoardIterMut {
  73. n: 0,
  74. width: self.width,
  75. iter: self.storage.iter_mut(),
  76. }
  77. }
  78. pub fn window_iter(&self, window: Rect) -> Option<BoardWindowIter<T>> {
  79. if !self.contains_rect(window) {
  80. return None;
  81. }
  82. Some(BoardWindowIter {
  83. n: 0,
  84. width: self.width,
  85. window,
  86. iter: self.storage.iter(),
  87. })
  88. }
  89. pub fn window_iter_mut(&mut self, window: Rect) -> Option<BoardWindowIterMut<T>> {
  90. if !self.contains_rect(window) {
  91. return None;
  92. }
  93. Some(BoardWindowIterMut {
  94. n: 0,
  95. width: self.width,
  96. window,
  97. iter: self.storage.iter_mut(),
  98. })
  99. }
  100. }
  101. impl<T> std::ops::Index<Coord> for Board<T> {
  102. type Output = T;
  103. fn index(&self, pos: Coord) -> &Self::Output {
  104. self.get(pos.x, pos.y).unwrap_or_else(|| panic!("Coordinate {:?} out of range", pos))
  105. }
  106. }
  107. impl<T> std::ops::Index<(usize, usize)> for Board<T> {
  108. type Output = T;
  109. fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
  110. self.get(x, y).unwrap_or_else(|| panic!("Coordinate {:?} out of range", (x, y)))
  111. }
  112. }
  113. impl<T> std::ops::Index<[usize;2]> for Board<T> {
  114. type Output = T;
  115. fn index(&self, [x, y]: [usize;2]) -> &Self::Output {
  116. self.get(x, y).unwrap_or_else(|| panic!("Coordinate {:?} out of range", (x, y)))
  117. }
  118. }
  119. impl<T> std::ops::IndexMut<Coord> for Board<T> {
  120. fn index_mut(&mut self, pos: Coord) -> &mut Self::Output {
  121. self.get_mut(pos.x, pos.y).unwrap_or_else(|| panic!("Coordinate {:?} out of range", pos))
  122. }
  123. }
  124. impl<T> std::ops::IndexMut<(usize, usize)> for Board<T> {
  125. fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
  126. self.get_mut(x, y).unwrap_or_else(|| panic!("Coordinate {:?} out of range", (x, y)))
  127. }
  128. }
  129. impl<T> std::ops::IndexMut<[usize;2]> for Board<T> {
  130. fn index_mut(&mut self, [x, y]: [usize;2]) -> &mut Self::Output {
  131. self.get_mut(x, y).unwrap_or_else(|| panic!("Coordinate {:?} out of range", (x, y)))
  132. }
  133. }
  134. /// An iterator over the elements of a `Board`. This returns values in
  135. /// row-major order but each element is also accompanied by its
  136. /// indices.
  137. pub struct BoardIter<'a, T> {
  138. n: usize,
  139. width: usize,
  140. iter: std::slice::Iter<'a, T>,
  141. }
  142. impl<'a, T> Iterator for BoardIter<'a, T> {
  143. type Item = (usize, usize, &'a T);
  144. fn next(&mut self) -> Option<Self::Item> {
  145. if let Some(v) = self.iter.next() {
  146. let x = self.n % self.width;
  147. let y = self.n / self.width;
  148. self.n += 1;
  149. Some((x, y, v))
  150. } else {
  151. None
  152. }
  153. }
  154. }
  155. /// An iterator over the elements of a `Board`. This returns values in
  156. /// row-major order but each element is also accompanied by its
  157. /// indices.
  158. pub struct BoardIterMut<'a, T> {
  159. n: usize,
  160. width: usize,
  161. iter: std::slice::IterMut<'a, T>,
  162. }
  163. impl<'a, T> Iterator for BoardIterMut<'a, T> {
  164. type Item = (usize, usize, &'a mut T);
  165. fn next(&mut self) -> Option<Self::Item> {
  166. if let Some(v) = self.iter.next() {
  167. let x = self.n % self.width;
  168. let y = self.n / self.width;
  169. self.n += 1;
  170. Some((x, y, v))
  171. } else {
  172. None
  173. }
  174. }
  175. }
  176. pub struct BoardWindowIter<'a, T> {
  177. n: usize,
  178. width: usize,
  179. window: Rect,
  180. iter: std::slice::Iter<'a, T>,
  181. }
  182. impl<'a, T> Iterator for BoardWindowIter<'a, T> {
  183. type Item = (usize, usize, &'a T);
  184. fn next(&mut self) -> Option<Self::Item> {
  185. while let Some(v) = self.iter.next() {
  186. let x = self.n % self.width;
  187. let y = self.n / self.width;
  188. self.n += 1;
  189. if self.window.contains([x, y]) {
  190. return Some((x, y, v));
  191. }
  192. }
  193. None
  194. }
  195. }
  196. pub struct BoardWindowIterMut<'a, T> {
  197. n: usize,
  198. width: usize,
  199. window: Rect,
  200. iter: std::slice::IterMut<'a, T>,
  201. }
  202. impl<'a, T> Iterator for BoardWindowIterMut<'a, T> {
  203. type Item = (usize, usize, &'a mut T);
  204. fn next(&mut self) -> Option<Self::Item> {
  205. while let Some(v) = self.iter.next() {
  206. let x = self.n % self.width;
  207. let y = self.n / self.width;
  208. self.n += 1;
  209. if self.window.contains([x, y]) {
  210. return Some((x, y, v));
  211. }
  212. }
  213. None
  214. }
  215. }
  216. #[cfg(test)]
  217. mod test {
  218. use super::*;
  219. macro_rules! board_from_vec {
  220. ($w:expr, $h:expr; [$($vec:tt)*]) => {
  221. {
  222. let w = $w;
  223. let h = $h;
  224. let v = vec![$($vec)*];
  225. assert!(v.len() == w * h);
  226. Board::new_from(w, h, |x, y| {
  227. v[x + y * w]
  228. })
  229. }
  230. }
  231. }
  232. #[test]
  233. fn board_indexing() {
  234. let b = board_from_vec![2,2; [1,2,3,4]];
  235. // in-bounds tests
  236. assert_eq!(b.get(0, 0), Some(&1));
  237. assert_eq!(b.get(1, 0), Some(&2));
  238. assert_eq!(b.get(0, 1), Some(&3));
  239. assert_eq!(b.get(1, 1), Some(&4));
  240. // out-of-bounds tests
  241. assert_eq!(b.get(2, 0), None);
  242. assert_eq!(b.get(0, 2), None);
  243. assert_eq!(b.get(2, 2), None);
  244. }
  245. #[test]
  246. fn board_mut_indexing() {
  247. let mut b = board_from_vec![2,2; [1,2,3,4]];
  248. // in-bounds tests
  249. *b.get_mut(0, 0).unwrap() = 5;
  250. *b.get_mut(1, 0).unwrap() = 6;
  251. *b.get_mut(0, 1).unwrap() = 7;
  252. *b.get_mut(1, 1).unwrap() = 8;
  253. assert_eq!(b, board_from_vec![2,2; [5,6,7,8]]);
  254. }
  255. #[test]
  256. fn board_iter() {
  257. let b = board_from_vec![2,2; [1,2,3,4]];
  258. let mut iter = b.iter();
  259. // in-bounds tests
  260. assert_eq!(iter.next(), Some((0, 0, &1)));
  261. assert_eq!(iter.next(), Some((1, 0, &2)));
  262. assert_eq!(iter.next(), Some((0, 1, &3)));
  263. assert_eq!(iter.next(), Some((1, 1, &4)));
  264. assert_eq!(iter.next(), None);
  265. }
  266. #[test]
  267. fn board_iter_mut() {
  268. let mut b = board_from_vec![2,2; [1,2,3,4]];
  269. // in-bounds tests
  270. for (x, y, r) in b.iter_mut() {
  271. *r = x * 2 + y * 2;
  272. }
  273. assert_eq!(b, board_from_vec![2,2; [0,2,2,4]]);
  274. }
  275. #[test]
  276. fn window_iter() {
  277. let b = board_from_vec![
  278. 4,4;
  279. [1,2,3,4,
  280. 5,6,7,8,
  281. 8,7,6,5,
  282. 4,3,2,1,
  283. ]
  284. ];
  285. let mut iter = b.window_iter(
  286. Rect {
  287. origin: [1, 1].into(),
  288. size: [2, 2].into(),
  289. }).expect("Did not find expected BoardWindowIter");
  290. // in-bounds tests
  291. assert_eq!(iter.next(), Some((1, 1, &6)));
  292. assert_eq!(iter.next(), Some((2, 1, &7)));
  293. assert_eq!(iter.next(), Some((1, 2, &7)));
  294. assert_eq!(iter.next(), Some((2, 2, &6)));
  295. assert_eq!(iter.next(), None);
  296. }
  297. #[test]
  298. fn window_iter_mut() {
  299. let mut b: Board<isize> = board_from_vec![
  300. 4,4;
  301. [1,2,3,4,
  302. 5,6,7,8,
  303. 8,7,6,5,
  304. 4,3,2,1,
  305. ]];
  306. let iter = b.window_iter_mut(
  307. Rect {
  308. origin: [1, 1].into(),
  309. size: [2, 2].into(),
  310. }).expect("Did not find expected BoardWindowIterMut");
  311. for (x, y, v) in iter {
  312. *v = -(2 * x as isize + 2 * y as isize);
  313. }
  314. assert_eq!(b, board_from_vec![
  315. 4,4;
  316. [ 1, 2, 3, 4,
  317. 5,-4,-6, 8,
  318. 8,-6,-8, 5,
  319. 4, 3, 2, 1,
  320. ]
  321. ]);
  322. }
  323. }