1use crate::{Dim, Dir, Loc, Scale};
2
3impl Loc {
4 #[inline]
8 pub fn neighbor(self, dir: Dir, dims: Dim) -> Option<Loc> {
9 match dir {
10 Dir::North => {
11 if self.y > 0 {
12 Some(Loc::new(self.x, self.y - 1))
13 } else {
14 None
15 }
16 }
17 Dir::East => {
18 let x: Scale = self.x + 1;
19 if x < dims.w {
20 Some(Loc::new(x, self.y))
21 } else {
22 None
23 }
24 }
25 Dir::South => {
26 let y: Scale = self.y + 1;
27 if y < dims.h {
28 Some(Loc::new(self.x, y))
29 } else {
30 None
31 }
32 }
33 Dir::West => {
34 if self.x > 0 {
35 Some(Loc::new(self.x - 1, self.y))
36 } else {
37 None
38 }
39 }
40 }
41 }
42
43 #[inline]
45 pub fn neighbor_unchecked(self, dir: Dir) -> Loc {
46 match dir {
47 Dir::North => Loc::new(self.x, self.y - 1),
48 Dir::East => Loc::new(self.x + 1, self.y),
49 Dir::South => Loc::new(self.x, self.y + 1),
50 Dir::West => Loc::new(self.x - 1, self.y),
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use crate::{Dim, Dir, Loc};
58
59 #[test]
60 fn neighbor() {
61 let dims: Dim = Dim::new(3, 3);
62 let test_cases: &[(Loc, Dir, Option<Loc>)] = &[
63 (Loc::new(1, 1), Dir::North, Some(Loc::new(1, 0))),
65 (Loc::new(1, 1), Dir::East, Some(Loc::new(2, 1))),
66 (Loc::new(1, 1), Dir::South, Some(Loc::new(1, 2))),
67 (Loc::new(1, 1), Dir::West, Some(Loc::new(0, 1))),
68 (Loc::new(0, 0), Dir::North, None),
70 (Loc::new(0, 0), Dir::West, None),
71 (Loc::new(0, 0), Dir::East, Some(Loc::new(1, 0))),
72 (Loc::new(0, 0), Dir::South, Some(Loc::new(0, 1))),
73 (Loc::new(2, 2), Dir::East, None),
75 (Loc::new(2, 2), Dir::South, None),
76 (Loc::new(2, 2), Dir::North, Some(Loc::new(2, 1))),
77 (Loc::new(2, 2), Dir::West, Some(Loc::new(1, 2))),
78 ];
79 for &(loc, dir, expected) in test_cases {
80 assert_eq!(loc.neighbor(dir, dims), expected, "loc={loc} dir={dir}");
81 }
82
83 let loc: Loc = Loc::new(1, 1);
85 for dir in Dir::ALL {
86 assert_eq!(
87 loc.neighbor(dir, dims).unwrap(),
88 loc.neighbor_unchecked(dir)
89 );
90 }
91 }
92
93 #[test]
94 fn neighbor_unchecked() {
95 let loc: Loc = Loc::new(2, 2);
96 for dir in Dir::ALL {
97 let n: Loc = loc.neighbor_unchecked(dir);
98 assert_eq!(n.neighbor_unchecked(dir.opposite()), loc);
99 }
100 }
101}