board.rs 10 KB

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