chickenwire/coordinate/axial.rs
1//! Axial Coordinates
2
3use std::ops::{Add, Div, Mul, Sub};
4
5use super::*;
6
7//////////////////////////////////////////////////////////////////////////////
8// Primary Structure
9//////////////////////////////////////////////////////////////////////////////
10
11/// Axial coordinates use the same system as cube coordinates, but only store
12/// two of the coordinate values. This is possible since, for cube coordinate
13/// (x, y, z), the third value can always be calculated when the other two are
14/// known due to the constraint x + y + z == 0.
15#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
16pub struct Axial {
17 pub q: i32,
18 pub r: i32,
19}
20
21//////////////////////////////////////////////////////////////////////////////
22// Traits: Arithmetic
23//////////////////////////////////////////////////////////////////////////////
24
25/// Adds two `Axial` coordinates in the same manner as vectors.
26///
27/// # Examples
28///
29/// ```
30/// use chickenwire::coordinate::axial::Axial;
31///
32/// let coord_1 = Axial::from_coords(1, -3);
33/// let coord_2 = Axial::from_coords(-5, 12);
34///
35/// assert_eq!(coord_1 + coord_2, Axial::from_coords(-4, 9));
36/// assert_eq!(coord_2 + coord_1, Axial::from_coords(-4, 9));
37/// ```
38impl Add for Axial {
39 type Output = Self;
40
41 fn add(self, other: Self) -> Self {
42 Self {
43 q: self.q + other.q,
44 r: self.r + other.r,
45 }
46 }
47}
48
49/// Subtracts two `Axial` coordinates in the same manner as vectors.
50///
51/// # Examples
52///
53/// ```
54/// use chickenwire::coordinate::axial::Axial;
55///
56/// let coord_1 = Axial::from_coords(1, -3);
57/// let coord_2 = Axial::from_coords(5, -12);
58///
59/// assert_eq!(coord_1 - coord_2, Axial::from_coords(-4, 9));
60/// assert_eq!(coord_2 - coord_1, Axial::from_coords(4, -9));
61/// ```
62impl Sub for Axial {
63 type Output = Self;
64
65 fn sub(self, other: Self) -> Self {
66 Self {
67 q: self.q - other.q,
68 r: self.r - other.r,
69 }
70 }
71}
72
73/// Multiplies an `Axial` coordinate by an `i32` scalar, like a vector.
74///
75/// # Examples
76///
77/// ```
78/// use chickenwire::coordinate::axial::Axial;
79///
80/// let coord = Axial::from_coords(1, -3);
81///
82/// assert_eq!(-1 * coord, Axial::from_coords(-1, 3));
83/// assert_eq!(0 * coord, Axial::ORIGIN);
84/// assert_eq!(coord * 2, Axial::from_coords(2, -6));
85/// ```
86impl Mul<i32> for Axial {
87 type Output = Self;
88
89 fn mul(self, n: i32) -> Self {
90 Self {
91 q: self.q * n,
92 r: self.r * n,
93 }
94 }
95}
96
97impl Mul<Axial> for i32 {
98 type Output = Axial;
99
100 fn mul(self, coord: Axial) -> Axial {
101 coord * self
102 }
103}
104
105/// Divides an `Axial` coordinate by an `i32` scalar, like a vector. Values
106/// are truncated (i.e. rounded toward zero).
107///
108/// # Panics
109///
110/// Panics when trying to divide by zero.
111///
112/// # Examples
113///
114/// ```
115/// use chickenwire::coordinate::axial::Axial;
116///
117/// let coord = Axial::from_coords(12, -36);
118///
119/// assert_eq!(coord / -1, Axial::from_coords(-12, 36));
120/// assert_eq!(coord / 2, Axial::from_coords(6, -18));
121/// assert_eq!(coord / 3, Axial::from_coords(4, -12));
122/// ```
123impl Div<i32> for Axial {
124 type Output = Self;
125
126 fn div(self, n: i32) -> Self {
127 Self {
128 q: self.q / n,
129 r: self.r / n,
130 }
131 }
132}
133
134//////////////////////////////////////////////////////////////////////////////
135// Traits: From & Into
136//////////////////////////////////////////////////////////////////////////////
137
138/// Creates an `Axial` from an `(i32, i32)`.
139///
140/// # Examples
141///
142/// ```
143/// use chickenwire::coordinate::axial::Axial;
144///
145/// assert_eq!(
146/// Axial::from((1, 2)),
147/// Axial { q: 1, r: 2 }
148/// );
149/// ```
150impl From<(i32, i32)> for Axial {
151 fn from((q, r): (i32, i32)) -> Self {
152 Self {
153 q: q,
154 r: r,
155 }
156 }
157}
158
159/// Creates an `Axial` from a `Cube`.
160///
161/// # Examples
162///
163/// ```
164/// use chickenwire::coordinate::axial::Axial;
165/// use chickenwire::coordinate::cube::Cube;
166///
167/// let cube = Cube::force_from_coords(1, 2, -3);
168///
169/// assert_eq!(
170/// Axial::from(cube),
171/// Axial { q: 1, r: -3 }
172/// );
173/// assert_eq!(
174/// Axial::from(Cube::ORIGIN),
175/// Axial::ORIGIN
176/// );
177/// ```
178impl From<Cube> for Axial {
179 fn from(coord: Cube) -> Self {
180 let (x, _, z) = coord.to_tuple();
181
182 Self { q: x, r: z }
183 }
184}
185
186/// Creates an `Axial` from a `MultiCoord`.
187///
188/// Conversion from both axial and cube `MultiCoord`s is supported.
189///
190/// # Panics
191///
192/// Panics when parsing a double or offset `MultiCoord`.
193impl From<MultiCoord> for Axial {
194 fn from(coord: MultiCoord) -> Self {
195 match coord.sys {
196 CoordSys::Axial => Axial { q: coord.a, r: coord.b },
197 CoordSys::Cube => Axial { q: coord.a, r: coord.c.unwrap() },
198 _ => panic!("{:?} is not an Axial or Cube coordinate", coord),
199 }
200 }
201}
202
203//////////////////////////////////////////////////////////////////////////////
204// Methods
205//////////////////////////////////////////////////////////////////////////////
206
207impl Axial {
208 //////////////////////////////////
209 // Constants
210 //////////////////////////////////
211
212 /// `Axial` coordinate origin of (0, 0).
213 pub const ORIGIN: Axial = Axial { q: 0, r: 0 };
214
215 //////////////////////////////////
216 // Initialization
217 //////////////////////////////////
218
219 /// For two unsigned 32-bit integers x and y, the corresponding axial
220 /// coordinate is (x, y).
221 ///
222 /// # Examples
223 ///
224 /// ```
225 /// use chickenwire::coordinate::axial::Axial;
226 ///
227 /// assert_eq!(Axial::from((1, 2)), Axial::from_coords(1, 2));
228 /// ```
229 pub fn from_coords(q: i32, r: i32) -> Self {
230 Self::from((q, r))
231 }
232
233 //////////////////////////////////
234 // Neighbors
235 //////////////////////////////////
236
237 /// [ docs missing ]
238 pub fn neighbors(self) -> Vec<Self> {
239 let cube_neighbors = Cube::from(self).neighbors();
240
241 cube_neighbors.into_iter().map(|coord| Self::from(coord)).collect()
242 }
243
244 /// [ docs missing ]
245 pub fn diagonals(self) -> Vec<Self> {
246 let cube_diagonals = Cube::from(self).diagonals();
247
248 cube_diagonals.into_iter().map(|coord| Self::from(coord)).collect()
249 }
250
251 //////////////////////////////////
252 // Distances
253 //////////////////////////////////
254
255 /// Determines the distance between two axial coordinates.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use chickenwire::coordinate::axial::Axial;
261 ///
262 /// let origin = Axial::ORIGIN;
263 /// let coord_1 = Axial { q: 1, r: -3 };
264 /// let coord_2 = Axial { q: -8, r: 2 };
265 ///
266 /// assert_eq!(origin.dist(coord_1), 3);
267 /// assert_eq!(coord_1.dist(origin), 3);
268 /// assert_eq!(coord_1.dist(coord_1), 0);
269 /// assert_eq!(coord_2.dist(coord_1), 9);
270 /// ```
271 pub fn dist(self, other: Self) -> i32 {
272 Cube::from(self).dist(Cube::from(other))
273 }
274}