1use crate::types::Coord;
2
3pub fn hex_offsets(radius: i32) -> Vec<Coord> {
6 let mut offsets = Vec::new();
7 for dq in -radius..=radius {
8 for dr in -radius..=radius {
9 if dq.abs().max(dr.abs()).max((dq + dr).abs()) <= radius {
10 offsets.push((dq, dr));
11 }
12 }
13 }
14 offsets
15}
16
17pub fn hex_distance(a: Coord, b: Coord) -> i32 {
20 let dq = (b.0 - a.0).abs();
21 let dr = (b.1 - a.1).abs();
22 let ds = (b.0 - a.0 + b.1 - a.1).abs();
23 dq.max(dr).max(ds)
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29
30 #[test]
31 fn same_point_is_zero() {
32 assert_eq!(hex_distance((0, 0), (0, 0)), 0);
33 assert_eq!(hex_distance((3, -2), (3, -2)), 0);
34 }
35
36 #[test]
37 fn all_six_adjacents_are_distance_one() {
38 let origin = (0, 0);
39 let neighbors = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, -1), (-1, 1)];
40 for n in neighbors {
41 assert_eq!(hex_distance(origin, n), 1, "neighbor {n:?} should be distance 1");
42 }
43 }
44
45 #[test]
46 fn along_axis_distance() {
47 assert_eq!(hex_distance((0, 0), (5, 0)), 5);
49 assert_eq!(hex_distance((0, 0), (0, 4)), 4);
51 assert_eq!(hex_distance((0, 0), (3, -3)), 3);
53 }
54
55 #[test]
56 fn diagonal_distance() {
57 assert_eq!(hex_distance((0, 0), (2, 1)), 3);
59 assert_eq!(hex_distance((0, 0), (1, 2)), 3);
61 }
62
63 #[test]
64 fn distance_is_symmetric() {
65 assert_eq!(hex_distance((1, 2), (4, -1)), hex_distance((4, -1), (1, 2)));
66 assert_eq!(hex_distance((-3, 5), (2, -2)), hex_distance((2, -2), (-3, 5)));
67 }
68
69 #[test]
70 fn negative_coords() {
71 assert_eq!(hex_distance((-2, -3), (1, 1)), 7);
73 }
74
75 #[test]
76 fn boundary_distance_eight() {
77 assert_eq!(hex_distance((0, 0), (8, 0)), 8);
79 }
80
81 #[test]
82 fn boundary_distance_nine() {
83 assert_eq!(hex_distance((0, 0), (9, 0)), 9);
85 }
86}