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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! A direction.
use std::ops::Neg;
use crate::Vector2;
/// A direction.
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum Direction {
/// Upward direction (negative Y-axis).
Up,
/// Rightward direction (positive X-axis).
Right,
/// Downward direction (positive Y-axis).
Down,
/// Leftward direction (negative X-axis).
Left,
}
impl Direction {
/// Returns an iterator over all directions.
pub fn iter() -> impl Iterator<Item = Self> {
[Self::Up, Self::Right, Self::Down, Self::Left].into_iter()
}
/// Rotates the direction 90° clockwise.
///
/// # Examples
///
/// ```
/// # use soukoban::prelude::*;
/// assert_eq!(Direction::Up.rotate_cw(), Direction::Right);
///
/// // Rotate the direction 90° counter-clockwise.
/// assert_eq!(-Direction::Right.rotate_cw(), Direction::Up);
/// ```
pub const fn rotate_cw(self) -> Self {
match self {
Self::Up => Self::Right,
Self::Right => Self::Down,
Self::Down => Self::Left,
Self::Left => Self::Up,
}
}
/// Rotates the direction 90° counter-clockwise.
///
/// # Examples
///
/// ```
/// # use soukoban::prelude::*;
/// assert_eq!(Direction::Up.rotate_ccw(), Direction::Left);
/// ```
pub fn rotate_ccw(self) -> Self {
-self.rotate_cw()
}
/// Flips the direction horizontally.
///
/// # Examples
///
/// ```
/// # use soukoban::prelude::*;
/// assert_eq!(Direction::Left.flip_horizontal(), Direction::Right);
/// assert_eq!(Direction::Up.flip_horizontal(), Direction::Up);
/// ```
pub const fn flip_horizontal(self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
Self::Up | Self::Down => self,
}
}
/// Flips the direction vertically.
///
/// # Examples
///
/// ```
/// # use soukoban::prelude::*;
/// assert_eq!(Direction::Up.flip_vertical(), Direction::Down);
/// assert_eq!(Direction::Left.flip_vertical(), Direction::Left);
/// ```
pub const fn flip_vertical(self) -> Self {
match self {
Self::Up => Self::Down,
Self::Down => Self::Up,
Self::Left | Self::Right => self,
}
}
}
impl Neg for Direction {
type Output = Self;
fn neg(self) -> Self::Output {
self.flip_horizontal().flip_vertical()
}
}
impl From<Direction> for Vector2<i32> {
fn from(direction: Direction) -> Self {
use Direction as E;
match direction {
E::Up => -Self::y(),
E::Right => Self::x(),
E::Down => Self::y(),
E::Left => -Self::x(),
}
}
}
impl TryFrom<Vector2<i32>> for Direction {
type Error = ();
fn try_from(vector: Vector2<i32>) -> Result<Self, Self::Error> {
use Direction::*;
match vector {
v if v == -Vector2::<i32>::y() => Ok(Up),
v if v == Vector2::<i32>::x() => Ok(Right),
v if v == Vector2::<i32>::y() => Ok(Down),
v if v == -Vector2::<i32>::x() => Ok(Left),
_ => Err(()),
}
}
}
/// A directed position.
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct DirectedPosition {
/// The position.
pub position: Vector2<i32>,
/// The direction.
pub direction: Direction,
}
impl DirectedPosition {
/// Creates a new `DirectedPosition`.
pub const fn new(position: Vector2<i32>, direction: Direction) -> Self {
Self {
position,
direction,
}
}
}