1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// External includes.
// Standard includes.
use std::convert::From;
use std::ops::{Add, AddAssign, Neg, Sub};
// Internal includes.
use super::{CardinalRotation, IsPosition, Position};
/// Defines a direction on a cartesian plane where each direction is an orthogonal, and cardinal, 90-degree vector.
///
/// ```
/// # use dungen_minion_geometry::*;
/// let north: CardinalDirection = CardinalDirection::North;
/// let east: CardinalDirection = CardinalDirection::East;
/// let south: CardinalDirection = CardinalDirection::South;
/// let west: CardinalDirection = CardinalDirection::West;
///
/// // Moving from north to east is a 90-degree rotation to the right.
/// assert!((east - north) == CardinalRotation::Right90);
///
/// // Moving from north to south is a full 180-degree rotation.
/// assert!((south - north) == CardinalRotation::Full180);
///
/// // Moving from north to west is a 90-degree rotation to the left.
/// assert!((west - north) == CardinalRotation::Left90);
///
/// // Moving from north to north is defined as not a rotation, even if you rotated to get there.
/// assert!((north - north) == CardinalRotation::None);
/// ```
#[derive(Copy, Clone, Debug, Display, Eq, Hash, PartialEq)]
pub enum CardinalDirection {
/// Represents a cartesian (0, +1) direction.
North,
/// Represents a cartesian (+1, 0) direction.
East,
/// Represents a cartesian (0, -1) direction.
South,
/// Represents a cartesian (-1, 0) direction.
West,
}
impl Add<CardinalRotation> for CardinalDirection {
type Output = CardinalDirection;
fn add(self, other: CardinalRotation) -> Self::Output {
Self::from(i8::from(self) + i8::from(other))
}
}
impl AddAssign<CardinalRotation> for CardinalDirection {
fn add_assign(&mut self, other: CardinalRotation) {
*self = *self + other;
}
}
impl From<i8> for CardinalDirection {
fn from(value: i8) -> Self {
let mut value = value % 4;
if value < 0 {
value = 4 - value.abs();
}
match value {
0 => CardinalDirection::North,
1 => CardinalDirection::East,
2 => CardinalDirection::South,
3 => CardinalDirection::West,
_ => panic!("Wrapping and if-check should not allow this: {}", value),
}
}
}
impl From<CardinalDirection> for i8 {
fn from(value: CardinalDirection) -> i8 {
match value {
CardinalDirection::North => 0,
CardinalDirection::East => 1,
CardinalDirection::South => 2,
CardinalDirection::West => 3,
}
}
}
impl From<Position> for Option<CardinalDirection> {
/// Attempts to convert from a position offset to a `CardinalDirection`.
///
/// ```
/// use dungen_minion_geometry::*;
/// assert!(Some(CardinalDirection::North) == Option::<CardinalDirection>::from(Position::new(0, -1)));
/// assert!(None == Option::<CardinalDirection>::from(Position::new(1, -1)));
/// assert!(Some(CardinalDirection::East) == Option::<CardinalDirection>::from(Position::new(1, 0)));
/// assert!(None == Option::<CardinalDirection>::from(Position::new(1, 1)));
/// assert!(Some(CardinalDirection::South) == Option::<CardinalDirection>::from(Position::new(0, 1)));
/// assert!(None == Option::<CardinalDirection>::from(Position::new(-1, 1)));
/// assert!(Some(CardinalDirection::West) == Option::<CardinalDirection>::from(Position::new(-1, 0)));
/// assert!(None == Option::<CardinalDirection>::from(Position::new(-1, -1)));
/// ```
fn from(value: Position) -> Self {
let test_value = Position::new(value.x().signum(), value.y().signum());
match test_value {
Position::NORTH => Some(CardinalDirection::North),
Position::EAST => Some(CardinalDirection::East),
Position::SOUTH => Some(CardinalDirection::South),
Position::WEST => Some(CardinalDirection::West),
_ => None,
}
}
}
impl Neg for CardinalDirection {
type Output = CardinalDirection;
fn neg(self) -> Self::Output {
CardinalDirection::from(i8::from(self) + 2)
}
}
impl Sub<CardinalDirection> for CardinalDirection {
type Output = CardinalRotation;
fn sub(self, other: CardinalDirection) -> Self::Output {
CardinalRotation::from(i8::from(self) - i8::from(other))
}
}