1use std::iter;
2
3use crate::usize_plus_i;
4
5pub trait Direction: Sized + PartialEq + Copy {
6 fn iter() -> impl Iterator<Item = Self>;
9
10 fn iter_from(initial_dir: Self) -> impl Iterator<Item = Self> {
34 let mut d = initial_dir;
35 let mut first = true;
36 iter::from_fn(move || {
37 if d == initial_dir && !first {
38 return None;
39 }
40 first = false;
41
42 let r = d;
43 d = d.rotate_right();
44
45 Some(r)
46 })
47 }
48
49 fn iter_valid_usizes_deltas(
61 curr: (usize, usize),
62 size: (usize, usize),
63 ) -> impl Iterator<Item = (usize, usize)> {
64 let mut dir_iter = Self::iter();
65 iter::from_fn(move || {
66 loop {
67 match dir_iter.next() {
68 None => return None,
69 Some(d) => {
70 let (dx, dy) = d.delta();
71 let next = (
72 i64::try_from(curr.0).unwrap() + i64::from(dx),
73 i64::try_from(curr.1).unwrap() + i64::from(dy),
74 );
75 if next.0 >= 0
76 && next.0 < i64::try_from(size.0).unwrap()
77 && next.1 >= 0
78 && next.1 < i64::try_from(size.1).unwrap()
79 {
80 return Some((
81 usize::try_from(next.0).unwrap(),
82 usize::try_from(next.1).unwrap(),
83 ));
84 }
85 }
86 }
87 }
88 })
89 }
90
91 fn delta(self) -> (i8, i8);
93
94 fn rotate_right(self) -> Self;
96
97 fn rotate_left(self) -> Self;
99
100 fn rotate_right_90(self) -> Self;
102
103 fn rotate_left_90(self) -> Self;
105
106 fn opposite(self) -> Self;
109
110 fn apply_delta_to_usizes(self, usizes: (usize, usize)) -> (usize, usize) {
122 let (d_x, d_y) = self.delta();
123 (
124 usize_plus_i(usizes.0, i64::from(d_x)),
125 usize_plus_i(usizes.1, i64::from(d_y)),
126 )
127 }
128}
129
130#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
132pub enum Dir4 {
133 Up,
134 Down,
135 Left,
136 Right,
137}
138
139impl Direction for Dir4 {
140 fn delta(self) -> (i8, i8) {
141 match self {
142 Dir4::Up => (0, -1),
143 Dir4::Down => (0, 1),
144 Dir4::Left => (-1, 0),
145 Dir4::Right => (1, 0),
146 }
147 }
148
149 fn rotate_right(self) -> Dir4 {
150 match self {
151 Dir4::Up => Dir4::Right,
152 Dir4::Down => Dir4::Left,
153 Dir4::Left => Dir4::Up,
154 Dir4::Right => Dir4::Down,
155 }
156 }
157
158 fn rotate_left(self) -> Dir4 {
159 self.rotate_right().opposite()
160 }
161
162 fn rotate_right_90(self) -> Dir4 {
163 self.rotate_right()
164 }
165
166 fn rotate_left_90(self) -> Dir4 {
167 self.rotate_left()
168 }
169
170 fn opposite(self) -> Dir4 {
171 match self {
172 Dir4::Up => Dir4::Down,
173 Dir4::Down => Dir4::Up,
174 Dir4::Left => Dir4::Right,
175 Dir4::Right => Dir4::Left,
176 }
177 }
178
179 fn iter() -> impl Iterator<Item = Dir4> {
180 Self::iter_from(Dir4::Up)
181 }
182}
183
184#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
186pub enum Dir8 {
187 Dir4(Dir4),
188 UpRight,
189 UpLeft,
190 DownRight,
191 DownLeft,
192}
193
194impl Direction for Dir8 {
195 fn delta(self) -> (i8, i8) {
196 match self {
197 Dir8::Dir4(d4) => d4.delta(),
198 Dir8::UpRight => (1, -1),
199 Dir8::UpLeft => (-1, -1),
200 Dir8::DownRight => (1, 1),
201 Dir8::DownLeft => (-1, 1),
202 }
203 }
204
205 fn rotate_right(self) -> Dir8 {
206 match self {
207 Dir8::Dir4(Dir4::Up) => Dir8::UpRight,
208 Dir8::Dir4(Dir4::Down) => Dir8::DownLeft,
209 Dir8::Dir4(Dir4::Left) => Dir8::UpLeft,
210 Dir8::Dir4(Dir4::Right) => Dir8::DownRight,
211 Dir8::UpRight => Dir8::Dir4(Dir4::Right),
212 Dir8::UpLeft => Dir8::Dir4(Dir4::Up),
213 Dir8::DownRight => Dir8::Dir4(Dir4::Down),
214 Dir8::DownLeft => Dir8::Dir4(Dir4::Left),
215 }
216 }
217
218 fn rotate_left(self) -> Dir8 {
219 match self {
220 Dir8::Dir4(Dir4::Up) => Dir8::UpLeft,
221 Dir8::Dir4(Dir4::Down) => Dir8::DownRight,
222 Dir8::Dir4(Dir4::Left) => Dir8::DownLeft,
223 Dir8::Dir4(Dir4::Right) => Dir8::UpRight,
224 Dir8::UpRight => Dir8::Dir4(Dir4::Up),
225 Dir8::UpLeft => Dir8::Dir4(Dir4::Left),
226 Dir8::DownRight => Dir8::Dir4(Dir4::Right),
227 Dir8::DownLeft => Dir8::Dir4(Dir4::Down),
228 }
229 }
230
231 fn rotate_right_90(self) -> Dir8 {
232 match self {
233 Dir8::Dir4(d4) => Dir8::Dir4(d4.rotate_right_90()),
234 Dir8::UpRight => Dir8::DownRight,
235 Dir8::UpLeft => Dir8::UpRight,
236 Dir8::DownRight => Dir8::DownLeft,
237 Dir8::DownLeft => Dir8::UpLeft,
238 }
239 }
240
241 fn rotate_left_90(self) -> Dir8 {
242 match self {
243 Dir8::Dir4(d4) => Dir8::Dir4(d4.rotate_left_90()),
244 Dir8::UpRight => Dir8::UpLeft,
245 Dir8::UpLeft => Dir8::DownLeft,
246 Dir8::DownRight => Dir8::UpRight,
247 Dir8::DownLeft => Dir8::DownRight,
248 }
249 }
250
251 fn opposite(self) -> Dir8 {
252 match self {
253 Dir8::Dir4(d4) => Dir8::Dir4(d4.opposite()),
254 Dir8::UpRight => Dir8::DownLeft,
255 Dir8::UpLeft => Dir8::DownRight,
256 Dir8::DownRight => Dir8::UpLeft,
257 Dir8::DownLeft => Dir8::UpRight,
258 }
259 }
260
261 fn iter() -> impl Iterator<Item = Dir8> {
262 Self::iter_from(Dir8::Dir4(Dir4::Up))
263 }
264}