lattice_graph/hex/double_coord/
shapes.rs1use crate::hex::shapes::*;
2use crate::lattice_abstract::shapes::*;
3#[cfg(feature = "const-generic-wrap")]
4use const_generic_wrap::WrapUSIZE;
5use std::marker::PhantomData;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct DoubleCoord {
10 pub(crate) h: usize,
11 pub(crate) v: usize,
12}
13
14impl DoubleCoord {
15 pub fn new(h: usize, v: usize) -> Self {
17 Self { h, v }
18 }
19
20 pub fn h(&self) -> usize {
22 self.h
23 }
24
25 pub fn v(&self) -> usize {
27 self.v
28 }
29}
30
31impl Coordinate for DoubleCoord {}
32
33pub trait DoubleCoordShapeBase: OE + RQ + Clone {
35 type Axis: Axis;
36 fn move_coord(
37 coord: DoubleCoord,
38 dir: <Self::Axis as Axis>::Direction,
39 h_max: usize,
40 v_max: usize,
41 ) -> Option<DoubleCoord>;
42}
43
44impl DoubleCoordShapeBase for OddR {
45 type Axis = AxisR;
46
47 fn move_coord(
48 coord: DoubleCoord,
49 dir: AxisDR,
50 h_max: usize,
51 v_max: usize,
52 ) -> Option<DoubleCoord> {
53 move_coord_r(coord, dir, h_max, v_max)
54 }
55}
56
57impl DoubleCoordShapeBase for OddQ {
58 type Axis = AxisQ;
59
60 fn move_coord(
61 coord: DoubleCoord,
62 dir: AxisDQ,
63 h_max: usize,
64 v_max: usize,
65 ) -> Option<DoubleCoord> {
66 move_coord_q(coord, dir, h_max, v_max)
67 }
68}
69
70fn move_coord_r(
71 coord: DoubleCoord,
72 dir: AxisDR,
73 h_max: usize,
74 v_max: usize,
75) -> Option<DoubleCoord> {
76 'outer: {
77 let mut coord = coord;
78 match dir {
79 AxisDR::NE => {
80 coord.h += 1;
81 if coord.h >= h_max {
82 break 'outer;
83 }
84 coord.v += 1;
85 if coord.v >= v_max {
86 break 'outer;
87 }
88 }
89 AxisDR::E => {
90 coord.h += 2;
91 if coord.h >= h_max {
92 break 'outer;
93 }
94 }
95 AxisDR::SE => {
96 coord.h += 1;
97 if coord.h >= h_max {
98 break 'outer;
99 }
100 if let Some(x) = coord.v.checked_sub(1) {
101 coord.v = x;
102 } else {
103 break 'outer;
104 }
105 }
106 AxisDR::SW => {
107 if let Some(x) = coord.h.checked_sub(1) {
108 coord.h = x;
109 } else {
110 break 'outer;
111 }
112 if let Some(x) = coord.v.checked_sub(1) {
113 coord.v = x;
114 } else {
115 break 'outer;
116 }
117 }
118 AxisDR::W => {
119 if let Some(x) = coord.h.checked_sub(2) {
120 coord.h = x;
121 } else {
122 break 'outer;
123 }
124 }
125 AxisDR::NW => {
126 if let Some(x) = coord.h.checked_sub(1) {
127 coord.h = x;
128 } else {
129 break 'outer;
130 }
131 coord.v += 1;
132 if coord.v >= v_max {
133 break 'outer;
134 }
135 }
136 }
137 return Some(coord);
138 }
139 None
140}
141
142fn move_coord_q(
143 coord: DoubleCoord,
144 dir: AxisDQ,
145 h_max: usize,
146 v_max: usize,
147) -> Option<DoubleCoord> {
148 'block: {
149 let mut coord = coord;
150 match dir {
151 AxisDQ::N => {
152 coord.v += 2;
153 if coord.v >= v_max {
154 break 'block;
155 }
156 }
157 AxisDQ::NE => {
158 coord.h += 1;
159 if coord.h >= h_max {
160 break 'block;
161 }
162 coord.v += 1;
163 if coord.v >= v_max {
164 break 'block;
165 }
166 }
167 AxisDQ::SE => {
168 coord.h += 1;
169 if coord.h >= h_max {
170 break 'block;
171 }
172 if let Some(x) = coord.v.checked_sub(1) {
173 coord.v = x;
174 } else {
175 break 'block;
176 }
177 }
178 AxisDQ::S => {
179 if let Some(x) = coord.v.checked_sub(2) {
180 coord.v = x;
181 } else {
182 break 'block;
183 }
184 }
185 AxisDQ::SW => {
186 if let Some(x) = coord.h.checked_sub(1) {
187 coord.h = x;
188 } else {
189 break 'block;
190 }
191 if let Some(x) = coord.v.checked_sub(1) {
192 coord.v = x;
193 } else {
194 break 'block;
195 }
196 }
197 AxisDQ::NW => {
198 if let Some(x) = coord.h.checked_sub(1) {
199 coord.h = x;
200 } else {
201 break 'block;
202 }
203 coord.v += 1;
204 if coord.v >= v_max {
205 break 'block;
206 }
207 }
208 }
209 return Some(coord);
210 }
211 None
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
216pub struct DoubleCoordShape<
217 ShapeBase,
218 Loop,
219 H = usize,
220 V = usize,
221 Axis = <ShapeBase as DoubleCoordShapeBase>::Axis,
222> {
223 h: H,
224 v: V,
225 l: PhantomData<fn() -> Loop>,
226 t: PhantomData<fn() -> ShapeBase>,
227 a: PhantomData<fn() -> Axis>,
228}
229
230impl<ShapeBase, Loop, H, V, Axis> DoubleCoordShape<ShapeBase, Loop, H, V, Axis> {
231 pub fn new(h: H, v: V) -> Self {
233 Self {
234 h,
235 v,
236 l: PhantomData,
237 t: PhantomData,
238 a: PhantomData,
239 }
240 }
241}
242
243#[cfg(feature = "const-generic-wrap")]
245pub type ConstDoubleCoordShape<T, L, const H: usize, const V: usize> =
246 DoubleCoordShape<T, L, WrapUSIZE<H>, WrapUSIZE<V>>;
247
248#[cfg(feature = "const-generic-wrap")]
249impl<T: DoubleCoordShapeBase, L, const H: usize, const V: usize> Default
250 for ConstDoubleCoordShape<T, L, H, V>
251{
252 fn default() -> Self {
253 Self::new(WrapUSIZE::<H>, WrapUSIZE::<V>)
254 }
255}
256
257impl<B, H, V> Shape for DoubleCoordShape<B, (), H, V, AxisR>
258where
259 B: DoubleCoordShapeBase<Axis = AxisR>,
260 H: Clone + Into<usize>,
261 V: Clone + Into<usize>,
262{
263 type Axis = B::Axis;
264
265 type Coordinate = DoubleCoord;
266
267 type OffsetConvertError = ();
268
269 type CoordinateMoveError = ();
270
271 fn horizontal(&self) -> usize {
272 self.h.clone().into()
273 }
274
275 fn vertical(&self) -> usize {
276 self.v.clone().into()
277 }
278
279 fn to_offset(&self, coord: Self::Coordinate) -> Result<Offset, Self::OffsetConvertError> {
280 let h = coord.h / 2;
281 let v = coord.v;
282 if h < self.horizontal() && v < self.vertical() {
283 Ok(Offset::new(h, v))
284 } else {
285 Err(())
286 }
287 }
288
289 unsafe fn to_offset_unchecked(&self, coord: Self::Coordinate) -> Offset {
290 let h = coord.h / 2;
291 let v = coord.v;
292 Offset::new(h, v)
293 }
294
295 fn offset_to_coordinate(&self, offset: Offset) -> Self::Coordinate {
296 let v = offset.vertical;
297 let h = offset.horizontal * 2 + (v & 1);
298 DoubleCoord::new(h, v)
299 }
300
301 fn move_coord(
302 &self,
303 coord: Self::Coordinate,
304 dir: <Self::Axis as Axis>::Direction,
305 ) -> Result<Self::Coordinate, Self::CoordinateMoveError> {
306 B::move_coord(coord, dir, self.horizontal(), self.vertical()).ok_or(())
307 }
308
309 fn is_neighbor(&self, a: Self::Coordinate, b: Self::Coordinate) -> bool {
310 let dif_v = a.v.abs_diff(b.v);
311 if dif_v > 1 {
312 return false;
313 }
314 let dif_h = a.h.abs_diff(b.h);
315 dif_h + dif_v == 2
317 }
323}