1#[cfg(feature = "const-generic-wrap")]
2use const_generic_wrap::*;
3use std::marker::{Copy, PhantomData};
4
5use crate::{hex::shapes::*, lattice_abstract::shapes::*};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
9pub struct HexOffset(Offset);
10
11impl HexOffset {
12 pub fn new(x: usize, y: usize) -> Self {
14 Self(Offset {
15 horizontal: x,
16 vertical: y,
17 })
18 }
19
20 pub fn horizontal(&self) -> usize {
22 self.0.horizontal()
23 }
24
25 pub fn vertical(&self) -> usize {
27 self.0.vertical()
28 }
29}
30
31impl Coordinate for HexOffset {}
32pub trait HexOffsetShapeBase: Clone {
34 type Axis: Axis;
35 fn move_coord(
36 horizontal: usize,
37 vertical: usize,
38 coord: HexOffset,
39 dir: <Self::Axis as Axis>::Direction,
40 ) -> Result<HexOffset, ()>;
41}
42
43pub trait HexOffsetShapeBaseLoopEW: HexOffsetShapeBase {
45 fn move_coord_lew(
46 horizontal: usize,
47 vertical: usize,
48 coord: HexOffset,
49 dir: <Self::Axis as Axis>::Direction,
50 ) -> Result<HexOffset, ()>;
51}
52
53impl HexOffsetShapeBase for OddR {
54 type Axis = AxisR;
55
56 fn move_coord(
57 horizontal: usize,
58 vertical: usize,
59 coord: HexOffset,
60 dir: AxisDR,
61 ) -> Result<HexOffset, ()> {
62 move_coord_r(horizontal, vertical, coord, dir, 0)
63 }
64}
65
66impl HexOffsetShapeBaseLoopEW for OddR {
67 fn move_coord_lew(
68 horizontal: usize,
69 vertical: usize,
70 coord: HexOffset,
71 dir: AxisDR,
72 ) -> Result<HexOffset, ()> {
73 move_coord_r_lew(horizontal, vertical, coord, dir, 0)
74 }
75}
76
77impl HexOffsetShapeBase for EvenR {
78 type Axis = AxisR;
79
80 fn move_coord(
81 horizontal: usize,
82 vertical: usize,
83 coord: HexOffset,
84 dir: AxisDR,
85 ) -> Result<HexOffset, ()> {
86 move_coord_r(horizontal, vertical, coord, dir, 1)
87 }
88}
89
90impl HexOffsetShapeBaseLoopEW for EvenR {
91 fn move_coord_lew(
92 horizontal: usize,
93 vertical: usize,
94 coord: HexOffset,
95 dir: AxisDR,
96 ) -> Result<HexOffset, ()> {
97 move_coord_r_lew(horizontal, vertical, coord, dir, 1)
98 }
99}
100
101fn move_coord_r(
102 horizontal: usize,
103 vertical: usize,
104 coord: HexOffset,
105 dir: AxisDR,
106 flag: usize,
107) -> Result<HexOffset, ()> {
108 let o = coord.0;
109 match (dir, o.vertical() & 1 == flag) {
110 (AxisDR::E, _) => o.add_x(1).check_x(horizontal),
111 (AxisDR::W, _) => o.sub_x(1),
112 (AxisDR::NE, true) | (AxisDR::NW, false) => o.add_y(1).check_y(vertical),
113 (AxisDR::SE, true) | (AxisDR::SW, false) => o.sub_y(1),
114 (AxisDR::NE, false) => o
115 .add_x(1)
116 .check_x(horizontal)
117 .and_then(|o| o.add_y(1).check_y(vertical)),
118 (AxisDR::SE, false) => o.add_x(1).check_x(horizontal).and_then(|o| o.sub_y(1)),
119 (AxisDR::SW, true) => o.sub_x(1).and_then(|o| o.sub_y(1)),
120 (AxisDR::NW, true) => o.sub_x(1).and_then(|o| o.add_y(1).check_y(vertical)),
121 }
122 .map(HexOffset)
123 .ok_or(())
124}
125
126fn move_coord_r_lew(
127 horizontal: usize,
128 vertical: usize,
129 coord: HexOffset,
130 dir: AxisDR,
131 flag: usize,
132) -> Result<HexOffset, ()> {
133 let o = coord.0;
134 match (dir, o.vertical() & 1 == flag) {
135 (AxisDR::E, _) => Some(o.add_x(1).check_x(horizontal).unwrap_or_else(|| o.set_x(0))),
136 (AxisDR::W, _) => Some(o.sub_x(1).unwrap_or_else(|| o.set_x(horizontal - 1))),
137 (AxisDR::NE, true) | (AxisDR::NW, false) => o.add_y(1).check_y(vertical),
138 (AxisDR::SE, true) | (AxisDR::SW, false) => o.sub_y(1),
139 (AxisDR::NE, false) => o
140 .add_x(1)
141 .check_x(horizontal)
142 .unwrap_or_else(|| o.set_x(0))
143 .add_y(1)
144 .check_y(vertical),
145 (AxisDR::SE, false) => o
146 .add_x(1)
147 .check_x(horizontal)
148 .unwrap_or_else(|| o.set_x(0))
149 .sub_y(1),
150 (AxisDR::SW, true) => o
151 .sub_x(1)
152 .unwrap_or_else(|| o.set_x(horizontal - 1))
153 .sub_y(1),
154 (AxisDR::NW, true) => o
155 .sub_x(1)
156 .unwrap_or_else(|| o.set_x(horizontal - 1))
157 .add_y(1)
158 .check_y(vertical),
159 }
160 .map(HexOffset)
161 .ok_or(())
162}
163
164impl HexOffsetShapeBase for OddQ {
165 type Axis = AxisQ;
166
167 fn move_coord(
168 horizontal: usize,
169 vertical: usize,
170 coord: HexOffset,
171 dir: AxisDQ,
172 ) -> Result<HexOffset, ()> {
173 move_coord_q(horizontal, vertical, coord, dir, 0)
174 }
175}
176
177impl HexOffsetShapeBaseLoopEW for OddQ {
178 fn move_coord_lew(
179 horizontal: usize,
180 vertical: usize,
181 coord: HexOffset,
182 dir: AxisDQ,
183 ) -> Result<HexOffset, ()> {
184 move_coord_q_lew(horizontal, vertical, coord, dir, 0)
185 }
186}
187
188impl HexOffsetShapeBase for EvenQ {
189 type Axis = AxisQ;
190
191 fn move_coord(
192 horizontal: usize,
193 vertical: usize,
194 coord: HexOffset,
195 dir: AxisDQ,
196 ) -> Result<HexOffset, ()> {
197 move_coord_q(horizontal, vertical, coord, dir, 1)
198 }
199}
200
201impl HexOffsetShapeBaseLoopEW for EvenQ {
202 fn move_coord_lew(
203 horizontal: usize,
204 vertical: usize,
205 coord: HexOffset,
206 dir: AxisDQ,
207 ) -> Result<HexOffset, ()> {
208 move_coord_q_lew(horizontal, vertical, coord, dir, 1)
209 }
210}
211
212impl<T, A> HexOffsetShapeBase for DirectedMarker<T>
213where
214 T: HexOffsetShapeBase<Axis = A>,
215 A: Axis,
216 A::Direction: Axis<Direction = A::Direction>,
217{
218 type Axis = <T::Axis as Axis>::Direction;
219
220 fn move_coord(
221 horizontal: usize,
222 vertical: usize,
223 coord: HexOffset,
224 dir: Self::Axis,
225 ) -> Result<HexOffset, ()> {
226 T::move_coord(horizontal, vertical, coord, dir)
227 }
228}
229
230fn move_coord_q(
231 horizontal: usize,
232 vertical: usize,
233 coord: HexOffset,
234 dir: AxisDQ,
235 flag: usize,
236) -> Result<HexOffset, ()> {
237 let o = coord.0;
238 match (dir, o.vertical() & 1 != flag) {
239 (AxisDQ::N, _) => o.add_y(1).check_y(vertical),
240 (AxisDQ::S, _) => o.sub_y(1),
241 (AxisDQ::NE, true) | (AxisDQ::NW, false) => o.add_x(1).check_x(horizontal),
242 (AxisDQ::SE, true) | (AxisDQ::SW, false) => o.sub_x(1),
243 (AxisDQ::NE, false) => o.add_y(1).add_x(1).check_x(horizontal),
244 (AxisDQ::SE, false) => o.add_y(1).sub_x(1).and_then(|o| o.check_y(vertical)),
245 (AxisDQ::SW, true) => o.sub_y(1).and_then(|o| o.sub_x(1)),
246 (AxisDQ::NW, true) => o.sub_y(1).and_then(|o| o.add_x(1).check_x(horizontal)),
247 }
248 .map(HexOffset)
249 .ok_or(())
250}
251
252fn move_coord_q_lew(
253 horizontal: usize,
254 vertical: usize,
255 coord: HexOffset,
256 dir: AxisDQ,
257 flag: usize,
258) -> Result<HexOffset, ()> {
259 let o = coord.0;
260 match (dir, o.vertical() & 1 != flag) {
261 (AxisDQ::N, _) => Some(o.add_x(1).check_x(horizontal).unwrap_or_else(|| o.set_x(0))),
262 (AxisDQ::S, _) => Some(o.sub_x(1).unwrap_or_else(|| o.set_x(horizontal - 1))),
263 (AxisDQ::NE, true) | (AxisDQ::NW, false) => o.add_x(1).check_x(horizontal),
264 (AxisDQ::SE, true) | (AxisDQ::SW, false) => o.sub_x(1),
265 (AxisDQ::NE, false) => o
266 .add_x(1)
267 .check_x(horizontal)
268 .unwrap_or_else(|| o.set_x(0))
269 .add_y(1)
270 .check_y(vertical),
271 (AxisDQ::SE, false) => o
272 .add_x(1)
273 .check_x(horizontal)
274 .unwrap_or_else(|| o.set_x(0))
275 .sub_y(1),
276 (AxisDQ::SW, true) => o
277 .sub_x(1)
278 .unwrap_or_else(|| o.set_x(horizontal - 1))
279 .sub_y(1),
280 (AxisDQ::NW, true) => o
281 .sub_x(1)
282 .unwrap_or_else(|| o.set_x(horizontal - 1))
283 .add_y(1)
284 .check_y(vertical),
285 }
286 .map(HexOffset)
287 .ok_or(())
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
292pub struct HexOffsetShape<ShapeBase, Loop, H = usize, V = usize> {
293 h: H,
294 v: V,
295 l: PhantomData<fn() -> Loop>,
296 t: PhantomData<fn() -> ShapeBase>,
297}
298
299impl<B, L, H, V> HexOffsetShape<B, L, H, V>
300where
301 H: Into<usize> + Copy,
302 V: Into<usize> + Copy,
303{
304 pub fn new(h: H, v: V) -> Self {
306 Self {
307 h,
308 v,
309 l: PhantomData,
310 t: PhantomData,
311 }
312 }
313}
314
315#[cfg(feature = "const-generic-wrap")]
317pub type ConstHexOffsetShape<T, L, const H: usize, const V: usize> =
318 HexOffsetShape<T, L, WrapUSIZE<H>, WrapUSIZE<V>>;
319
320#[cfg(feature = "const-generic-wrap")]
321impl<T, L, const H: usize, const V: usize> Default for ConstHexOffsetShape<T, L, H, V> {
322 fn default() -> Self {
323 Self::new(WrapUSIZE::<H>, WrapUSIZE::<V>)
324 }
325}
326
327impl<B, H, V> Shape for HexOffsetShape<B, (), H, V>
328where
329 B: HexOffsetShapeBase,
330 H: Into<usize> + Copy,
331 V: Into<usize> + Copy,
332{
333 type Axis = B::Axis;
334 type Coordinate = HexOffset;
335 type OffsetConvertError = ();
336 type CoordinateMoveError = ();
337
338 fn horizontal(&self) -> usize {
339 self.h.into()
340 }
341
342 fn vertical(&self) -> usize {
343 self.v.into()
344 }
345
346 fn to_offset(&self, coord: Self::Coordinate) -> Result<Offset, Self::OffsetConvertError> {
347 let offset = coord.0;
348 if offset.horizontal() < self.horizontal() && offset.vertical() < self.vertical() {
349 Ok(offset)
350 } else {
351 Err(())
352 }
353 }
354
355 fn offset_to_coordinate(&self, offset: Offset) -> Self::Coordinate {
356 HexOffset(offset)
357 }
358
359 unsafe fn to_offset_unchecked(&self, coord: Self::Coordinate) -> Offset {
360 coord.0
361 }
362
363 fn horizontal_edge_size(&self, _axis: Self::Axis) -> usize {
364 self.horizontal()
365 }
366
367 fn vertical_edge_size(&self, _axis: Self::Axis) -> usize {
368 self.vertical()
369 }
370
371 fn move_coord(
372 &self,
373 coord: Self::Coordinate,
374 dir: <Self::Axis as Axis>::Direction,
375 ) -> Result<Self::Coordinate, Self::CoordinateMoveError> {
376 B::move_coord(self.horizontal(), self.vertical(), coord, dir)
377 }
378}
379
380impl<B, H, V> Shape for HexOffsetShape<B, LoopEW, H, V>
381where
382 B: HexOffsetShapeBaseLoopEW,
383 H: Into<usize> + Copy,
384 V: Into<usize> + Copy,
385{
386 type Axis = B::Axis;
387 type Coordinate = HexOffset;
388 type OffsetConvertError = ();
389 type CoordinateMoveError = ();
390
391 fn horizontal(&self) -> usize {
392 self.h.into()
393 }
394
395 fn vertical(&self) -> usize {
396 self.v.into()
397 }
398
399 fn to_offset(&self, coord: Self::Coordinate) -> Result<Offset, Self::OffsetConvertError> {
400 let offset = coord.0;
401 if offset.horizontal() < self.horizontal() && offset.vertical() < self.vertical() {
402 Ok(offset)
403 } else {
404 Err(())
405 }
406 }
407
408 fn offset_to_coordinate(&self, offset: Offset) -> Self::Coordinate {
409 HexOffset(offset)
410 }
411
412 unsafe fn to_offset_unchecked(&self, coord: Self::Coordinate) -> Offset {
413 coord.0
414 }
415
416 fn horizontal_edge_size(&self, _axis: Self::Axis) -> usize {
417 self.horizontal()
418 }
419
420 fn vertical_edge_size(&self, _axis: Self::Axis) -> usize {
421 self.vertical()
422 }
423
424 fn move_coord(
425 &self,
426 coord: Self::Coordinate,
427 dir: <Self::Axis as Axis>::Direction,
428 ) -> Result<Self::Coordinate, Self::CoordinateMoveError> {
429 B::move_coord_lew(self.horizontal(), self.vertical(), coord, dir)
430 }
431}