lattice_graph/hex/
hex2d.rs

1/*!
2Module to use [`hex2d`] as Coordinate of Hex Graph.
3
4This Module is to use [`hex2d`] as Coordinate of Hex Graph.
5The behavior is almost same as [`axial_based`](`super::axial_based`).
6
7Currently this [`HexShape`](`HexShape`) doesn't use [`hex2d::Direction`]
8as [`Axis`] or [`AxisDirection`](`crate::lattice_abstract::shapes::AxisDirection`)
9to reuse the implemention with [`axial_based`](`super::axial_based`).
10So it isn't perfectly integrate with it, so I might make another
11`Shape` and `Graph` if I have time.
12*/
13
14use super::{
15    axial_based::{shapes::AxialCoord, HexAxialShape},
16    shapes::{AxisDQ, AxisDR, OddR},
17};
18use crate::{
19    lattice_abstract::{shapes::Axis, LatticeGraph},
20    unreachable_debug_checked,
21};
22#[cfg(feature = "const-generic-wrap")]
23use const_generic_wrap::WrapUSIZE;
24use hex2d::Integer;
25
26impl<I: Integer> crate::lattice_abstract::shapes::Coordinate for hex2d::Coordinate<I> {}
27impl<I: Integer> AxialCoord for hex2d::Coordinate<I> {
28    fn new(r: isize, q: isize) -> Self {
29        Self::new(
30            I::from_isize(r).unwrap_or_else(|| unsafe { unreachable_debug_checked() }),
31            I::from_isize(q).unwrap_or_else(|| unsafe { unreachable_debug_checked() }),
32        )
33    }
34
35    fn r(&self) -> isize {
36        self.x
37            .to_isize()
38            .unwrap_or_else(|| unsafe { unreachable_debug_checked() })
39    }
40
41    fn q(&self) -> isize {
42        self.y
43            .to_isize()
44            .unwrap_or_else(|| unsafe { unreachable_debug_checked() })
45    }
46}
47
48/// Shape for [`Coordinate`](`hex2d::Coordinate`)
49pub type HexShape<B, L, I = i32, H = usize, V = usize> =
50    HexAxialShape<B, L, H, V, hex2d::Coordinate<I>>;
51/// Hex Graph with [`Coordinate`](`hex2d::Coordinate`).
52pub type HexGraph<N, E, B = OddR, L = (), I = i32, H = usize, V = usize> =
53    LatticeGraph<N, E, HexShape<B, L, I, H, V>>;
54
55#[cfg(feature = "const-generic-wrap")]
56/// Shape for [`Coordinate`](`hex2d::Coordinate`) as ZST.
57pub type HexShapeConst<B, L, I, const H: usize, const V: usize> =
58    HexShape<B, L, I, WrapUSIZE<H>, WrapUSIZE<V>>;
59impl<B, L, I: hex2d::Integer, const H: usize, const V: usize> Default
60    for HexShapeConst<B, L, I, H, V>
61{
62    fn default() -> Self {
63        Self::new(WrapUSIZE::<H>, WrapUSIZE::<V>)
64    }
65}
66
67#[cfg(feature = "const-generic-wrap")]
68/// Hex Graph with [`Coordinate`](`hex2d::Coordinate`) as ZST.
69pub type HexGraphConst<N, E, B, L, I, const H: usize, const V: usize> =
70    LatticeGraph<N, E, HexShapeConst<B, L, I, H, V>>;
71
72impl From<hex2d::Direction> for AxisDR {
73    fn from(d: hex2d::Direction) -> Self {
74        let i = d.to_int::<isize>() as usize;
75        let i = if i == 5 { 0 } else { i + 1 };
76        debug_assert!(i <= 5);
77        unsafe { Self::from_index_unchecked(i) }
78        // match d {
79        //     hex2d::Direction::YZ => AxisDR::NW,
80        //     hex2d::Direction::XZ => AxisDR::NE,
81        //     hex2d::Direction::XY => AxisDR::E,
82        //     hex2d::Direction::ZY => AxisDR::SE,
83        //     hex2d::Direction::ZX => AxisDR::SW,
84        //     hex2d::Direction::YX => AxisDR::W,
85        // }
86    }
87}
88
89impl From<hex2d::Direction> for AxisDQ {
90    fn from(d: hex2d::Direction) -> Self {
91        let i = d.to_int::<isize>() as usize;
92        debug_assert!(i <= 5);
93        unsafe { Self::from_index_unchecked(i) }
94    }
95}
96
97impl From<AxisDR> for hex2d::Direction {
98    fn from(d: AxisDR) -> Self {
99        let i = d.to_index();
100        let i = if i == 0 { 5 } else { i - 1 } as isize;
101        debug_assert!(i <= 5);
102        Self::from_int(i)
103    }
104}
105
106impl From<AxisDQ> for hex2d::Direction {
107    fn from(d: AxisDQ) -> Self {
108        let i = d.to_index() as isize;
109        Self::from_int(i)
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    type C = hex2d::Coordinate;
116    use super::*;
117    use crate::hex::shapes::{AxisR, OddR};
118    use petgraph::{data::DataMap, visit::*};
119    use rstest::*;
120    type Hex5x5 = HexGraphConst<C, (C, AxisR), OddR, (), i32, 5, 5>;
121
122    #[fixture]
123    fn hexgraph_oddr55() -> Hex5x5 {
124        Hex5x5::new_with_s(|x| (x), |n, d| (n, d))
125    }
126    #[rstest]
127    fn gen_oddr(hexgraph_oddr55: Hex5x5) {
128        let graph = hexgraph_oddr55;
129        for i in 0..graph.node_count() {
130            let x = graph.from_index(i);
131            assert_eq!(Some(&x), graph.node_weight(x));
132        }
133        assert_eq!(0, std::mem::size_of_val(graph.shape()))
134    }
135
136    #[rstest]
137    #[case(C::new(0, 0),[C::new(0, 1), C::new(1, 0)] )]
138    #[case(C::new(4, 0),[C::new(4, 1), C::new(3, 0), C::new(3, 1)] )]
139    #[case(C::new(1, 1),[
140        C::new(1, 2),
141        C::new(2, 1),
142        C::new(2, 0),
143        C::new(1, 0),
144        C::new(0, 1),
145        C::new(0, 2),
146    ]) ]
147    #[case(C::new(1, 2),[
148        C::new(1, 3),
149        C::new(2, 2),
150        C::new(2, 1),
151        C::new(1, 1),
152        C::new(0, 2),
153        C::new(0, 3),
154    ]) ]
155    fn neighbors_oddr(
156        hexgraph_oddr55: Hex5x5,
157        #[case] target: C,
158        #[case] neighbors: impl IntoIterator<Item = C>,
159    ) {
160        let graph = hexgraph_oddr55;
161        let e = graph.neighbors(target);
162        debug_assert!(e.eq(neighbors));
163        let e = graph.neighbors(target);
164        for neighbor in e {
165            assert_eq!(neighbor.distance(target), 1);
166        }
167    }
168}