board.rs 11 KB

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