···22name = "utils"
33version = "0.1.0"
44edition = "2021"
55-66-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77-88-[dependencies]
···11+/// Module containing utilities related to direction and movement.
22+use crate::pos::Position;
33+44+/// Trait used to define an object that can be used to move around a grid.
55+///
66+/// This is meant for complex scenarios where you want to move around a grid in a non-standard way.
77+/// By implementing this trait you can use various methods from the [Position] struct to move around.
88+///
99+/// # Implementing
1010+///
1111+/// Implementing this trait requires you to define a `get_kernel` method that returns a `Position`.
1212+/// This position is used to move around the grid by applying it to the current position.
1313+///
1414+/// # Examples
1515+///
1616+/// ```
1717+/// use utils::prelude::*;
1818+///
1919+/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2020+/// struct RightBy(usize);
2121+///
2222+/// impl Movement for RightBy {
2323+/// fn get_kernel(&self) -> Position {
2424+/// Position::new(self.0 as isize, 0)
2525+/// }
2626+/// }
2727+///
2828+/// let pos = Position::new(0, 0);
2929+/// assert_eq!(pos.move_dir(RightBy(1)), Position::new(1, 0));
3030+/// ```
3131+///
3232+/// # See also
3333+///
3434+/// - [Direction] is a simple implementation of this trait.
3535+/// - [Position] is the main user of this trait.
3636+///
3737+pub trait Movement: std::fmt::Debug + Copy + Clone + PartialEq + std::hash::Hash {
3838+ fn get_kernel(&self) -> Position;
3939+}
4040+4141+/// The four cardinal directions.
4242+/// Useful for iterating over all four directions.
4343+pub const CARDINALS: [Direction; 4] = [
4444+ Direction::North,
4545+ Direction::South,
4646+ Direction::East,
4747+ Direction::West,
4848+];
4949+5050+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
5151+/// The four cardinal directions.
5252+/// This is a simple implementation of the [Movement] trait.
5353+///
5454+/// # Examples
5555+///
5656+/// ```
5757+/// use utils::prelude::*;
5858+///
5959+/// let pos = Position::new(0, 0);
6060+/// assert_eq!(pos.move_dir(Direction::North), Position::new(0, -1));
6161+/// assert_eq!(pos.move_dir(Direction::South), Position::new(0, 1));
6262+/// assert_eq!(pos.move_dir(Direction::East), Position::new(1, 0));
6363+/// assert_eq!(pos.move_dir(Direction::West), Position::new(-1, 0));
6464+/// ```
6565+///
6666+pub enum Direction {
6767+ North,
6868+ South,
6969+ East,
7070+ West,
7171+}
7272+7373+impl Direction {
7474+ /// Returns the direction that is opposite to the current one.
7575+ ///
7676+ /// # Examples
7777+ ///
7878+ /// ```
7979+ /// use utils::prelude::*;
8080+ ///
8181+ /// assert_eq!(Direction::North.opposite(), Direction::South);
8282+ /// assert_eq!(Direction::South.opposite(), Direction::North);
8383+ /// assert_eq!(Direction::East.opposite(), Direction::West);
8484+ /// assert_eq!(Direction::West.opposite(), Direction::East);
8585+ /// ```
8686+ ///
8787+ pub fn opposite(&self) -> Self {
8888+ match self {
8989+ Self::North => Self::South,
9090+ Self::South => Self::North,
9191+ Self::East => Self::West,
9292+ Self::West => Self::East,
9393+ }
9494+ }
9595+9696+ /// Returns the direction that is 90 degrees to the current one.
9797+ ///
9898+ /// # Examples
9999+ ///
100100+ /// ```
101101+ /// use utils::prelude::*;
102102+ ///
103103+ /// assert_eq!(Direction::North.ninety_deg(true), Direction::East);
104104+ /// assert_eq!(Direction::North.ninety_deg(false), Direction::West);
105105+ ///
106106+ /// assert_eq!(Direction::South.ninety_deg(true), Direction::West);
107107+ /// assert_eq!(Direction::South.ninety_deg(false), Direction::East);
108108+ /// ```
109109+ ///
110110+ pub fn ninety_deg(&self, clockwise: bool) -> Self {
111111+ match (self, clockwise) {
112112+ (Self::North, true) => Self::East,
113113+ (Self::North, false) => Self::West,
114114+ (Self::South, true) => Self::West,
115115+ (Self::South, false) => Self::East,
116116+ (Self::East, true) => Self::South,
117117+ (Self::East, false) => Self::North,
118118+ (Self::West, true) => Self::North,
119119+ (Self::West, false) => Self::South,
120120+ }
121121+ }
122122+}
123123+124124+impl From<Position> for Direction {
125125+ fn from(pos: Position) -> Self {
126126+ let pos = pos.normalize();
127127+ match (pos.x, pos.y) {
128128+ (0, -1) => Self::North,
129129+ (0, 1) => Self::South,
130130+ (1, 0) => Self::East,
131131+ (-1, 0) => Self::West,
132132+ _ => panic!("Invalid position"),
133133+ }
134134+ }
135135+}
136136+137137+impl Movement for Direction {
138138+ fn get_kernel(&self) -> Position {
139139+ match self {
140140+ Direction::North => Position::new(0, -1),
141141+ Direction::South => Position::new(0, 1),
142142+ Direction::East => Position::new(1, 0),
143143+ Direction::West => Position::new(-1, 0),
144144+ }
145145+ }
146146+}
+24
utils/src/geom.rs
···11+use crate::pos::Position;
22+33+/// Get the area of a polygon given its vertices.
44+///
55+/// This is the shoelace formula.
66+///
77+pub fn area(verts: &[Position]) -> isize {
88+ verts
99+ .windows(2)
1010+ .map(|w| ((w[0].x) * (w[1].y)) - ((w[0].y) * (w[1].x)))
1111+ .sum::<isize>()
1212+ / 2
1313+}
1414+1515+/// Get the perimeter of a polygon given its vertices.
1616+///
1717+/// This is the sum of the distances between each vertex.
1818+///
1919+pub fn perimeter(verts: &[Position]) -> isize {
2020+ verts
2121+ .windows(2)
2222+ .map(|w| (w[0].x - w[1].x).abs() + (w[0].y - w[1].y).abs())
2323+ .sum::<isize>()
2424+}
+938
utils/src/grid.rs
···11+use crate::{
22+ dir::{Direction, Movement, CARDINALS},
33+ pos::Position,
44+};
55+66+/// A 2D integer grid of values.
77+///
88+/// This grid is represented by a vector of vectors.
99+///
1010+/// # Examples
1111+///
1212+/// ```
1313+/// use utils::prelude::*;
1414+///
1515+/// let data = vec![
1616+/// vec![1, 2, 3],
1717+/// vec![4, 5, 6],
1818+/// vec![7, 8, 9],
1919+/// ];
2020+///
2121+/// let grid = Grid::new(data);
2222+///
2323+/// assert_eq!(grid.get(Position::new(0, 0)), Some(&1));
2424+/// assert_eq!(grid.get(Position::new(1, 1)), Some(&5));
2525+/// assert_eq!(grid.get(Position::new(2, 2)), Some(&9));
2626+/// ```
2727+///
2828+pub struct Grid<T> {
2929+ data: Vec<Vec<T>>,
3030+}
3131+3232+impl<T> Grid<T> {
3333+ /// Create a new grid from a vector of vectors.
3434+ pub fn new(data: Vec<Vec<T>>) -> Self {
3535+ Self { data }
3636+ }
3737+3838+ /// Parse a grid from a string, this will convert each character into `T` via `From<char>`.
3939+ ///
4040+ /// Use the `tiles!` macro to easily create an enum that implements `From<char>`.
4141+ ///
4242+ /// # Examples
4343+ ///
4444+ /// ```
4545+ /// use utils::prelude::*;
4646+ ///
4747+ /// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4848+ /// enum Tile {
4949+ /// Floor,
5050+ /// Wall,
5151+ /// }
5252+ ///
5353+ /// impl From<char> for Tile {
5454+ /// fn from(c: char) -> Self {
5555+ /// match c {
5656+ /// '.' => Self::Floor,
5757+ /// '#' => Self::Wall,
5858+ /// _ => panic!("Invalid tile {c}"),
5959+ /// }
6060+ /// }
6161+ /// }
6262+ ///
6363+ /// let input = ".#.\n#.#\n.#.";
6464+ /// let grid = Grid::<Tile>::parse(input);
6565+ ///
6666+ /// assert_eq!(grid.get(Position::new(0, 0)), Some(&Tile::Floor));
6767+ /// assert_eq!(grid.get(Position::new(1, 0)), Some(&Tile::Wall));
6868+ /// assert_eq!(grid.get(Position::new(2, 0)), Some(&Tile::Floor));
6969+ /// assert_eq!(grid.get(Position::new(1, 1)), Some(&Tile::Floor));
7070+ /// ```
7171+ ///
7272+ /// Using `tiles!`...
7373+ ///
7474+ /// ```
7575+ /// use utils::prelude::*;
7676+ /// use utils::tiles;
7777+ ///
7878+ /// tiles!(Tile, [
7979+ /// '.' => Floor,
8080+ /// '#' => Wall,
8181+ /// ]);
8282+ ///
8383+ /// let input = ".#.\n#.#\n.#.";
8484+ /// let grid = Grid::<Tile>::parse(input);
8585+ ///
8686+ /// assert_eq!(grid.get(Position::new(0, 0)), Some(&Tile::Floor));
8787+ /// assert_eq!(grid.get(Position::new(1, 0)), Some(&Tile::Wall));
8888+ /// assert_eq!(grid.get(Position::new(2, 0)), Some(&Tile::Floor));
8989+ /// assert_eq!(grid.get(Position::new(1, 1)), Some(&Tile::Floor));
9090+ /// ```
9191+ ///
9292+ pub fn parse(input: &str) -> Self
9393+ where
9494+ T: From<char>,
9595+ {
9696+ let data = input
9797+ .lines()
9898+ .map(|line| line.chars().map(|c| c.into()).collect())
9999+ .collect();
100100+ Self::new(data)
101101+ }
102102+103103+ /// Return the width of the grid.
104104+ pub fn width(&self) -> usize {
105105+ self.data[0].len()
106106+ }
107107+108108+ /// Return the height of the grid.
109109+ pub fn height(&self) -> usize {
110110+ self.data.len()
111111+ }
112112+113113+ /// Get the size of the grid.
114114+ pub fn size(&self) -> (usize, usize) {
115115+ (self.width(), self.height())
116116+ }
117117+118118+ /// Get the bounds of the grid.
119119+ ///
120120+ /// (This is the same as `self.size()` with -1 added to each component)
121121+ pub fn bounds(&self) -> (usize, usize) {
122122+ (self.width() - 1, self.height() - 1)
123123+ }
124124+125125+ /// Get a value from the grid at the given position.
126126+ ///
127127+ /// # Examples
128128+ ///
129129+ /// ```
130130+ /// use utils::prelude::*;
131131+ ///
132132+ /// let data = vec![
133133+ /// vec![1, 2, 3],
134134+ /// vec![4, 5, 6],
135135+ /// vec![7, 8, 9],
136136+ /// ];
137137+ ///
138138+ /// let grid = Grid::new(data);
139139+ /// assert_eq!(grid.get(Position::new(0, 0)), Some(&1));
140140+ /// assert_eq!(grid.get(Position::new(1, 1)), Some(&5));
141141+ /// assert_eq!(grid.get(Position::new(2, 2)), Some(&9));
142142+ /// assert_eq!(grid.get(Position::new(3, 3)), None);
143143+ /// ```
144144+ ///
145145+ pub fn get(&self, pos: Position) -> Option<&T> {
146146+ self.data
147147+ .get(pos.y as usize)
148148+ .and_then(|row| row.get(pos.x as usize))
149149+ }
150150+151151+ /// Get a value from the grid at the given position,
152152+ /// panicking if the position is out of bounds.
153153+ ///
154154+ /// # Examples
155155+ ///
156156+ /// ```
157157+ /// use utils::prelude::*;
158158+ ///
159159+ /// let data = vec![
160160+ /// vec![1, 2, 3],
161161+ /// vec![4, 5, 6],
162162+ /// vec![7, 8, 9],
163163+ /// ];
164164+ ///
165165+ /// let grid = Grid::new(data);
166166+ ///
167167+ /// assert_eq!(grid.unsafe_get(Position::new(0, 0)), &1);
168168+ /// assert_eq!(grid.unsafe_get(Position::new(1, 1)), &5);
169169+ /// ```
170170+ ///
171171+ pub fn unsafe_get(&self, pos: Position) -> &T {
172172+ &self.data[pos.y as usize][pos.x as usize]
173173+ }
174174+175175+ /// Get the value at the given position, wrapping around the grid if necessary.
176176+ ///
177177+ /// # Examples
178178+ ///
179179+ /// ```
180180+ /// use utils::prelude::*;
181181+ ///
182182+ /// let data = vec![
183183+ /// vec![1, 2, 3],
184184+ /// vec![4, 5, 6],
185185+ /// vec![7, 8, 9],
186186+ /// ];
187187+ ///
188188+ /// let grid = Grid::new(data);
189189+ /// assert_eq!(grid.get_wrapped(Position::new(0, 0)), &1);
190190+ /// assert_eq!(grid.get_wrapped(Position::new(1, 1)), &5);
191191+ /// assert_eq!(grid.get_wrapped(Position::new(2, 2)), &9);
192192+ /// assert_eq!(grid.get_wrapped(Position::new(3, 3)), &1);
193193+ /// assert_eq!(grid.get_wrapped(Position::new(-1, -1)), &9);
194194+ /// ```
195195+ ///
196196+ pub fn get_wrapped(&self, pos: Position) -> &T {
197197+ let wrapped_pos = pos.bind(self.size());
198198+ &self.data[wrapped_pos.1][wrapped_pos.0]
199199+ }
200200+201201+ /// Iterate over a row of the grid.
202202+ ///
203203+ /// # Examples
204204+ ///
205205+ /// ```
206206+ /// use utils::prelude::*;
207207+ ///
208208+ /// let data = vec![
209209+ /// vec![1, 2, 3],
210210+ /// vec![4, 5, 6],
211211+ /// vec![7, 8, 9],
212212+ /// ];
213213+ ///
214214+ /// let grid = Grid::new(data);
215215+ ///
216216+ /// assert_eq!(grid.iter_row(0).unwrap().collect::<Vec<_>>(), vec![&1, &2, &3]);
217217+ /// assert_eq!(grid.iter_row(1).unwrap().sum::<usize>(), 4+5+6);
218218+ /// assert!(grid.iter_row(8).is_none());
219219+ /// ```
220220+ ///
221221+ pub fn iter_row(&self, row: usize) -> Option<impl Iterator<Item = &T>> {
222222+ self.data.get(row).map(|row| row.iter())
223223+ }
224224+225225+ /// Iterate over a column of the grid.
226226+ ///
227227+ /// # Examples
228228+ ///
229229+ /// ```
230230+ /// use utils::prelude::*;
231231+ ///
232232+ ///
233233+ /// let data = vec![
234234+ /// vec![1, 2, 3],
235235+ /// vec![4, 5, 6],
236236+ /// vec![7, 8, 9],
237237+ /// ];
238238+ ///
239239+ /// let grid = Grid::new(data);
240240+ ///
241241+ /// assert_eq!(grid.iter_col(0).unwrap().collect::<Vec<_>>(), vec![&1, &4, &7]);
242242+ /// assert_eq!(grid.iter_col(1).unwrap().sum::<usize>(), 2+5+8);
243243+ /// assert!(grid.iter_col(8).is_none());
244244+ /// ```
245245+ ///
246246+ pub fn iter_col(&self, col: usize) -> Option<impl Iterator<Item = &T>> {
247247+ if col > self.width() {
248248+ return None;
249249+ }
250250+ Some(self.data.iter().filter_map(move |row| row.get(col)))
251251+ }
252252+253253+ /// Get a row of the grid.
254254+ ///
255255+ /// This is the same as `self.iter_row(row).map(|iter| iter.collect())`.
256256+ pub fn get_row(&self, y: usize) -> Option<Vec<&T>> {
257257+ self.iter_row(y).map(|iter| iter.collect())
258258+ }
259259+260260+ /// Get a column of the grid.
261261+ ///
262262+ /// This is the same as `self.iter_col(col).map(|iter| iter.collect())`.
263263+ pub fn get_col(&self, x: usize) -> Option<Vec<&T>> {
264264+ self.iter_col(x).map(|iter| iter.collect())
265265+ }
266266+267267+ /// Iterate over all rows of the grid.
268268+ ///
269269+ /// # Examples
270270+ ///
271271+ /// ```
272272+ /// use utils::prelude::*;
273273+ ///
274274+ ///
275275+ /// let data = vec![
276276+ /// vec![1, 2, 3],
277277+ /// vec![4, 5, 6],
278278+ /// vec![7, 8, 9],
279279+ /// ];
280280+ ///
281281+ /// let grid = Grid::new(data);
282282+ ///
283283+ /// assert_eq!(grid.iter_rows().enumerate().filter_map(|(y, row)| row.collect::<Vec<_>>().get(y).copied()).sum::<usize>(), 1+5+9);
284284+ /// ```
285285+ ///
286286+ pub fn iter_rows(&self) -> impl Iterator<Item = impl Iterator<Item = &T>> {
287287+ self.data.iter().map(|row| row.iter())
288288+ }
289289+290290+ /// Iterate over all columns of the grid.
291291+ ///
292292+ /// # Examples
293293+ ///
294294+ /// ```
295295+ /// use utils::prelude::*;
296296+ ///
297297+ ///
298298+ /// let data = vec![
299299+ /// vec![1, 2, 3],
300300+ /// vec![4, 5, 6],
301301+ /// vec![7, 8, 9],
302302+ /// ];
303303+ ///
304304+ /// let grid = Grid::new(data);
305305+ ///
306306+ /// assert_eq!(grid.iter_cols().enumerate().filter_map(|(x, col)| col.collect::<Vec<_>>().get(x).copied()).sum::<usize>(), 1+5+9);
307307+ /// ```
308308+ ///
309309+ pub fn iter_cols(&self) -> impl Iterator<Item = impl Iterator<Item = &T>> {
310310+ (0..self.width()).map(move |col| self.iter_col(col).unwrap())
311311+ }
312312+313313+ /// Iterate over all elements of the grid.
314314+ ///
315315+ /// This also yields the position of each element for easy access.
316316+ ///
317317+ /// # Examples
318318+ ///
319319+ /// ```
320320+ /// use utils::prelude::*;
321321+ ///
322322+ /// let data = vec![
323323+ /// vec![1, 2, 3],
324324+ /// vec![4, 5, 6],
325325+ /// vec![7, 8, 9],
326326+ /// ];
327327+ ///
328328+ /// let grid = Grid::new(data);
329329+ ///
330330+ /// assert_eq!(grid.iter().map(|(_, v)| v).sum::<usize>(), 1+2+3+4+5+6+7+8+9);
331331+ /// ```
332332+ ///
333333+ pub fn iter(&self) -> impl Iterator<Item = (Position, &T)> {
334334+ self.data.iter().enumerate().flat_map(|(y, row)| {
335335+ row.iter()
336336+ .enumerate()
337337+ .map(move |(x, col)| (Position::new(x as isize, y as isize), col))
338338+ })
339339+ }
340340+341341+ /// Get all positions relative to the given position in the grid based off the given kernels.
342342+ ///
343343+ /// This will automatically filter out any positions that are out of bounds.
344344+ ///
345345+ /// # Examples
346346+ ///
347347+ /// ```
348348+ /// use utils::prelude::*;
349349+ ///
350350+ /// let data = vec![
351351+ /// vec![1, 2, 3],
352352+ /// vec![4, 5, 6],
353353+ /// vec![7, 8, 9],
354354+ /// ];
355355+ ///
356356+ /// let grid = Grid::new(data);
357357+ ///
358358+ /// let pos = Position::new(1, 1);
359359+ /// let kernels = &[
360360+ /// Direction::North,
361361+ /// Direction::East,
362362+ /// ];
363363+ ///
364364+ /// let mut relatives = grid.relatives(pos, kernels);
365365+ ///
366366+ /// assert_eq!(relatives.next(), Some((Direction::North, Position::new(1, 0), &2)));
367367+ /// assert_eq!(relatives.next(), Some((Direction::East, Position::new(2, 1), &6)));
368368+ /// ```
369369+ ///
370370+ /// ```
371371+ /// use utils::prelude::*;
372372+ ///
373373+ /// let data = vec![
374374+ /// vec![1, 2, 3],
375375+ /// vec![4, 5, 6],
376376+ /// vec![7, 8, 9],
377377+ /// ];
378378+ ///
379379+ /// let grid = Grid::new(data);
380380+ ///
381381+ /// let pos = Position::new(1, 0);
382382+ /// let kernels = &[
383383+ /// Direction::North, // This will be filtered out, as (1, -1) is out of bounds
384384+ /// Direction::East,
385385+ /// ];
386386+ ///
387387+ /// let mut relatives = grid.relatives(pos, kernels);
388388+ ///
389389+ /// assert_eq!(relatives.next(), Some((Direction::East, Position::new(2, 0), &3)));
390390+ /// ```
391391+ ///
392392+ pub fn relatives<'a, M: Movement>(
393393+ &'a self,
394394+ pos: Position,
395395+ kernels: &'a [M],
396396+ ) -> impl Iterator<Item = (M, Position, &T)> + 'a {
397397+ pos.relatives(kernels)
398398+ .filter_map(move |(pos, dir)| self.get(pos).map(|v| (dir, pos, v)))
399399+ }
400400+401401+ /// Get all positions relative to the given position in the grid based off the given kernels.
402402+ ///
403403+ /// Wraps around the grid if necessary.
404404+ ///
405405+ pub fn relatives_wrapped<'a, M: Movement>(
406406+ &'a self,
407407+ pos: Position,
408408+ kernels: &'a [M],
409409+ ) -> impl Iterator<Item = (M, Position, &T)> + 'a {
410410+ pos.relatives(kernels)
411411+ .map(move |(pos, dir)| (dir, pos, self.get_wrapped(pos)))
412412+ }
413413+414414+ /// Get all positions relative to the given position in the grid based off the given kernels,
415415+ /// applying the kernel multiple times.
416416+ ///
417417+ /// This will automatically filter out any positions that are out of bounds.
418418+ ///
419419+ pub fn relatives_expand_by<'a, M: Movement>(
420420+ &'a self,
421421+ pos: Position,
422422+ kernels: &'a [M],
423423+ expand: usize,
424424+ ) -> impl Iterator<Item = ((M, usize), Position, &T)> + 'a {
425425+ pos.relatives_expand_by(kernels, expand)
426426+ .filter_map(move |(dir, pos)| self.get(pos).map(|v| (dir, pos, v)))
427427+ }
428428+429429+ /// Get all positions relative to the given position in the grid based off the given kernels,
430430+ /// applying the kernel multiple times.
431431+ ///
432432+ /// Wraps around the grid if necessary.
433433+ ///
434434+ pub fn relatives_expand_by_wrapped<'a, M: Movement>(
435435+ &'a self,
436436+ pos: Position,
437437+ kernels: &'a [M],
438438+ expand: usize,
439439+ ) -> impl Iterator<Item = ((M, usize), Position, &T)> + 'a {
440440+ pos.relatives_expand_by(kernels, expand)
441441+ .map(move |(dir, pos)| (dir, pos, self.get_wrapped(pos)))
442442+ }
443443+444444+ /// Like [Grid::relatives] but with `kernels` set to the four cardinal directions.
445445+ pub fn adjacent<'a>(
446446+ &'a self,
447447+ pos: Position,
448448+ ) -> impl Iterator<Item = (Direction, Position, &T)> + 'a {
449449+ self.relatives(pos, &CARDINALS)
450450+ }
451451+452452+ /// Like [Grid::relatives_wrapped] but with `kernels` set to the four cardinal directions.
453453+ pub fn adjacent_wrapped<'a>(
454454+ &'a self,
455455+ pos: Position,
456456+ ) -> impl Iterator<Item = (Direction, Position, &T)> + 'a {
457457+ self.relatives_wrapped(pos, &CARDINALS)
458458+ }
459459+460460+ /// Like [Grid::relatives_expand_by] but with `kernels` set to the four cardinal directions.
461461+ pub fn adjacent_expand_by<'a>(
462462+ &'a self,
463463+ pos: Position,
464464+ expand: usize,
465465+ ) -> impl Iterator<Item = ((Direction, usize), Position, &T)> + 'a {
466466+ self.relatives_expand_by(pos, &CARDINALS, expand)
467467+ }
468468+469469+ /// Like [Grid::relatives_expand_by_wrapped] but with `kernels` set to the four cardinal directions.
470470+ pub fn adjacent_expand_by_wrapped<'a>(
471471+ &'a self,
472472+ pos: Position,
473473+ expand: usize,
474474+ ) -> impl Iterator<Item = ((Direction, usize), Position, &T)> + 'a {
475475+ self.relatives_expand_by_wrapped(pos, &CARDINALS, expand)
476476+ }
477477+}
478478+479479+impl<T: std::fmt::Debug> std::fmt::Debug for Grid<T> {
480480+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481481+ let mut debug = f.debug_struct("Grid");
482482+ for (y, row) in self.data.iter().enumerate() {
483483+ debug.field(&format!("row_{}", y), row);
484484+ }
485485+ debug.finish()
486486+ }
487487+}
488488+489489+/// Utilities for making tiles of a grid.
490490+pub mod tiles {
491491+ use crate::{dir::Movement, pos::Position};
492492+493493+ use super::Grid;
494494+495495+ #[macro_export]
496496+ /// Create an enum that implements `From<char>`.
497497+ ///
498498+ /// There are three versions of this macro:
499499+ ///
500500+ /// ## 1. Simple
501501+ ///
502502+ /// Create a simple enum that implements `From<char>`, with the specific characters mapping to specific variants.
503503+ /// Also will make the implementation panic if an invalid character is given.
504504+ ///
505505+ /// ```
506506+ /// use utils::prelude::*;
507507+ /// use utils::tiles;
508508+ ///
509509+ /// tiles!(Tile, [
510510+ /// '.' => Floor,
511511+ /// '#' => Wall,
512512+ /// ]);
513513+ ///
514514+ /// assert_eq!(Tile::from('.'), Tile::Floor);
515515+ /// assert_eq!(Tile::from('#'), Tile::Wall);
516516+ /// ```
517517+ ///
518518+ /// ## 2. With Extra Variants
519519+ ///
520520+ /// Create an enum that implements `From<char>`, with the specific characters mapping to specific variants.
521521+ /// Also allows for extra variants to be added, which won't be mapped to any characters.
522522+ ///
523523+ /// ```
524524+ /// use utils::prelude::*;
525525+ /// use utils::tiles;
526526+ ///
527527+ /// tiles!(Tile, [
528528+ /// '.' => Floor,
529529+ /// '#' => Wall,
530530+ /// ], [
531531+ /// Empty,
532532+ /// ]);
533533+ ///
534534+ /// assert_eq!(Tile::from('.'), Tile::Floor);
535535+ /// assert_eq!(Tile::from('#'), Tile::Wall);
536536+ /// let empty = Tile::Empty;
537537+ /// ```
538538+ ///
539539+ /// The extra variants can also have fields.
540540+ ///
541541+ /// ```
542542+ /// use utils::prelude::*;
543543+ /// use utils::tiles;
544544+ ///
545545+ /// tiles!(Tile, [
546546+ /// '.' => Floor,
547547+ /// '#' => Wall,
548548+ /// ], [
549549+ /// Door(bool),
550550+ /// ]);
551551+ ///
552552+ /// assert_eq!(Tile::from('.'), Tile::Floor);
553553+ /// assert_eq!(Tile::from('#'), Tile::Wall);
554554+ /// let door = Tile::Door(true);
555555+ /// ```
556556+ ///
557557+ /// ## 3. With Extra Variants and Extra Logic for Invalid Characters
558558+ ///
559559+ /// Create an enum that implements `From<char>`, with the specific characters mapping to specific variants.
560560+ /// Also allows for extra variants to be added, which won't be mapped to any characters.
561561+ /// Also allows for extra logic to be added for invalid characters.
562562+ ///
563563+ /// ```
564564+ /// use utils::prelude::*;
565565+ /// use utils::tiles;
566566+ ///
567567+ /// tiles!(Tile, [
568568+ /// '.' => Floor,
569569+ /// '#' => Wall,
570570+ /// ], [
571571+ /// Slope(Direction)
572572+ /// ], |c| {
573573+ /// match c {
574574+ /// '>' => Tile::Slope(Direction::East),
575575+ /// '<' => Tile::Slope(Direction::West),
576576+ /// _ => panic!("Invalid tile {c}"),
577577+ /// }
578578+ /// });
579579+ ///
580580+ /// assert_eq!(Tile::from('.'), Tile::Floor);
581581+ /// assert_eq!(Tile::from('#'), Tile::Wall);
582582+ /// assert_eq!(Tile::from('>'), Tile::Slope(Direction::East));
583583+ /// ```
584584+ ///
585585+ macro_rules! tiles {
586586+ ($name:ident, [$($char:pat => $v_name:ident$(,)?)*]) => {
587587+ tiles!($name, [$($char => $v_name,)*], [], |c| { panic!("Invalid tile {c}") });
588588+ };
589589+590590+ ($name:ident, [$($char:pat => $v_name:ident$(,)?)*], [$($e_name:ident$(($($i_name:ty$(,)?)*))?$(,)?)*]) => {
591591+ tiles!($name, [$($char => $v_name,)*], [$($e_name$(($($i_name,)*))?,)*], |c| { panic!("Invalid tile {c}") });
592592+ };
593593+594594+ ($name:ident, [$($char:pat => $v_name:ident$(,)?)*], [$($e_name:ident$(($($i_name:ty$(,)?)*))?$(,)?)*], $default:expr) => {
595595+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
596596+ pub enum $name {
597597+ $($v_name,)*
598598+ $($e_name$(($($i_name,)*))?,)*
599599+ }
600600+601601+ impl From<char> for $name {
602602+ fn from(c: char) -> Self {
603603+ match c {
604604+ $($char => Self::$v_name,)*
605605+ _ => ($default)(c),
606606+ }
607607+ }
608608+ }
609609+ };
610610+ }
611611+612612+ /// Simple tile that holds a number value.
613613+ pub struct NumberTile {
614614+ pub value: isize,
615615+ }
616616+617617+ impl From<char> for NumberTile {
618618+ fn from(c: char) -> Self {
619619+ Self {
620620+ value: c.to_digit(10).unwrap() as isize,
621621+ }
622622+ }
623623+ }
624624+625625+ /// A tile that represents some kind of movement to another position in the grid.
626626+ pub trait DirectedTile<T: Movement>: Copy + Clone {
627627+ /// Get the next direction from the previous direction and position.
628628+ fn next_dir(&self, previous_dir: T, pos: Position) -> Option<T>;
629629+630630+ /// Get the next position and position from the previous direction and position.
631631+ fn next_pos(&self, previous_dir: T, pos: Position) -> Option<(T, Position)> {
632632+ self.next_dir(previous_dir, pos)
633633+ .map(|d| (d, pos.move_dir(d)))
634634+ }
635635+ }
636636+637637+ /// A tile that can be used in a flood fill.
638638+ pub trait FillableTile: Copy + Clone {
639639+ /// Check if the tile can be filled.
640640+ fn get_next_tiles(&self, pos: Position, grid: &Grid<Self>) -> Vec<Position>;
641641+ }
642642+}
643643+644644+/// Utilities for traversing a grid.
645645+pub mod cursors {
646646+647647+ use std::{
648648+ collections::{HashSet, VecDeque},
649649+ hash::Hasher,
650650+ };
651651+652652+ use super::{
653653+ tiles::{DirectedTile, FillableTile},
654654+ *,
655655+ };
656656+657657+ #[derive(Clone, Copy)]
658658+ /// A cursor for traversing a grid.
659659+ ///
660660+ /// This cursor holds a position and a direction which represents the current position in the grid.
661661+ ///
662662+ /// # Examples
663663+ ///
664664+ /// ```
665665+ /// use utils::prelude::*;
666666+ ///
667667+ /// let data = vec![
668668+ /// vec![1, 2, 3],
669669+ /// vec![4, 5, 6],
670670+ /// vec![7, 8, 9],
671671+ /// ];
672672+ ///
673673+ /// let grid = Grid::new(data);
674674+ ///
675675+ /// let mut cursor = GridCursor::zero(&grid);
676676+ ///
677677+ /// assert_eq!(cursor.get(), Some(&1));
678678+ /// cursor.move_forward();
679679+ /// assert_eq!(cursor.get(), Some(&2));
680680+ /// cursor.turn(true);
681681+ /// cursor.move_forward();
682682+ /// assert_eq!(cursor.get(), Some(&5));
683683+ /// ```
684684+ ///
685685+ pub struct GridCursor<'a, T, D: Movement> {
686686+ grid: &'a Grid<T>,
687687+ pos: Position,
688688+ dir: D,
689689+ }
690690+691691+ impl<'a, T> GridCursor<'a, T, Direction> {
692692+ /// Create a new cursor at position (0, 0) facing east.
693693+ pub fn zero(grid: &'a Grid<T>) -> Self {
694694+ Self {
695695+ grid,
696696+ pos: Position::new(0, 0),
697697+ dir: Direction::East,
698698+ }
699699+ }
700700+701701+ /// Turn the cursor 90 degrees clockwise or counter-clockwise.
702702+ pub fn turn(&mut self, clockwise: bool) {
703703+ self.dir = self.dir.ninety_deg(clockwise);
704704+ }
705705+706706+ /// Turn the cursor 180 degrees.
707707+ pub fn turn_around(&mut self) {
708708+ self.dir = self.dir.opposite();
709709+ }
710710+ }
711711+712712+ impl<'a, T, D: Movement> PartialEq for GridCursor<'a, T, D> {
713713+ fn eq(&self, other: &Self) -> bool {
714714+ self.pos == other.pos && self.dir == other.dir
715715+ }
716716+ }
717717+718718+ impl<'a, T, D: Movement> std::hash::Hash for GridCursor<'a, T, D> {
719719+ fn hash<H: Hasher>(&self, state: &mut H) {
720720+ self.pos.hash(state);
721721+ self.dir.hash(state);
722722+ }
723723+ }
724724+725725+ impl<'a, T, D: Movement> GridCursor<'a, T, D> {
726726+ /// Create a new cursor at the given position and direction.
727727+ pub fn new(grid: &'a Grid<T>, pos: Position, dir: D) -> Self {
728728+ Self { grid, pos, dir }
729729+ }
730730+731731+ /// Move the cursor forward one step in the direction it is facing.
732732+ pub fn move_forward(&mut self) {
733733+ self.pos = self.pos.move_dir(self.dir);
734734+ }
735735+736736+ /// Get the value at the current position of the cursor.
737737+ pub fn get(&self) -> Option<&T> {
738738+ self.grid.get(self.pos)
739739+ }
740740+741741+ /// Move the cursor forward one step in the direction it is facing and get the value at the new position.
742742+ pub fn next(&mut self) -> Option<&T> {
743743+ self.move_forward();
744744+ self.get()
745745+ }
746746+ }
747747+748748+ impl<'a, T: std::fmt::Debug, D: Movement> std::fmt::Debug for GridCursor<'a, T, D> {
749749+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
750750+ f.debug_struct("GridCursor")
751751+ .field("pos", &self.pos)
752752+ .field("dir", &self.dir)
753753+ .field("value", &self.get())
754754+ .finish()
755755+ }
756756+ }
757757+758758+ /// A cursor for traversing a grid with a direction.
759759+ ///
760760+ /// This cursor will follow the direction of the tile it is currently on.
761761+ ///
762762+ /// # Examples
763763+ ///
764764+ /// ```
765765+ /// use utils::prelude::*;
766766+ /// use utils::tiles;
767767+ ///
768768+ /// tiles!(Tile, [
769769+ /// '>' => Right,
770770+ /// '<' => Left,
771771+ /// '^' => Up,
772772+ /// 'v' => Down,
773773+ /// ]);
774774+ ///
775775+ /// impl DirectedTile<Direction> for Tile {
776776+ /// fn next_dir(&self, previous_dir: Direction, pos: Position) -> Option<Direction> {
777777+ /// match self {
778778+ /// Tile::Right => Some(Direction::East),
779779+ /// Tile::Left => Some(Direction::West),
780780+ /// Tile::Up => Some(Direction::North),
781781+ /// Tile::Down => Some(Direction::South),
782782+ /// _ => None,
783783+ /// }
784784+ /// }
785785+ /// }
786786+ ///
787787+ /// let data = vec![
788788+ /// vec![Tile::Right, Tile::Right, Tile::Down],
789789+ /// vec![Tile::Up, Tile::Left, Tile::Down],
790790+ /// vec![Tile::Up, Tile::Left, Tile::Left],
791791+ /// ];
792792+ ///
793793+ /// let grid = Grid::new(data);
794794+ ///
795795+ /// let mut cursor = DirectedCursor::new(&grid, Position::new(0, 0), Direction::East);
796796+ ///
797797+ /// let path = cursor.map(|(p, _, _)| p).take(8).collect::<Vec<_>>();
798798+ ///
799799+ /// assert_eq!(path, vec![
800800+ /// Position::new(1, 0),
801801+ /// Position::new(2, 0),
802802+ /// Position::new(2, 1),
803803+ /// Position::new(2, 2),
804804+ /// Position::new(1, 2),
805805+ /// Position::new(0, 2),
806806+ /// Position::new(0, 1),
807807+ /// Position::new(0, 0),
808808+ /// ]);
809809+ /// ```
810810+ ///
811811+ pub struct DirectedCursor<'a, T: DirectedTile<D>, D: Movement>(GridCursor<'a, T, D>);
812812+813813+ impl<'a, T: DirectedTile<D>, D: Movement> DirectedCursor<'a, T, D> {
814814+ /// Create a new cursor at the given position and direction.
815815+ /// Note this starting position will *not* be included in the iterator.
816816+ pub fn new(grid: &'a Grid<T>, pos: Position, dir: D) -> Self {
817817+ let initial_cursor = GridCursor::new(grid, pos, dir);
818818+ Self(initial_cursor)
819819+ }
820820+ }
821821+822822+ impl<'a, T: DirectedTile<D>, D: Movement> Iterator for DirectedCursor<'a, T, D> {
823823+ type Item = (Position, D, T);
824824+825825+ fn next(&mut self) -> Option<Self::Item> {
826826+ let current_val = self.0.get().cloned();
827827+ current_val.and_then(|tile| {
828828+ tile.next_pos(self.0.dir, self.0.pos).map(|(dir, pos)| {
829829+ self.0.dir = dir;
830830+ self.0.pos = pos;
831831+ (self.0.pos, self.0.dir, tile)
832832+ })
833833+ })
834834+ }
835835+ }
836836+837837+ /// A cursor that flood fills a grid.
838838+ ///
839839+ /// This cursor will flood fill the grid from the given position,
840840+ /// using [FillableTile::get_next_tiles] to determine which tiles to fill.
841841+ ///
842842+ /// Setting `wrapped` to true will make the cursor wrap around the grid if necessary.
843843+ /// Note this can lead to infinite loops if you don't have something to stop the iterator.
844844+ ///
845845+ /// # Examples
846846+ ///
847847+ /// ```
848848+ /// use utils::prelude::*;
849849+ /// use utils::tiles;
850850+ ///
851851+ /// tiles!(Tile, [
852852+ /// '.' => Floor,
853853+ /// '#' => Wall,
854854+ /// ]);
855855+ ///
856856+ /// impl FillableTile for Tile {
857857+ /// fn get_next_tiles(&self, pos: Position, grid: &Grid<Self>) -> Vec<Position> {
858858+ /// match self {
859859+ /// Tile::Floor => grid.adjacent(pos).filter(|(_, _, t)| t == &&Tile::Floor).map(|(_, p, _)| p).collect(),
860860+ /// _ => vec![],
861861+ /// }
862862+ /// }
863863+ /// }
864864+ ///
865865+ /// let data = vec![
866866+ /// vec![Tile::Floor, Tile::Floor, Tile::Floor],
867867+ /// vec![Tile::Floor, Tile::Wall, Tile::Floor],
868868+ /// vec![Tile::Floor, Tile::Floor, Tile::Wall],
869869+ /// ];
870870+ ///
871871+ /// let grid = Grid::new(data);
872872+ ///
873873+ /// let mut cursor = FloodFillCursor::new(&grid, Position::new(0, 0), true);
874874+ ///
875875+ /// let path = cursor.collect::<Vec<_>>();
876876+ ///
877877+ /// assert_eq!(path, vec![
878878+ /// Position::new(0, 0),
879879+ /// Position::new(0, 1),
880880+ /// Position::new(1, 0),
881881+ /// Position::new(0, 2),
882882+ /// Position::new(2, 0),
883883+ /// Position::new(1, 2),
884884+ /// Position::new(2, 1),
885885+ /// ]);
886886+ /// ```
887887+ ///
888888+ pub struct FloodFillCursor<'a, T: FillableTile> {
889889+ grid: &'a Grid<T>,
890890+ visited: HashSet<Position>,
891891+ queue: VecDeque<Position>,
892892+ wrapped: bool,
893893+ }
894894+895895+ impl<'a, T: FillableTile> FloodFillCursor<'a, T> {
896896+ /// Create a new cursor at the given position.
897897+ pub fn new(grid: &'a Grid<T>, pos: Position, wrapped: bool) -> Self {
898898+ let mut visited = HashSet::new();
899899+ visited.insert(pos);
900900+ let mut queue = VecDeque::new();
901901+ queue.push_back(pos);
902902+ Self {
903903+ grid,
904904+ visited,
905905+ queue,
906906+ wrapped,
907907+ }
908908+ }
909909+ }
910910+911911+ impl<'a, T: FillableTile> std::fmt::Debug for FloodFillCursor<'a, T> {
912912+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
913913+ f.debug_struct("FloodFillCursor")
914914+ .field("visited", &self.visited)
915915+ .field("queue", &self.queue)
916916+ .finish()
917917+ }
918918+ }
919919+920920+ impl<'a, T: FillableTile> Iterator for FloodFillCursor<'a, T> {
921921+ type Item = Position;
922922+923923+ fn next(&mut self) -> Option<Self::Item> {
924924+ let pos = self.queue.pop_front()?;
925925+ let tile = if self.wrapped {
926926+ self.grid.get_wrapped(pos)
927927+ } else {
928928+ self.grid.get(pos)?
929929+ };
930930+ for next_pos in tile.get_next_tiles(pos, self.grid) {
931931+ if self.visited.insert(next_pos) {
932932+ self.queue.push_back(next_pos);
933933+ }
934934+ }
935935+ Some(pos)
936936+ }
937937+ }
938938+}
+17-12
utils/src/lib.rs
···11-pub fn add(left: usize, right: usize) -> usize {
22- left + right
33-}
11+pub mod day_utils;
22+pub mod dir;
33+pub mod geom;
44+pub mod grid;
55+pub mod line;
66+pub mod pos;
77+pub mod range;
4855-#[cfg(test)]
66-mod tests {
77- use super::*;
88-99- #[test]
1010- fn it_works() {
1111- let result = add(2, 2);
1212- assert_eq!(result, 4);
1313- }
99+pub mod prelude {
1010+ pub use crate::day_utils::*;
1111+ pub use crate::dir::*;
1212+ pub use crate::geom;
1313+ pub use crate::grid::cursors::*;
1414+ pub use crate::grid::tiles::*;
1515+ pub use crate::grid::*;
1616+ pub use crate::line::*;
1717+ pub use crate::pos::*;
1818+ pub use crate::range::*;
1419}
+171
utils/src/line.rs
···11+use std::ops::Neg;
22+33+use crate::{dir::Direction, pos::Position};
44+55+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66+/// A line between two points.
77+///
88+/// This line is represented by two [Position]s.
99+///
1010+/// # Examples
1111+///
1212+/// ```
1313+/// use utils::prelude::*;
1414+///
1515+/// let line = Line::new(Position::new(0, 0), Position::new(1, 1));
1616+/// assert_eq!(line.get_slope(), 1.0);
1717+/// assert_eq!(line.get_intercept(), 0.0);
1818+/// ```
1919+///
2020+pub struct Line(Position, Position);
2121+2222+impl Line {
2323+ /// Create a new line between two points.
2424+ ///
2525+ /// # Examples
2626+ ///
2727+ /// ```
2828+ /// use utils::prelude::*;
2929+ ///
3030+ /// let line = Line::new(Position::new(0, 0), Position::new(1, 1));
3131+ /// assert_eq!(line.end().x, 1);
3232+ /// ```
3333+ ///
3434+ pub fn new(start: Position, end: Position) -> Self {
3535+ Self(start, end)
3636+ }
3737+3838+ /// Create a new line from a starting point and a direction.
3939+ ///
4040+ /// # Examples
4141+ ///
4242+ /// ```
4343+ /// use utils::prelude::*;
4444+ ///
4545+ /// let line = Line::from_dir(Position::new(0, 0), Direction::East);
4646+ /// assert_eq!(line.end().x, 1);
4747+ /// ```
4848+ ///
4949+ pub fn from_dir(start: Position, dir: Direction) -> Self {
5050+ Self(start, start.move_dir(dir))
5151+ }
5252+5353+ /// Get the linear slope of the line.
5454+ ///
5555+ /// # Examples
5656+ ///
5757+ /// ```
5858+ /// use utils::prelude::*;
5959+ ///
6060+ /// let line = Line::new(Position::new(0, 0), Position::new(1, 1));
6161+ /// assert_eq!(line.get_slope(), 1.0);
6262+ ///
6363+ /// let line = Line::new(Position::new(0, 0), Position::new(2, 1));
6464+ /// assert_eq!(line.get_slope(), 0.5);
6565+ /// ```
6666+ ///
6767+ pub fn get_slope(&self) -> f64 {
6868+ let dx = self.1.x - self.0.x;
6969+ let dy = self.1.y - self.0.y;
7070+ dy as f64 / dx as f64
7171+ }
7272+7373+ /// Get the y-intercept of the line.
7474+ ///
7575+ /// # Examples
7676+ ///
7777+ /// ```
7878+ /// use utils::prelude::*;
7979+ ///
8080+ /// let line = Line::new(Position::new(0, 0), Position::new(1, 1));
8181+ /// assert_eq!(line.get_intercept(), 0.0);
8282+ ///
8383+ /// let line = Line::new(Position::new(0, 5), Position::new(2, 1));
8484+ /// assert_eq!(line.get_intercept(), 5.0);
8585+ /// ```
8686+ ///
8787+ pub fn get_intercept(&self) -> f64 {
8888+ let slope = self.get_slope();
8989+ self.0.y as f64 - slope * self.0.x as f64
9090+ }
9191+9292+ /// Check that the given point is *after* the start position on the line.
9393+ ///
9494+ /// Note this doesn't check if the point is on the line, just that it is
9595+ /// on the same side of the line as the end point.
9696+ ///
9797+ /// # Examples
9898+ ///
9999+ /// ```
100100+ /// use utils::prelude::*;
101101+ ///
102102+ /// let line = Line::new(Position::new(0, 0), Position::new(2, 2));
103103+ /// assert_eq!(line.check_after(&Position::new(1, 1)), true);
104104+ ///
105105+ /// let line = Line::new(Position::new(0, 0), Position::new(2, 2));
106106+ /// assert_eq!(line.check_after(&Position::new(-1, -1)), false);
107107+ /// ```
108108+ ///
109109+ pub fn check_after(&self, pos: &Position) -> bool {
110110+ let relative = pos.sub(&self.0);
111111+ let d = self.1.sub(&self.0);
112112+ relative.normalize() == d.normalize()
113113+ }
114114+115115+ /// Get the intersection point between this line and another.
116116+ ///
117117+ /// Pass `check_after` as `true` to ensure that the intersection point is
118118+ /// after the start of both lines.
119119+ ///
120120+ /// # Examples
121121+ ///
122122+ /// ```
123123+ /// use utils::prelude::*;
124124+ ///
125125+ /// let line1 = Line::new(Position::new(2, -2), Position::new(-2, 2));
126126+ /// let line2 = Line::new(Position::new(2, 2), Position::new(-2, -2));
127127+ /// assert_eq!(line1.get_intersection(&line2, true), Some(Position::new(0, 0)));
128128+ ///
129129+ /// let line1 = Line::new(Position::new(5, 0), Position::new(6, 8));
130130+ /// let line2 = Line::new(Position::new(0, 1), Position::new(-4, -3));
131131+ /// assert_eq!(line1.get_intersection(&line2, true), None);
132132+ /// ```
133133+ ///
134134+ pub fn get_intersection(&self, other: &Self, check_after: bool) -> Option<Position> {
135135+ let slope = self.get_slope();
136136+ let intercept = self.get_intercept();
137137+ let other_slope = other.get_slope();
138138+ let other_intercept = other.get_intercept();
139139+140140+ if slope == other_slope {
141141+ return None;
142142+ }
143143+144144+ let x = (other_intercept - intercept) / (slope - other_slope);
145145+ let y = slope * x + intercept;
146146+147147+ let point = Position::new(x as isize, y as isize);
148148+149149+ if !check_after || self.check_after(&point) && other.check_after(&point) {
150150+ Some(point)
151151+ } else {
152152+ None
153153+ }
154154+ }
155155+156156+ pub fn start(&self) -> Position {
157157+ self.0
158158+ }
159159+160160+ pub fn end(&self) -> Position {
161161+ self.1
162162+ }
163163+}
164164+165165+impl Neg for Line {
166166+ type Output = Self;
167167+168168+ fn neg(self) -> Self::Output {
169169+ Self(self.1, self.0)
170170+ }
171171+}
+775
utils/src/pos.rs
···11+/// Position utilities
22+use std::{
33+ fmt::{Debug, Display},
44+ ops::{Add, Mul, Neg, Sub},
55+ str::FromStr,
66+};
77+88+use crate::dir::{Direction, Movement, CARDINALS};
99+1010+type CompType = isize;
1111+type PositiveType = (usize, usize);
1212+1313+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1414+/// A position in 2D space on an integer grid
1515+/// This is meant to represent indices of a 2D array, so north is negative y
1616+///
1717+/// This is also used to represent a vector in 2D space at times
1818+pub struct Position {
1919+ pub x: CompType,
2020+ pub y: CompType,
2121+}
2222+2323+impl Position {
2424+ /// Create a new position
2525+ pub fn new(x: CompType, y: CompType) -> Self {
2626+ Self { x, y }
2727+ }
2828+2929+ /// Create a new position at 0, 0
3030+ pub fn zero() -> Self {
3131+ Self { x: 0, y: 0 }
3232+ }
3333+3434+ /// Create the unit vector position
3535+ pub fn one() -> Self {
3636+ Self { x: 1, y: 1 }
3737+ }
3838+3939+ /// Get the position flipped over the line y = x
4040+ ///
4141+ /// # Examples
4242+ ///
4343+ /// ```
4444+ /// use utils::prelude::*;
4545+ ///
4646+ /// let flipped = Position::new(1, 2).flip();
4747+ /// assert_eq!(flipped, Position::new(2, 1));
4848+ /// ```
4949+ ///
5050+ pub fn flip(&self) -> Self {
5151+ Self {
5252+ x: self.y,
5353+ y: self.x,
5454+ }
5555+ }
5656+5757+ /// Normalize a position to a unit vector
5858+ ///
5959+ /// # Examples
6060+ ///
6161+ /// ```
6262+ /// use utils::prelude::*;
6363+ ///
6464+ /// let normalized = Position::new(1, 1).normalize();
6565+ /// assert_eq!(normalized, Position::new(1, 1));
6666+ ///
6767+ /// let normalized = Position::new(50, -45).normalize();
6868+ /// assert_eq!(normalized, Position::new(1, -1));
6969+ ///
7070+ /// let normalized = Position::new(-30, 0).normalize();
7171+ /// assert_eq!(normalized, Position::new(-1, 0));
7272+ /// ```
7373+ ///
7474+ pub fn normalize(&self) -> Self {
7575+ Self {
7676+ x: self.x.signum(),
7777+ y: self.y.signum(),
7878+ }
7979+ }
8080+8181+ /// Get the magnitude of a position
8282+ ///
8383+ /// # Examples
8484+ ///
8585+ /// ```
8686+ /// use utils::prelude::*;
8787+ ///
8888+ /// let mag = Position::new(0, 1).magnitude();
8989+ /// assert_eq!(mag, 1.0);
9090+ ///
9191+ /// let mag = Position::new(3, 4).magnitude();
9292+ /// assert_eq!(mag, 5.0);
9393+ /// ```
9494+ ///
9595+ pub fn magnitude(&self) -> f64 {
9696+ (((self.x * self.x) + (self.y * self.y)) as f64).sqrt()
9797+ }
9898+9999+ /// Get the absolute value of a position
100100+ ///
101101+ /// # Examples
102102+ ///
103103+ /// ```
104104+ /// use utils::prelude::*;
105105+ ///
106106+ /// let abs = Position::new(-1, -1).abs();
107107+ /// assert_eq!(abs, Position::new(1, 1));
108108+ /// ```
109109+ ///
110110+ pub fn abs(&self) -> Self {
111111+ Self {
112112+ x: self.x.abs(),
113113+ y: self.y.abs(),
114114+ }
115115+ }
116116+117117+ /// Sum the components of a position
118118+ ///
119119+ /// # Examples
120120+ ///
121121+ /// ```
122122+ /// use utils::prelude::*;
123123+ ///
124124+ /// let sum = Position::new(1, 1).sum();
125125+ /// assert_eq!(sum, 2);
126126+ /// ```
127127+ ///
128128+ pub fn sum(&self) -> CompType {
129129+ self.x + self.y
130130+ }
131131+132132+ /// Get the difference between the components of a position
133133+ ///
134134+ /// # Examples
135135+ ///
136136+ /// ```
137137+ /// use utils::prelude::*;
138138+ ///
139139+ /// let diff = Position::new(1, 1).diff();
140140+ /// assert_eq!(diff, 0);
141141+ /// ```
142142+ ///
143143+ pub fn diff(&self) -> CompType {
144144+ self.x - self.y
145145+ }
146146+147147+ /// Get the direction of one position relative to another
148148+ ///
149149+ /// This is the direction that the second position is from the first
150150+ ///
151151+ /// Meaning
152152+ ///
153153+ /// ```txt
154154+ /// ...
155155+ /// A.B
156156+ /// ...
157157+ ///
158158+ /// A.get_dir(B) == Direction::East
159159+ /// and
160160+ /// B.get_dir(A) == Direction::West
161161+ /// ```
162162+ ///
163163+ /// # Panics
164164+ ///
165165+ /// If the positions are the same or diagonal from each other
166166+ ///
167167+ /// # Examples
168168+ ///
169169+ /// ```
170170+ /// use utils::prelude::*;
171171+ ///
172172+ /// let dir = Position::new(1, 1).get_dir(&Position::new(5, 1));
173173+ /// assert_eq!(dir, Direction::East);
174174+ ///
175175+ /// let dir = Position::new(5, 1).get_dir(&Position::new(1, 1));
176176+ /// assert_eq!(dir, Direction::West);
177177+ ///
178178+ /// let dir = Position::new(1, 1).get_dir(&Position::new(1, 5));
179179+ /// assert_eq!(dir, Direction::South);
180180+ /// ```
181181+ ///
182182+ pub fn get_dir(&self, other: &Self) -> Direction {
183183+ other.sub(self).normalize().into()
184184+ }
185185+186186+ /// Add two positions together
187187+ ///
188188+ /// # Examples
189189+ ///
190190+ /// ```
191191+ /// use utils::prelude::*;
192192+ ///
193193+ /// let sum = Position::new(1, 1).add(&Position::new(5, 4));
194194+ /// assert_eq!(sum, Position::new(6, 5));
195195+ /// ```
196196+ ///
197197+ pub fn add(&self, other: &Self) -> Self {
198198+ Self {
199199+ x: self.x + other.x,
200200+ y: self.y + other.y,
201201+ }
202202+ }
203203+204204+ /// Get the difference between two positions
205205+ ///
206206+ /// # Examples
207207+ ///
208208+ /// ```
209209+ /// use utils::prelude::*;
210210+ ///
211211+ /// let diff = Position::new(1, 1).sub(&Position::new(5, 5));
212212+ /// assert_eq!(diff, Position::new(-4, -4));
213213+ /// ```
214214+ ///
215215+ pub fn sub(&self, other: &Self) -> Self {
216216+ Self {
217217+ x: self.x - other.x,
218218+ y: self.y - other.y,
219219+ }
220220+ }
221221+222222+ /// Multiply two positions together
223223+ ///
224224+ /// # Examples
225225+ ///
226226+ /// ```
227227+ /// use utils::prelude::*;
228228+ ///
229229+ /// let multiplied = Position::new(1, 1).multiply(&Position::new(5, 4));
230230+ /// assert_eq!(multiplied, Position::new(5, 4));
231231+ /// ```
232232+ ///
233233+ pub fn multiply(&self, other: &Self) -> Self {
234234+ Self {
235235+ x: self.x * other.x,
236236+ y: self.y * other.y,
237237+ }
238238+ }
239239+240240+ /// Get the dot product of two positions
241241+ ///
242242+ /// x1 * x2 + y1 * y2
243243+ ///
244244+ /// # Examples
245245+ ///
246246+ /// ```
247247+ /// use utils::prelude::*;
248248+ ///
249249+ /// let dot = Position::new(1, 1).dot(&Position::new(5, 4));
250250+ /// assert_eq!(dot, 9);
251251+ /// ```
252252+ ///
253253+ pub fn dot(&self, other: &Self) -> CompType {
254254+ self.multiply(other).sum()
255255+ }
256256+257257+ /// Get the angle between two positions
258258+ ///
259259+ /// # Examples
260260+ ///
261261+ /// ```
262262+ /// use utils::prelude::*;
263263+ ///
264264+ /// let angle = Position::new(0, 1).angle(&Position::new(1, 0));
265265+ ///
266266+ /// assert_eq!(angle, std::f64::consts::FRAC_PI_2);
267267+ /// ```
268268+ ///
269269+ pub fn angle(&self, other: &Self) -> f64 {
270270+ let dot = self.dot(other) as f64;
271271+ let mag = self.magnitude() * other.magnitude();
272272+ (dot / mag).acos()
273273+ }
274274+275275+ /// Get the cross product of two positions
276276+ ///
277277+ /// x1 * y2 - y1 * x2
278278+ ///
279279+ /// # Examples
280280+ ///
281281+ /// ```
282282+ /// use utils::prelude::*;
283283+ ///
284284+ /// let cross = Position::new(2, 3).cross(&Position::new(5, 4));
285285+ /// assert_eq!(cross, -7);
286286+ /// ```
287287+ ///
288288+ pub fn cross(&self, other: &Self) -> CompType {
289289+ self.multiply(&other.flip()).diff()
290290+ }
291291+292292+ /// Multiply a position by a scalar
293293+ ///
294294+ /// # Examples
295295+ ///
296296+ /// ```
297297+ /// use utils::prelude::*;
298298+ ///
299299+ /// let multiplied = Position::new(1, 1).multiply_comp(5);
300300+ /// assert_eq!(multiplied, Position::new(5, 5));
301301+ /// ```
302302+ ///
303303+ pub fn multiply_comp(&self, other: CompType) -> Self {
304304+ Self {
305305+ x: self.x * other,
306306+ y: self.y * other,
307307+ }
308308+ }
309309+310310+ /// Get the manhattan distance between two positions
311311+ ///
312312+ /// # Examples
313313+ ///
314314+ /// ```
315315+ /// use utils::prelude::*;
316316+ ///
317317+ /// let distance = Position::new(1, 1).manhattan(&Position::new(5, 5));
318318+ /// assert_eq!(distance, 8);
319319+ /// ```
320320+ ///
321321+ pub fn manhattan(&self, other: &Self) -> CompType {
322322+ self.sub(other).abs().sum()
323323+ }
324324+325325+ /// Get the chebyshev distance between two positions
326326+ ///
327327+ /// # Examples
328328+ ///
329329+ /// ```
330330+ /// use utils::prelude::*;
331331+ ///
332332+ /// let distance = Position::new(1, 1).chebyshev(&Position::new(5, 5));
333333+ /// assert_eq!(distance, 4);
334334+ /// ```
335335+ ///
336336+ pub fn chebyshev(&self, other: &Self) -> CompType {
337337+ let diff = self.sub(other).abs();
338338+ diff.x.max(diff.y)
339339+ }
340340+341341+ /// Check if a component is within a range of 0..bound
342342+ /// Note bound is exclusive
343343+ fn check_comp(comp: CompType, bound: usize) -> bool {
344344+ (0..(bound as isize)).contains(&comp)
345345+ }
346346+347347+ /// Check if a position is within a range of (0..bound.0, 0..bound.1)
348348+ /// Note bound is exclusive
349349+ ///
350350+ /// # Examples
351351+ ///
352352+ /// ```
353353+ /// use utils::prelude::*;
354354+ ///
355355+ /// let checked = Position::new(0, 0).check((10, 10));
356356+ /// assert!(checked);
357357+ ///
358358+ /// let checked = Position::new(50, 50).check((5, 5));
359359+ /// assert_eq!(checked, false);
360360+ /// ```
361361+ ///
362362+ pub fn check(&self, bounds: PositiveType) -> bool {
363363+ Self::check_comp(self.x, bounds.0) && Self::check_comp(self.y, bounds.1)
364364+ }
365365+366366+ /// Normalize a value to be within a range of 0..bound
367367+ /// Note bound is exclusive
368368+ ///
369369+ /// # Examples
370370+ ///
371371+ /// ```
372372+ /// use utils::prelude::*;
373373+ ///
374374+ /// let normalized = Position::bind_comp(-1, 10);
375375+ /// assert_eq!(normalized, 9);
376376+ ///
377377+ /// let normalized = Position::bind_comp(-10, 5);
378378+ /// assert_eq!(normalized, 0);
379379+ ///
380380+ /// let normalized = Position::bind_comp(10, 5);
381381+ /// assert_eq!(normalized, 0);
382382+ ///
383383+ /// let normalized = Position::bind_comp(3, 6);
384384+ /// assert_eq!(normalized, 3);
385385+ /// ```
386386+ ///
387387+ pub fn bind_comp(comp: CompType, bound: usize) -> usize {
388388+ let bound = bound as isize;
389389+ if comp >= bound || comp.is_negative() {
390390+ let ans = comp % bound;
391391+ if ans.is_negative() {
392392+ (ans + bound) as usize
393393+ } else {
394394+ ans as usize
395395+ }
396396+ } else {
397397+ comp as usize
398398+ }
399399+ }
400400+401401+ /// Bind a position to be within ranges of (0..bound.0, 0..bound.1)
402402+ /// Note bound is exclusive
403403+ ///
404404+ /// # Examples
405405+ ///
406406+ /// ```
407407+ /// use utils::prelude::*;
408408+ ///
409409+ /// let bound = Position::new(-1, -1).bind((11, 11));
410410+ /// assert_eq!(bound, (10, 10));
411411+ ///
412412+ /// let bound = Position::new(-10, -10).bind((6, 6));
413413+ /// assert_eq!(bound, (2, 2));
414414+ ///
415415+ /// let bound = Position::new(10, 10).bind((6, 6));
416416+ /// assert_eq!(bound, (4, 4));
417417+ /// ```
418418+ ///
419419+ pub fn bind(&self, bounds: PositiveType) -> PositiveType {
420420+ (
421421+ Self::bind_comp(self.x, bounds.0),
422422+ Self::bind_comp(self.y, bounds.1),
423423+ )
424424+ }
425425+426426+ /// Move a position by direction
427427+ ///
428428+ /// # Examples
429429+ ///
430430+ /// ```
431431+ /// use utils::prelude::*;
432432+ ///
433433+ /// let moved = Position::new(0, 0).move_dir(Direction::North);
434434+ /// assert_eq!(moved, Position::new(0, -1));
435435+ ///
436436+ /// let moved = Position::new(0, 0).move_dir(Direction::East);
437437+ /// assert_eq!(moved, Position::new(1, 0));
438438+ /// ```
439439+ ///
440440+ pub fn move_dir(&self, dir: impl Movement) -> Self {
441441+ self.add(&dir.get_kernel())
442442+ }
443443+444444+ /// Move a position by direction a certain number of times
445445+ ///
446446+ /// # Examples
447447+ ///
448448+ /// ```
449449+ /// use utils::prelude::*;
450450+ ///
451451+ /// let moved = Position::new(0, 0).move_times(Direction::North, 5);
452452+ /// assert_eq!(moved, Position::new(0, -5));
453453+ /// ```
454454+ ///
455455+ pub fn move_times(&self, dir: impl Movement, times: usize) -> Self {
456456+ self.add(&dir.get_kernel().multiply_comp(times as isize))
457457+ }
458458+459459+ /// Move a position by direction,
460460+ /// checking if it is within a range of (0..bound.0, 0..bound.1)
461461+ ///
462462+ /// # Returns
463463+ ///
464464+ /// * `Some(Position)` if the new position is within the bounds
465465+ /// * `None` if the new position is outside the bounds
466466+ ///
467467+ /// # Examples
468468+ ///
469469+ /// ```
470470+ /// use utils::prelude::*;
471471+ ///
472472+ /// let moved = Position::new(0, 0).move_dir_checked(Direction::East, (10, 10));
473473+ /// assert_eq!(moved.unwrap(), Position::new(1, 0));
474474+ ///
475475+ /// let moved = Position::new(40, 40).move_dir_checked(Direction::East, (40, 40));
476476+ /// assert!(moved.is_none());
477477+ /// ```
478478+ ///
479479+ pub fn move_dir_checked(&self, dir: impl Movement, bounds: PositiveType) -> Option<Self> {
480480+ let new = self.move_dir(dir);
481481+ if new.check(bounds) {
482482+ Some(new)
483483+ } else {
484484+ None
485485+ }
486486+ }
487487+488488+ /// Move a position by direction a certain number of times,
489489+ /// checking if it is within a range of (0..bound.0, 0..bound.1)
490490+ ///
491491+ /// # Returns
492492+ ///
493493+ /// * `Some(Position)` if the new position is within the bounds
494494+ /// * `None` if the new position is outside the bounds
495495+ ///
496496+ pub fn move_times_checked(
497497+ &self,
498498+ dir: impl Movement,
499499+ times: usize,
500500+ bounds: PositiveType,
501501+ ) -> Option<Self> {
502502+ let new = self.move_times(dir, times);
503503+ if new.check(bounds) {
504504+ Some(new)
505505+ } else {
506506+ None
507507+ }
508508+ }
509509+510510+ /// Get all positions relative to this position by a list of directions
511511+ ///
512512+ /// # Examples
513513+ ///
514514+ /// ```
515515+ /// use utils::prelude::*;
516516+ ///
517517+ /// let relatives = Position::new(0, 0).relatives(&[Direction::North, Direction::East]).collect::<Vec<_>>();
518518+ /// assert_eq!(relatives, vec![(Position::new(0, -1), Direction::North), (Position::new(1, 0), Direction::East)]);
519519+ /// ```
520520+ ///
521521+ pub fn relatives<'a, T: Movement>(
522522+ self,
523523+ kernels: &'a [T],
524524+ ) -> impl Iterator<Item = (Self, T)> + 'a {
525525+ kernels.into_iter().map(move |k| (self.move_dir(*k), *k))
526526+ }
527527+528528+ /// Get all positions relative to this position by a list of directions,
529529+ /// checking if they are within a range of (0..bound.0, 0..bound.1)
530530+ ///
531531+ /// # Examples
532532+ ///
533533+ /// ```
534534+ /// use utils::prelude::*;
535535+ ///
536536+ /// let relatives = Position::new(0, 0).relatives_checked(&[Direction::North, Direction::East], (10, 10)).collect::<Vec<_>>();
537537+ /// assert_eq!(relatives, vec![(Position::new(1, 0), Direction::East)]);
538538+ /// ```
539539+ ///
540540+ pub fn relatives_checked<'a, T: Movement>(
541541+ self,
542542+ kernels: &'a [T],
543543+ bounds: PositiveType,
544544+ ) -> impl Iterator<Item = (Self, T)> + 'a {
545545+ kernels
546546+ .iter()
547547+ .filter_map(move |k| self.move_dir_checked(*k, bounds).map(|p| (p, *k)))
548548+ }
549549+550550+ /// Get all positions relative to this position by a list of directions,
551551+ /// repeating each direction a certain number of times
552552+ ///
553553+ /// # Examples
554554+ ///
555555+ /// ```
556556+ /// use utils::prelude::*;
557557+ ///
558558+ /// let relatives = Position::new(0, 0).relatives_expand_by(&[Direction::North, Direction::East], 2).collect::<Vec<_>>();
559559+ /// let expected = vec![
560560+ /// ((Direction::North, 1), Position::new(0, -1)),
561561+ /// ((Direction::North, 2), Position::new(0, -2)),
562562+ /// ((Direction::East, 1), Position::new(1, 0)),
563563+ /// ((Direction::East, 2), Position::new(2, 0)),
564564+ /// ];
565565+ ///
566566+ /// assert_eq!(relatives, expected);
567567+ /// ```
568568+ ///
569569+ pub fn relatives_expand_by<'a, T: Movement>(
570570+ self,
571571+ kernels: &'a [T],
572572+ times: usize,
573573+ ) -> impl Iterator<Item = ((T, usize), Self)> + 'a {
574574+ kernels
575575+ .into_iter()
576576+ .flat_map(move |k| (1..=times).map(move |t| ((*k, t), self.move_times(*k, t))))
577577+ }
578578+579579+ /// Get all positions relative to this position by a list of directions,
580580+ /// repeating each direction a certain number of times,
581581+ /// checking if they are within a range of (0..bound.0, 0..bound.1)
582582+ ///
583583+ /// # Examples
584584+ ///
585585+ /// ```
586586+ /// use utils::prelude::*;
587587+ ///
588588+ /// let relatives = Position::new(0, 0).relatives_expand_by_checked(&[Direction::North, Direction::East], 2, (10, 10)).collect::<Vec<_>>();
589589+ /// let expected = vec![
590590+ /// ((Direction::East, 1), Position::new(1, 0)),
591591+ /// ((Direction::East, 2), Position::new(2, 0)),
592592+ /// ];
593593+ ///
594594+ /// assert_eq!(relatives, expected);
595595+ /// ```
596596+ ///
597597+ pub fn relatives_expand_by_checked<'a, T: Movement>(
598598+ self,
599599+ kernels: &'a [T],
600600+ times: usize,
601601+ bounds: PositiveType,
602602+ ) -> impl Iterator<Item = ((T, usize), Self)> + 'a {
603603+ kernels.into_iter().flat_map(move |k| {
604604+ (1..=times)
605605+ .filter_map(move |t| self.move_times_checked(*k, t, bounds).map(|p| ((*k, t), p)))
606606+ })
607607+ }
608608+609609+ /// Get all positions adjacent to this position
610610+ ///
611611+ /// # Examples
612612+ ///
613613+ /// ```
614614+ /// use utils::prelude::*;
615615+ ///
616616+ /// let adjacents = Position::new(0, 0).adjacents().collect::<Vec<_>>();
617617+ /// let expected = vec![
618618+ /// (Position::new(0, -1), Direction::North),
619619+ /// (Position::new(0, 1), Direction::South),
620620+ /// (Position::new(1, 0), Direction::East),
621621+ /// (Position::new(-1, 0), Direction::West),
622622+ /// ];
623623+ ///
624624+ /// assert_eq!(adjacents, expected);
625625+ /// ```
626626+ ///
627627+ pub fn adjacents(self) -> impl Iterator<Item = (Self, Direction)> {
628628+ self.relatives(&CARDINALS)
629629+ }
630630+631631+ /// Get all positions adjacent to this position
632632+ ///
633633+ /// # Examples
634634+ ///
635635+ /// ```
636636+ /// use utils::prelude::*;
637637+ ///
638638+ /// let adjacents = Position::new(0, 0).adjacents_checked((2, 2)).collect::<Vec<_>>();
639639+ /// let expected = vec![
640640+ /// (Position::new(0, 1), Direction::South),
641641+ /// (Position::new(1, 0), Direction::East),
642642+ /// ];
643643+ ///
644644+ /// assert_eq!(adjacents, expected);
645645+ /// ```
646646+ ///
647647+ pub fn adjacents_checked(
648648+ self,
649649+ bounds: PositiveType,
650650+ ) -> impl Iterator<Item = (Self, Direction)> {
651651+ self.relatives_checked(&CARDINALS, bounds)
652652+ }
653653+}
654654+655655+impl Add for Position {
656656+ type Output = Self;
657657+658658+ fn add(self, other: Self) -> Self {
659659+ Self::add(&self, &other)
660660+ }
661661+}
662662+663663+impl Add<&Position> for Position {
664664+ type Output = Self;
665665+666666+ fn add(self, other: &Self) -> Self {
667667+ Self::add(&self, other)
668668+ }
669669+}
670670+671671+impl Sub for Position {
672672+ type Output = Self;
673673+674674+ fn sub(self, other: Self) -> Self {
675675+ Self::sub(&self, &other)
676676+ }
677677+}
678678+679679+impl Sub<&Position> for Position {
680680+ type Output = Self;
681681+682682+ fn sub(self, other: &Self) -> Self {
683683+ Self::sub(&self, other)
684684+ }
685685+}
686686+687687+impl Mul for Position {
688688+ type Output = Self;
689689+690690+ fn mul(self, other: Self) -> Self {
691691+ Self::multiply(&self, &other)
692692+ }
693693+}
694694+695695+impl Mul<&Position> for Position {
696696+ type Output = Self;
697697+698698+ fn mul(self, other: &Self) -> Self {
699699+ Self::multiply(&self, other)
700700+ }
701701+}
702702+703703+impl Mul<CompType> for Position {
704704+ type Output = Self;
705705+706706+ fn mul(self, other: CompType) -> Self {
707707+ Self::multiply_comp(&self, other)
708708+ }
709709+}
710710+711711+impl Mul<usize> for Position {
712712+ type Output = Self;
713713+714714+ fn mul(self, other: usize) -> Self {
715715+ Self::multiply_comp(&self, other as isize)
716716+ }
717717+}
718718+719719+impl Neg for Position {
720720+ type Output = Self;
721721+722722+ fn neg(self) -> Self {
723723+ self.multiply_comp(-1)
724724+ }
725725+}
726726+727727+impl Display for Position {
728728+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
729729+ write!(f, "({},{})", self.x, self.y)
730730+ }
731731+}
732732+733733+impl FromStr for Position {
734734+ type Err = String;
735735+736736+ fn from_str(s: &str) -> Result<Self, Self::Err> {
737737+ let mut split = s.split(',');
738738+ let x = split.next().ok_or("No x")?.parse().expect("No x");
739739+ let y = split.next().ok_or("No y")?.parse().expect("No y");
740740+ Ok(Self { x, y })
741741+ }
742742+}
743743+744744+impl From<(CompType, CompType)> for Position {
745745+ fn from((x, y): (CompType, CompType)) -> Self {
746746+ Self { x, y }
747747+ }
748748+}
749749+750750+impl Into<(CompType, CompType)> for Position {
751751+ fn into(self) -> (CompType, CompType) {
752752+ (self.x, self.y)
753753+ }
754754+}
755755+756756+impl From<(usize, usize)> for Position {
757757+ fn from((x, y): (usize, usize)) -> Self {
758758+ Self {
759759+ x: x as isize,
760760+ y: y as isize,
761761+ }
762762+ }
763763+}
764764+765765+impl Into<(usize, usize)> for Position {
766766+ fn into(self) -> (usize, usize) {
767767+ (self.x as usize, self.y as usize)
768768+ }
769769+}
770770+771771+impl From<Direction> for Position {
772772+ fn from(dir: Direction) -> Self {
773773+ dir.get_kernel()
774774+ }
775775+}