1use std::cmp::{max, min};
2
3#[derive(Debug, Clone, Copy, Eq, PartialEq)]
5pub struct Pos {
6 pub x: u16,
7 pub y: u16,
8}
9
10impl Pos {
11 pub(crate) fn constrain<I: Into<Self> + Copy>(self, other: I) -> Self {
12 Self {
13 x: max(min(self.x, other.into().x - 1), 0),
14 y: max(min(self.y, other.into().y - 1), 0),
15 }
16 }
17
18 pub(crate) fn within(self, other: Self, length: u16) -> Option<usize> {
19 if self.x >= other.x && self.x <= other.x + length && self.y == other.y {
20 Some((self.x - other.x) as usize)
21 } else {
22 None
23 }
24 }
25
26 pub(crate) fn move_x(self, by: i16, max: u16) -> Self {
27 Pos {
28 x: (self.x as i16 + by) as u16,
29 y: self.y,
30 }
31 .constrain((max, u16::MAX))
32 }
33}
34
35impl From<(u16, u16)> for Pos {
36 fn from((x, y): (u16, u16)) -> Self {
37 Self { x, y }
38 }
39}
40
41impl Ord for Pos {
42 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
43 match self.y.cmp(&other.y) {
44 core::cmp::Ordering::Equal => self.x.cmp(&other.x),
45 ord => ord,
46 }
47 }
48}
49
50impl PartialOrd for Pos {
51 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
52 Some(self.cmp(other))
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use std::cmp::Ordering;
59
60 use super::*;
61
62 #[test]
63 fn within_1() {
64 let pos: Pos = (2, 2).into();
65 let field: Pos = (0, 2).into();
66
67 let res = pos.within(field, 4);
68
69 assert_eq!(res, Some(2));
70 }
71
72 #[test]
73 fn within_2() {
74 let pos: Pos = (6, 2).into();
75 let field: Pos = (2, 2).into();
76
77 let res = pos.within(field, 4);
78
79 assert_eq!(res, Some(4));
80 }
81
82 #[test]
83 fn outside_x() {
84 let pos: Pos = (2, 2).into();
85 let field: Pos = (7, 2).into();
86
87 let res = pos.within(field, 4);
88
89 assert_eq!(res, None);
90 }
91
92 #[test]
93 fn outside_y() {
94 let pos: Pos = (2, 2).into();
95 let field: Pos = (2, 0).into();
96
97 let res = pos.within(field, 4);
98
99 assert_eq!(res, None);
100 }
101
102 #[test]
103 fn ordering() {
104 let test_pos: Pos = (2, 2).into();
105
106 assert_eq!(test_pos.cmp(&(0, 0).into()), Ordering::Greater);
107 assert_eq!(test_pos.cmp(&(2, 0).into()), Ordering::Greater);
108 assert_eq!(test_pos.cmp(&(0, 2).into()), Ordering::Greater);
109 assert_eq!(test_pos.cmp(&(2, 2).into()), Ordering::Equal);
110 assert_eq!(test_pos.cmp(&(2, 4).into()), Ordering::Less);
111 assert_eq!(test_pos.cmp(&(0, 4).into()), Ordering::Less);
112 assert_eq!(test_pos.cmp(&(4, 4).into()), Ordering::Less);
113 }
114}