1use crate::continent::ContinentSize;
5use crate::error::Result;
6use derive_more::{From, Into};
7use glam::u8::U8Vec2;
8use itertools::Itertools;
9use serde::de::{self, Error as _, MapAccess, SeqAccess, Visitor};
10use serde::ser::SerializeStruct;
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use std::borrow::Cow;
13use std::fmt;
14use std::ops::{Add, AddAssign, Sub, SubAssign};
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
17pub struct Coord(U8Vec2);
18
19impl Coord {
20 #[inline]
21 #[must_use]
22 pub const fn new(x: u8, y: u8) -> Self {
23 Self(U8Vec2::new(x, y))
24 }
25
26 #[inline]
27 #[must_use]
28 pub const fn splat(value: u8) -> Self {
29 Self(U8Vec2::splat(value))
30 }
31
32 #[inline]
33 pub const fn x(&self) -> u8 {
34 self.0.x
35 }
36
37 #[inline]
38 pub const fn y(&self) -> u8 {
39 self.0.y
40 }
41
42 #[inline]
43 pub fn distance(&self, rhs: Coord) -> Distance {
44 Distance::new(self.0.chebyshev_distance(rhs.0))
45 }
46
47 #[inline]
48 pub fn is_within_continent(&self, size: ContinentSize) -> bool {
49 size > self.x() && size > self.y()
50 }
51
52 pub fn is_within_distance(&self, other: Coord, distance: Distance) -> bool {
53 let x0 = i16::from(self.x());
54 let y0 = i16::from(self.y());
55 let distance = i16::from(distance);
56
57 let absx = (i16::from(other.x()) - x0).abs();
58 let absy = (i16::from(other.y()) - y0).abs();
59 absx.max(absy) <= distance
60 }
61
62 #[inline]
63 #[must_use]
64 pub fn within_distance(self, distance: Distance) -> Vec<Self> {
65 within_distance(self, distance, false)
66 }
67
68 #[inline]
69 #[must_use]
70 pub fn within_distance_inclusive(self, distance: Distance) -> Vec<Self> {
71 within_distance(self, distance, true)
72 }
73}
74
75fn within_distance(origin: Coord, distance: Distance, inclusive: bool) -> Vec<Coord> {
76 let mut coords = Vec::new();
77 let x0 = i16::from(origin.x());
78 let y0 = i16::from(origin.y());
79 let distance = i16::from(distance);
80
81 for x in (x0 - distance)..=(x0 + distance) {
82 for y in (y0 - distance)..=(y0 + distance) {
83 let absx = (x - x0).abs();
84 let absy = (y - y0).abs();
85 if absx.max(absy) <= distance
86 && (inclusive || x != x0 || y != y0)
87 && let Ok(x) = u8::try_from(x)
88 && let Ok(y) = u8::try_from(y)
89 {
90 coords.push(Coord::new(x, y));
91 }
92 }
93 }
94
95 coords.into_iter().unique().collect()
96}
97
98impl Add for Coord {
99 type Output = Coord;
100
101 fn add(self, rhs: Self) -> Self::Output {
102 Self(self.0.saturating_add(rhs.0))
103 }
104}
105
106impl Sub for Coord {
107 type Output = Coord;
108
109 fn sub(self, rhs: Self) -> Self::Output {
110 Self(self.0.saturating_sub(rhs.0))
111 }
112}
113
114impl From<(u8, u8)> for Coord {
115 fn from((x, y): (u8, u8)) -> Self {
116 Self::new(x, y)
117 }
118}
119
120impl fmt::Display for Coord {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 write!(f, "{:03}|{:03}", self.0.x, self.0.y)
123 }
124}
125
126impl Serialize for Coord {
127 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
128 where
129 S: Serializer,
130 {
131 let mut coord = serializer.serialize_struct("Coord", 2)?;
132 coord.serialize_field("x", &self.0.x)?;
133 coord.serialize_field("y", &self.0.y)?;
134 coord.end()
135 }
136}
137
138impl<'de> Deserialize<'de> for Coord {
139 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
140 where
141 D: Deserializer<'de>,
142 {
143 deserializer.deserialize_struct("Coord", &CoordVisitor::FIELD, CoordVisitor)
144 }
145}
146
147struct CoordVisitor;
148
149impl CoordVisitor {
150 const FIELD: [&str; 2] = ["x", "y"];
151}
152
153impl<'de> Visitor<'de> for CoordVisitor {
154 type Value = Coord;
155
156 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
157 formatter.write_str("struct Coord")
158 }
159
160 fn visit_seq<V>(self, mut seq: V) -> Result<Coord, V::Error>
161 where
162 V: SeqAccess<'de>,
163 {
164 let x = seq
165 .next_element()?
166 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
167
168 let y = seq
169 .next_element()?
170 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
171
172 Ok(Coord::new(x, y))
173 }
174
175 fn visit_map<V>(self, mut map: V) -> Result<Coord, V::Error>
176 where
177 V: MapAccess<'de>,
178 {
179 let mut x = None;
180 let mut y = None;
181
182 while let Some(key) = map.next_key::<Cow<'static, str>>()? {
183 match key.as_ref() {
184 "x" => x = Some(map.next_value()?),
185 "y" => y = Some(map.next_value()?),
186 _ => {}
187 }
188 }
189
190 Ok(Coord::new(
191 x.ok_or_else(|| V::Error::missing_field("x"))?,
192 y.ok_or_else(|| V::Error::missing_field("y"))?,
193 ))
194 }
195}
196
197#[derive(
198 Clone, Copy, Debug, Default, From, Into, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize,
199)]
200#[into(i16, u8, f64)]
201pub struct Distance(u8);
202
203impl Distance {
204 #[inline]
205 pub const fn new(distance: u8) -> Self {
206 Self(distance)
207 }
208}
209
210impl PartialEq<u8> for Distance {
211 fn eq(&self, other: &u8) -> bool {
212 self.0.eq(other)
213 }
214}
215
216impl Add for Distance {
217 type Output = Distance;
218
219 fn add(self, rhs: Self) -> Self::Output {
220 Self(self.0.saturating_add(rhs.0))
221 }
222}
223
224impl AddAssign for Distance {
225 fn add_assign(&mut self, rhs: Self) {
226 *self = *self + rhs;
227 }
228}
229
230impl Sub for Distance {
231 type Output = Distance;
232
233 fn sub(self, rhs: Self) -> Self::Output {
234 Self(self.0.saturating_sub(rhs.0))
235 }
236}
237
238impl SubAssign for Distance {
239 fn sub_assign(&mut self, rhs: Self) {
240 *self = *self - rhs;
241 }
242}
243
244impl Add<u8> for Distance {
245 type Output = Distance;
246
247 fn add(self, rhs: u8) -> Self::Output {
248 Self(self.0.saturating_add(rhs))
249 }
250}
251
252impl AddAssign<u8> for Distance {
253 fn add_assign(&mut self, rhs: u8) {
254 *self = *self + rhs;
255 }
256}
257
258impl Sub<u8> for Distance {
259 type Output = Distance;
260
261 fn sub(self, rhs: u8) -> Self::Output {
262 Self(self.0.saturating_sub(rhs))
263 }
264}
265
266impl SubAssign<u8> for Distance {
267 fn sub_assign(&mut self, rhs: u8) {
268 *self = *self - rhs;
269 }
270}