1use std::{
2 fmt,
3 ops::{Add, Index, IndexMut, Neg, Sub},
4};
5
6use num::{
7 CheckedAdd,
8 CheckedSub,
9 One,
10 traits::{SaturatingAdd, SaturatingSub},
11};
12use rand::{
13 Rng,
14 distr::{Distribution, StandardUniform},
15};
16use serde::{Deserialize, Serialize};
17
18use crate::CoordPair;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub enum Axis {
22 Y,
23 X,
24}
25
26impl Axis {
27 pub const ALL: [Self; 2] = [Self::Y, Self::X];
28
29 pub fn shift(self) -> Self {
30 match self {
31 Self::Y => Self::X,
32 Self::X => Self::Y,
33 }
34 }
35}
36
37impl fmt::Display for Axis {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 Self::Y => write!(f, "y"),
41 Self::X => write!(f, "x"),
42 }
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
47pub enum Order {
48 Backwards,
49 Forwards,
50}
51
52impl Order {
53 pub const ALL: [Self; 2] = [Self::Backwards, Self::Forwards];
54
55 pub fn move_unit<C>(self, target: C) -> C
56 where
57 C: Add<Output = C> + Sub<Output = C> + One,
58 {
59 self.move_by(C::one(), target)
60 }
61
62 pub fn checked_move_unit<C>(self, target: &C) -> Option<C>
63 where
64 C: CheckedAdd + CheckedSub + One,
65 {
66 self.checked_move_by(&C::one(), target)
67 }
68
69 pub fn saturating_move_unit<C>(self, target: &C) -> C
70 where
71 C: SaturatingAdd + SaturatingSub + One,
72 {
73 self.saturating_move_by(&C::one(), target)
74 }
75
76 pub fn move_by<C>(self, magnitude: C, target: C) -> C
77 where
78 C: Add<Output = C> + Sub<Output = C>,
79 {
80 match self {
81 Self::Backwards => target - magnitude,
82 Self::Forwards => target + magnitude,
83 }
84 }
85
86 pub fn checked_move_by<C>(self, magnitude: &C, target: &C) -> Option<C>
87 where
88 C: CheckedAdd + CheckedSub,
89 {
90 match self {
91 Self::Backwards => target.checked_sub(magnitude),
92 Self::Forwards => target.checked_add(magnitude),
93 }
94 }
95
96 pub fn saturating_move_by<C>(self, magnitude: &C, target: &C) -> C
97 where
98 C: SaturatingAdd + SaturatingSub,
99 {
100 match self {
101 Self::Backwards => target.saturating_add(magnitude),
102 Self::Forwards => target.saturating_sub(magnitude),
103 }
104 }
105}
106
107impl fmt::Display for Order {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 match self {
110 Self::Backwards => write!(f, "-"),
111 Self::Forwards => write!(f, "+"),
112 }
113 }
114}
115
116#[derive(
117 Debug,
118 Clone,
119 Copy,
120 PartialEq,
121 Eq,
122 PartialOrd,
123 Ord,
124 Hash,
125 Serialize,
126 Deserialize,
127)]
128pub enum Direction {
129 Up,
130 Left,
131 Down,
132 Right,
133}
134
135impl Direction {
136 pub const COUNT: usize = 4;
137
138 pub const ALL: [Self; Self::COUNT] =
139 [Self::Up, Self::Left, Self::Down, Self::Right];
140
141 pub fn new(axis: Axis, order: Order) -> Self {
142 match (axis, order) {
143 (Axis::Y, Order::Backwards) => Self::Up,
144 (Axis::X, Order::Backwards) => Self::Left,
145 (Axis::Y, Order::Forwards) => Self::Down,
146 (Axis::X, Order::Forwards) => Self::Right,
147 }
148 }
149
150 pub fn axis(self) -> Axis {
151 match self {
152 Self::Up | Self::Down => Axis::Y,
153 Self::Left | Self::Right => Axis::X,
154 }
155 }
156
157 pub fn order(self) -> Order {
158 match self {
159 Self::Up | Self::Left => Order::Backwards,
160 Self::Down | Self::Right => Order::Forwards,
161 }
162 }
163
164 pub fn move_unit<C>(self, target: CoordPair<C>) -> CoordPair<C>
165 where
166 C: Add<Output = C> + Sub<Output = C> + One,
167 {
168 DirectionVec::unit(self).mov(target)
169 }
170
171 pub fn checked_move_unit<C>(
172 self,
173 target: &CoordPair<C>,
174 ) -> Option<CoordPair<C>>
175 where
176 C: CheckedAdd + CheckedSub + One + Clone,
177 {
178 DirectionVec::unit(self).as_ref().checked_move(target)
179 }
180
181 pub fn checked_move_unit_by_ref<C>(
182 self,
183 target: CoordPair<&C>,
184 ) -> Option<CoordPair<C>>
185 where
186 C: CheckedAdd + CheckedSub + One + Clone,
187 {
188 DirectionVec::unit(self).as_ref().checked_move_by_ref(target)
189 }
190
191 pub fn saturating_move_unit<C>(self, target: &CoordPair<C>) -> CoordPair<C>
192 where
193 C: SaturatingAdd + SaturatingSub + One + Clone,
194 {
195 DirectionVec::unit(self).as_ref().saturating_move(target)
196 }
197
198 pub fn saturating_move_unit_by_ref<C>(
199 self,
200 target: CoordPair<&C>,
201 ) -> CoordPair<C>
202 where
203 C: SaturatingAdd + SaturatingSub + One + Clone,
204 {
205 DirectionVec::unit(self).as_ref().saturating_move_by_ref(target)
206 }
207
208 pub fn move_by<C>(self, magnitude: C, target: CoordPair<C>) -> CoordPair<C>
209 where
210 C: Add<Output = C> + Sub<Output = C>,
211 {
212 DirectionVec { direction: self, magnitude }.mov(target)
213 }
214
215 pub fn checked_move_by<C>(
216 self,
217 magnitude: &C,
218 target: &CoordPair<C>,
219 ) -> Option<CoordPair<C>>
220 where
221 C: CheckedAdd + CheckedSub + Clone,
222 {
223 DirectionVec { direction: self, magnitude }.checked_move(target)
224 }
225
226 pub fn checked_move_by_ref_by<C>(
227 self,
228 magnitude: &C,
229 target: CoordPair<&C>,
230 ) -> Option<CoordPair<C>>
231 where
232 C: CheckedAdd + CheckedSub + Clone,
233 {
234 DirectionVec { direction: self, magnitude }.checked_move_by_ref(target)
235 }
236
237 pub fn saturating_move_by<C>(
238 self,
239 magnitude: &C,
240 target: &CoordPair<C>,
241 ) -> CoordPair<C>
242 where
243 C: SaturatingAdd + SaturatingSub + Clone,
244 {
245 self.saturating_move_by_ref_by(magnitude, target.as_ref())
246 }
247
248 pub fn saturating_move_by_ref_by<C>(
249 self,
250 magnitude: &C,
251 target: CoordPair<&C>,
252 ) -> CoordPair<C>
253 where
254 C: SaturatingAdd + SaturatingSub + Clone,
255 {
256 match self.axis() {
257 Axis::Y => CoordPair {
258 y: self.order().saturating_move_by(magnitude, target.y),
259 x: target.x.clone(),
260 },
261 Axis::X => CoordPair {
262 x: self.order().saturating_move_by(magnitude, target.x),
263 y: target.y.clone(),
264 },
265 }
266 }
267}
268
269impl fmt::Display for Direction {
270 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271 match self {
272 Self::Up => write!(f, "-y"),
273 Self::Left => write!(f, "-x"),
274 Self::Down => write!(f, "+y"),
275 Self::Right => write!(f, "+x"),
276 }
277 }
278}
279
280impl Neg for Direction {
281 type Output = Self;
282
283 fn neg(self) -> Self::Output {
284 match self {
285 Self::Up => Self::Down,
286 Self::Left => Self::Right,
287 Self::Right => Self::Left,
288 Self::Down => Self::Up,
289 }
290 }
291}
292
293impl Distribution<Direction> for StandardUniform {
294 fn sample<R>(&self, rng: &mut R) -> Direction
295 where
296 R: Rng + ?Sized,
297 {
298 let index = rng.random_range(0 .. Direction::COUNT);
299 Direction::ALL[index]
300 }
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
304pub struct DirectionMap<T> {
305 pub up: T,
306 pub left: T,
307 pub down: T,
308 pub right: T,
309}
310
311impl<T> DirectionMap<T> {
312 pub fn from_dirs<F>(mut generator: F) -> DirectionMap<T>
313 where
314 F: FnMut(Direction) -> T,
315 {
316 Self {
317 up: generator(Direction::Up),
318 left: generator(Direction::Left),
319 down: generator(Direction::Down),
320 right: generator(Direction::Right),
321 }
322 }
323
324 pub fn map<F, U>(self, mut mapper: F) -> DirectionMap<U>
325 where
326 F: FnMut(T) -> U,
327 {
328 self.map_with_dirs(|elem, _| mapper(elem))
329 }
330
331 pub fn map_with_dirs<F, U>(self, mut mapper: F) -> DirectionMap<U>
332 where
333 F: FnMut(T, Direction) -> U,
334 {
335 DirectionMap {
336 up: mapper(self.up, Direction::Up),
337 left: mapper(self.left, Direction::Left),
338 down: mapper(self.down, Direction::Down),
339 right: mapper(self.right, Direction::Right),
340 }
341 }
342
343 pub fn as_ref(&self) -> DirectionMap<&T> {
344 DirectionMap {
345 up: &self.up,
346 left: &self.left,
347 down: &self.down,
348 right: &self.right,
349 }
350 }
351
352 pub fn as_mut(&mut self) -> DirectionMap<&mut T> {
353 DirectionMap {
354 up: &mut self.up,
355 left: &mut self.left,
356 down: &mut self.down,
357 right: &mut self.right,
358 }
359 }
360}
361
362impl<'a, T> DirectionMap<&'a T> {
363 pub fn copied(self) -> DirectionMap<T>
364 where
365 T: Copy,
366 {
367 self.map(|a| *a)
368 }
369
370 pub fn cloned(self) -> DirectionMap<T>
371 where
372 T: Clone,
373 {
374 self.map(Clone::clone)
375 }
376}
377
378impl<'a, T> DirectionMap<&'a mut T> {
379 pub fn copied(self) -> DirectionMap<T>
380 where
381 T: Copy,
382 {
383 self.map(|a| *a)
384 }
385
386 pub fn cloned(self) -> DirectionMap<T>
387 where
388 T: Clone,
389 {
390 self.map(|a| a.clone())
391 }
392
393 pub fn share(self) -> DirectionMap<&'a T> {
394 self.map(|a| &*a)
395 }
396}
397
398impl<T> DirectionMap<Option<T>> {
399 pub fn transpose(self) -> Option<DirectionMap<T>> {
400 Some(DirectionMap {
401 up: self.up?,
402 left: self.left?,
403 down: self.down?,
404 right: self.right?,
405 })
406 }
407
408 pub fn from_transposed(transposed: Option<DirectionMap<T>>) -> Self {
409 match transposed {
410 Some(table) => table.map(Some),
411 None => Self::from_dirs(|_| None),
412 }
413 }
414}
415
416impl<T, E> DirectionMap<Result<T, E>> {
417 pub fn transpose(self) -> Result<DirectionMap<T>, E> {
418 Ok(DirectionMap {
419 up: self.up?,
420 left: self.left?,
421 down: self.down?,
422 right: self.right?,
423 })
424 }
425
426 pub fn from_transposed(transposed: Result<DirectionMap<T>, E>) -> Self
427 where
428 E: Clone,
429 {
430 match transposed {
431 Ok(table) => table.map(Ok),
432 Err(error) => Self::from_dirs(|_| Err(error.clone())),
433 }
434 }
435}
436
437impl<T> Index<Direction> for DirectionMap<T> {
438 type Output = T;
439
440 fn index(&self, index: Direction) -> &Self::Output {
441 match index {
442 Direction::Up => &self.up,
443 Direction::Left => &self.left,
444 Direction::Down => &self.down,
445 Direction::Right => &self.right,
446 }
447 }
448}
449
450impl<T> Index<(Axis, Order)> for DirectionMap<T> {
451 type Output = T;
452
453 fn index(&self, (axis, order): (Axis, Order)) -> &Self::Output {
454 &self[Direction::new(axis, order)]
455 }
456}
457
458impl<T> IndexMut<Direction> for DirectionMap<T> {
459 fn index_mut(&mut self, index: Direction) -> &mut Self::Output {
460 match index {
461 Direction::Up => &mut self.up,
462 Direction::Left => &mut self.left,
463 Direction::Down => &mut self.down,
464 Direction::Right => &mut self.right,
465 }
466 }
467}
468
469impl<T> IndexMut<(Axis, Order)> for DirectionMap<T> {
470 fn index_mut(&mut self, (axis, order): (Axis, Order)) -> &mut Self::Output {
471 &mut self[Direction::new(axis, order)]
472 }
473}
474
475#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
476pub struct DirectionFlags {
477 bits: u8,
478}
479
480impl DirectionFlags {
481 pub fn new(map: DirectionMap<bool>) -> Self {
482 Self::packed([map, DirectionMap::default()])
483 }
484
485 pub fn packed(maps: [DirectionMap<bool>; 2]) -> Self {
486 let mut bits = 0_u8;
487 for map in maps.into_iter().rev() {
488 for direction in Direction::ALL.into_iter().rev() {
489 bits <<= 1;
490 bits |= u8::from(map[direction]);
491 }
492 }
493 Self { bits }
494 }
495
496 pub fn map(self) -> DirectionMap<bool> {
497 self.packed_maps()[0]
498 }
499
500 pub fn packed_maps(self) -> [DirectionMap<bool>; 2] {
501 let mut bits = self.bits;
502 let mut maps = [DirectionMap::default(); 2];
503 for map in &mut maps {
504 for direction in Direction::ALL {
505 map[direction] = (bits & 1) != 0;
506 bits >>= 1;
507 }
508 }
509 maps
510 }
511
512 pub fn with<F>(self, mapper: F) -> Self
513 where
514 F: FnOnce(DirectionMap<bool>) -> DirectionMap<bool>,
515 {
516 self.packed_with(|maps| [mapper(maps[0]), maps[1]])
517 }
518
519 pub fn packed_with<F>(self, mapper: F) -> Self
520 where
521 F: FnOnce([DirectionMap<bool>; 2]) -> [DirectionMap<bool>; 2],
522 {
523 Self::packed(mapper(self.packed_maps()))
524 }
525
526 pub fn modify<F, T>(&mut self, modifier: F) -> T
527 where
528 F: FnOnce(&mut DirectionMap<bool>) -> T,
529 {
530 self.packed_modify(|maps| modifier(&mut maps[0]))
531 }
532
533 pub fn packed_modify<F, T>(&mut self, modifier: F) -> T
534 where
535 F: FnOnce(&mut [DirectionMap<bool>; 2]) -> T,
536 {
537 let mut maps = self.packed_maps();
538 let output = modifier(&mut maps);
539 *self = Self::packed(maps);
540 output
541 }
542}
543
544impl From<DirectionMap<bool>> for DirectionFlags {
545 fn from(map: DirectionMap<bool>) -> Self {
546 Self::new(map)
547 }
548}
549
550impl From<DirectionFlags> for DirectionMap<bool> {
551 fn from(flags: DirectionFlags) -> Self {
552 flags.map()
553 }
554}
555
556impl From<[DirectionMap<bool>; 2]> for DirectionFlags {
557 fn from(packed_maps: [DirectionMap<bool>; 2]) -> Self {
558 Self::packed(packed_maps)
559 }
560}
561
562impl From<DirectionFlags> for [DirectionMap<bool>; 2] {
563 fn from(flags: DirectionFlags) -> Self {
564 flags.packed_maps()
565 }
566}
567
568#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
569pub struct DirectionVec<C> {
570 pub direction: Direction,
571 pub magnitude: C,
572}
573
574impl<C> Neg for DirectionVec<C> {
575 type Output = Self;
576
577 fn neg(self) -> Self::Output {
578 Self { direction: -self.direction, ..self }
579 }
580}
581
582impl<C> DirectionVec<C> {
583 pub fn unit(direction: Direction) -> Self
584 where
585 C: One,
586 {
587 Self { direction, magnitude: C::one() }
588 }
589
590 pub fn as_ref(&self) -> DirectionVec<&C> {
591 DirectionVec { direction: self.direction, magnitude: &self.magnitude }
592 }
593
594 pub fn as_mut(&mut self) -> DirectionVec<&mut C> {
595 DirectionVec {
596 direction: self.direction,
597 magnitude: &mut self.magnitude,
598 }
599 }
600
601 pub fn map<F, C0>(self, mapper: F) -> DirectionVec<C0>
602 where
603 F: FnOnce(C) -> C0,
604 {
605 DirectionVec {
606 direction: self.direction,
607 magnitude: mapper(self.magnitude),
608 }
609 }
610
611 pub fn with_mangitude<C0>(&self, new_magnitude: C0) -> DirectionVec<C0> {
612 self.as_ref().map(|_| new_magnitude)
613 }
614
615 pub fn mov(self, target: CoordPair<C>) -> CoordPair<C>
616 where
617 C: Add<Output = C> + Sub<Output = C>,
618 {
619 match self.direction.axis() {
620 Axis::Y => CoordPair {
621 y: self.direction.order().move_by(self.magnitude, target.y),
622 ..target
623 },
624 Axis::X => CoordPair {
625 x: self.direction.order().move_by(self.magnitude, target.x),
626 ..target
627 },
628 }
629 }
630}
631
632impl<'a, C> DirectionVec<&'a C> {
633 pub fn copied(self) -> DirectionVec<C>
634 where
635 C: Copy,
636 {
637 self.map(|m| *m)
638 }
639
640 pub fn cloned(self) -> DirectionVec<C>
641 where
642 C: Clone,
643 {
644 self.map(Clone::clone)
645 }
646
647 pub fn checked_move(self, target: &CoordPair<C>) -> Option<CoordPair<C>>
648 where
649 C: CheckedAdd + CheckedSub + Clone,
650 {
651 self.checked_move_by_ref(target.as_ref())
652 }
653
654 pub fn checked_move_by_ref(
655 self,
656 target: CoordPair<&C>,
657 ) -> Option<CoordPair<C>>
658 where
659 C: CheckedAdd + CheckedSub + Clone,
660 {
661 match self.direction.axis() {
662 Axis::Y => Some(CoordPair {
663 y: self
664 .direction
665 .order()
666 .checked_move_by(self.magnitude, target.y)?,
667 x: target.x.clone(),
668 }),
669 Axis::X => Some(CoordPair {
670 x: self
671 .direction
672 .order()
673 .checked_move_by(self.magnitude, target.x)?,
674 y: target.y.clone(),
675 }),
676 }
677 }
678
679 pub fn saturating_move(self, target: &CoordPair<C>) -> CoordPair<C>
680 where
681 C: SaturatingAdd + SaturatingSub + Clone,
682 {
683 self.saturating_move_by_ref(target.as_ref())
684 }
685
686 pub fn saturating_move_by_ref(self, target: CoordPair<&C>) -> CoordPair<C>
687 where
688 C: SaturatingAdd + SaturatingSub + Clone,
689 {
690 match self.direction.axis() {
691 Axis::Y => CoordPair {
692 y: self
693 .direction
694 .order()
695 .saturating_move_by(self.magnitude, target.y),
696 x: target.x.clone(),
697 },
698 Axis::X => CoordPair {
699 x: self
700 .direction
701 .order()
702 .saturating_move_by(self.magnitude, target.x),
703 y: target.y.clone(),
704 },
705 }
706 }
707}
708
709impl<'a, C> DirectionVec<&'a mut C> {
710 pub fn copied(self) -> DirectionVec<C>
711 where
712 C: Copy,
713 {
714 self.map(|m| *m)
715 }
716
717 pub fn cloned(self) -> DirectionVec<C>
718 where
719 C: Clone,
720 {
721 self.map(|m| m.clone())
722 }
723
724 pub fn share(self) -> DirectionVec<&'a C> {
725 self.map(|m| &*m)
726 }
727}
728
729#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
730pub enum Diagonal {
731 TopLeft,
732 TopRight,
733 BottomLeft,
734 BottomRight,
735}
736
737impl Diagonal {
738 pub const ALL: [Self; 4] =
739 [Self::TopLeft, Self::TopRight, Self::BottomLeft, Self::BottomRight];
740
741 pub fn new(axes_orders: CoordPair<Order>) -> Self {
742 match axes_orders {
743 CoordPair { y: Order::Backwards, x: Order::Backwards } => {
744 Self::TopLeft
745 },
746 CoordPair { y: Order::Backwards, x: Order::Forwards } => {
747 Self::TopRight
748 },
749 CoordPair { y: Order::Forwards, x: Order::Backwards } => {
750 Self::BottomLeft
751 },
752 CoordPair { y: Order::Forwards, x: Order::Forwards } => {
753 Self::BottomRight
754 },
755 }
756 }
757
758 pub fn axes_orders(self) -> CoordPair<Order> {
759 match self {
760 Self::TopLeft => {
761 CoordPair { y: Order::Backwards, x: Order::Backwards }
762 },
763 Self::TopRight => {
764 CoordPair { y: Order::Backwards, x: Order::Forwards }
765 },
766 Self::BottomLeft => {
767 CoordPair { y: Order::Forwards, x: Order::Backwards }
768 },
769 Self::BottomRight => {
770 CoordPair { y: Order::Forwards, x: Order::Forwards }
771 },
772 }
773 }
774}
775
776impl fmt::Display for Diagonal {
777 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778 match self {
779 Self::TopLeft => write!(f, "-y -x"),
780 Self::TopRight => write!(f, "-y +x"),
781 Self::BottomLeft => write!(f, "+y -x"),
782 Self::BottomRight => write!(f, "+y +x"),
783 }
784 }
785}
786
787#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
788pub struct DiagonalMap<T> {
789 pub top_left: T,
790 pub top_right: T,
791 pub bottom_left: T,
792 pub bottom_right: T,
793}
794
795impl<T> Index<Diagonal> for DiagonalMap<T> {
796 type Output = T;
797
798 fn index(&self, index: Diagonal) -> &Self::Output {
799 match index {
800 Diagonal::TopLeft => &self.top_left,
801 Diagonal::TopRight => &self.top_right,
802 Diagonal::BottomLeft => &self.bottom_left,
803 Diagonal::BottomRight => &self.bottom_right,
804 }
805 }
806}
807
808impl<T> Index<CoordPair<Order>> for DiagonalMap<T> {
809 type Output = T;
810
811 fn index(&self, index: CoordPair<Order>) -> &Self::Output {
812 &self[Diagonal::new(index)]
813 }
814}
815
816impl<T> IndexMut<Diagonal> for DiagonalMap<T> {
817 fn index_mut(&mut self, index: Diagonal) -> &mut Self::Output {
818 match index {
819 Diagonal::TopLeft => &mut self.top_left,
820 Diagonal::TopRight => &mut self.top_right,
821 Diagonal::BottomLeft => &mut self.bottom_left,
822 Diagonal::BottomRight => &mut self.bottom_right,
823 }
824 }
825}
826
827impl<T> IndexMut<CoordPair<Order>> for DiagonalMap<T> {
828 fn index_mut(&mut self, index: CoordPair<Order>) -> &mut Self::Output {
829 &mut self[Diagonal::new(index)]
830 }
831}