1use std::iter::FusedIterator;
2
3use screeps::{RoomCoordinate, RoomXY};
4
5use crate::room_coordinate::{range_exclusive, range_inclusive};
6
7#[derive(Debug, Clone)]
10struct PairIter {
11 b_min: RoomCoordinate,
13 b_max: RoomCoordinate,
14 forward: (RoomCoordinate, RoomCoordinate),
16 backward: (RoomCoordinate, RoomCoordinate),
17 done: bool,
18}
19
20impl PairIter {
21 fn new(min: (RoomCoordinate, RoomCoordinate), max: (RoomCoordinate, RoomCoordinate)) -> Self {
22 Self {
23 b_min: min.1,
24 b_max: max.1,
25 forward: min,
26 backward: max,
27 done: max.0 < min.0 || max.1 < min.1,
30 }
31 }
32}
33
34impl Iterator for PairIter {
35 type Item = (RoomCoordinate, RoomCoordinate);
36
37 fn next(&mut self) -> Option<Self::Item> {
38 if self.done {
39 return None;
40 }
41
42 let res = Some(self.forward);
43
44 if self.forward == self.backward {
45 self.done = true;
46 } else if self.forward.1 == self.b_max {
47 self.forward = (
50 unsafe { RoomCoordinate::unchecked_new(self.forward.0.u8() + 1) },
51 self.b_min,
52 );
53 } else {
54 self.forward.1 = unsafe { RoomCoordinate::unchecked_new(self.forward.1.u8() + 1) };
56 }
57
58 res
59 }
60
61 fn size_hint(&self) -> (usize, Option<usize>) {
62 let len = self.len();
63 (len, Some(len))
64 }
65
66 fn fold<B, F>(self, init: B, mut f: F) -> B
67 where
68 Self: Sized,
69 F: FnMut(B, Self::Item) -> B,
70 {
71 if self.done {
72 return init;
73 }
74
75 #[cold]
76 fn cold_call<B>(
77 this: PairIter,
78 init: B,
79 mut f: impl FnMut(B, <PairIter as Iterator>::Item) -> B,
80 ) -> B {
81 if this.forward.0 == this.backward.0 {
82 return range_inclusive(this.forward.1, this.backward.1)
83 .map(|b| (this.forward.0, b))
84 .fold(init, f);
85 }
86
87 let forward_partial_acc = range_inclusive(this.forward.1, this.b_max)
88 .map(|b| (this.forward.0, b))
89 .fold(init, &mut f);
90
91 let middle_partials_acc = range_exclusive(this.forward.0, this.backward.0).fold(
92 forward_partial_acc,
93 |inner_acc, a| {
94 range_inclusive(this.b_min, this.b_max)
95 .map(|b| (a, b))
96 .fold(inner_acc, &mut f)
97 },
98 );
99
100 range_inclusive(this.b_min, this.backward.1)
101 .map(|b| (this.backward.0, b))
102 .fold(middle_partials_acc, f)
103 }
104
105 if self.forward.1 == self.b_min && self.backward.1 == self.b_max {
106 range_inclusive(self.forward.0, self.backward.0).fold(init, |acc, a| {
107 range_inclusive(self.b_min, self.b_max)
108 .map(|b| (a, b))
109 .fold(acc, &mut f)
110 })
111 } else {
112 cold_call(self, init, f)
113 }
114 }
115}
116
117impl FusedIterator for PairIter {}
118
119impl ExactSizeIterator for PairIter {
120 fn len(&self) -> usize {
121 if self.done {
122 return 0;
123 }
124
125 let forward = (self.forward.0.u8(), self.forward.1.u8());
126 let backward = (self.backward.0.u8(), self.backward.1.u8());
127
128 if forward.0 == backward.0 {
129 return (backward.1 - forward.1 + 1) as usize;
130 }
131
132 let full_ranges = (backward.0 - forward.0 - 1) as usize;
133 full_ranges * (self.b_max.u8() - self.b_min.u8() + 1) as usize
134 + (self.b_max.u8() - forward.1 + 1) as usize
135 + (backward.1 - self.b_min.u8() + 1) as usize
136 }
137}
138
139impl DoubleEndedIterator for PairIter {
140 fn next_back(&mut self) -> Option<Self::Item> {
141 if self.done {
142 return None;
143 }
144
145 let res = Some(self.backward);
146
147 if self.backward == self.forward {
148 self.done = true;
149 } else if self.backward.1 == self.b_min {
150 self.backward = (
153 unsafe { RoomCoordinate::unchecked_new(self.backward.0.u8() - 1) },
154 self.b_max,
155 );
156 } else {
157 self.backward.1 = unsafe { RoomCoordinate::unchecked_new(self.backward.1.u8() - 1) };
159 }
160
161 res
162 }
163
164 fn rfold<B, F>(self, init: B, mut f: F) -> B
165 where
166 Self: Sized,
167 F: FnMut(B, Self::Item) -> B,
168 {
169 if self.done {
170 return init;
171 }
172
173 #[cold]
174 fn cold_call<B>(
175 this: PairIter,
176 init: B,
177 mut f: impl FnMut(B, <PairIter as Iterator>::Item) -> B,
178 ) -> B {
179 if this.forward.0 == this.backward.0 {
180 return range_inclusive(this.forward.1, this.backward.1)
181 .map(|b| (this.forward.0, b))
182 .rfold(init, f);
183 }
184
185 let backward_partial_acc = range_inclusive(this.b_min, this.backward.1)
186 .map(|b| (this.backward.0, b))
187 .rfold(init, &mut f);
188
189 let middle_partials_acc = range_exclusive(this.forward.0, this.backward.0).rfold(
190 backward_partial_acc,
191 |inner_acc, a| {
192 range_inclusive(this.b_min, this.b_max)
193 .map(|b| (a, b))
194 .rfold(inner_acc, &mut f)
195 },
196 );
197
198 range_inclusive(this.forward.1, this.b_max)
199 .map(|b| (this.forward.0, b))
200 .rfold(middle_partials_acc, f)
201 }
202
203 if self.forward.1 == self.b_min && self.backward.1 == self.b_max {
204 range_inclusive(self.forward.0, self.backward.0).rfold(init, |acc, a| {
205 range_inclusive(self.b_min, self.b_max)
206 .map(|b| (a, b))
207 .rfold(acc, &mut f)
208 })
209 } else {
210 cold_call(self, init, f)
211 }
212 }
213}
214
215#[derive(Clone, Copy, PartialEq, Eq, Debug)]
236pub enum Order {
237 XMajor,
238 YMajor,
239}
240
241#[derive(Debug, Clone)]
243pub struct GridIter {
244 inner: PairIter,
245 order: Order,
246}
247
248impl GridIter {
249 pub fn new(top_left: RoomXY, bottom_right: RoomXY, order: Order) -> Self {
279 let top = top_left.y;
280 let bottom = bottom_right.y;
281 let left = top_left.x;
282 let right = bottom_right.x;
283 let (a_min, a_max, b_min, b_max) = match order {
284 Order::XMajor => (left, right, top, bottom),
285 Order::YMajor => (top, bottom, left, right),
286 };
287 Self {
288 inner: PairIter::new((a_min, b_min), (a_max, b_max)),
289 order,
290 }
291 }
292
293 fn get_xy(&self, a: RoomCoordinate, b: RoomCoordinate) -> RoomXY {
294 match self.order {
295 Order::XMajor => RoomXY { x: a, y: b },
296 Order::YMajor => RoomXY { x: b, y: a },
297 }
298 }
299}
300
301impl Iterator for GridIter {
302 type Item = RoomXY;
303
304 fn next(&mut self) -> Option<Self::Item> {
305 self.inner.next().map(|(a, b)| self.get_xy(a, b))
306 }
307
308 fn size_hint(&self) -> (usize, Option<usize>) {
309 self.inner.size_hint()
310 }
311
312 fn fold<B, F>(self, init: B, mut f: F) -> B
313 where
314 Self: Sized,
315 F: FnMut(B, Self::Item) -> B,
316 {
317 match self.order {
318 Order::XMajor => self
319 .inner
320 .fold(init, move |acc, (x, y)| f(acc, RoomXY { x, y })),
321 Order::YMajor => self
322 .inner
323 .fold(init, move |acc, (y, x)| f(acc, RoomXY { x, y })),
324 }
325 }
326}
327
328impl FusedIterator for GridIter {}
329
330impl ExactSizeIterator for GridIter {
331 fn len(&self) -> usize {
332 self.inner.len()
333 }
334}
335
336impl DoubleEndedIterator for GridIter {
337 fn next_back(&mut self) -> Option<Self::Item> {
338 self.inner.next_back().map(|(a, b)| self.get_xy(a, b))
339 }
340
341 fn rfold<B, F>(self, init: B, mut f: F) -> B
342 where
343 Self: Sized,
344 F: FnMut(B, Self::Item) -> B,
345 {
346 match self.order {
347 Order::XMajor => self
348 .inner
349 .rfold(init, move |acc, (x, y)| f(acc, RoomXY { x, y })),
350 Order::YMajor => self
351 .inner
352 .rfold(init, move |acc, (y, x)| f(acc, RoomXY { x, y })),
353 }
354 }
355}
356
357pub fn chebyshev_range_iter(centre: RoomXY, radius: u8) -> impl Iterator<Item = RoomXY> {
368 let signed_radius = radius.min(50) as i8;
369 let top_left = RoomXY {
370 x: centre.x.saturating_add(-signed_radius),
371 y: centre.y.saturating_add(-signed_radius),
372 };
373 let bottom_right = RoomXY {
374 x: centre.x.saturating_add(signed_radius),
375 y: centre.y.saturating_add(signed_radius),
376 };
377 GridIter::new(top_left, bottom_right, Order::YMajor)
378}
379
380pub fn manhattan_range_iter(centre: RoomXY, radius: u8) -> impl Iterator<Item = RoomXY> {
391 let signed_radius = radius.min(100) as i8;
392 let min_x = centre.x.saturating_add(-signed_radius);
393 let min_x_offset = min_x.u8() as i8 - centre.x.u8() as i8;
394 let max_x = centre.x.saturating_add(signed_radius);
395 let max_x_offset = max_x.u8() as i8 - centre.x.u8() as i8;
396 range_inclusive(min_x, max_x)
397 .zip(min_x_offset..=max_x_offset)
398 .flat_map(move |(x, x_offset)| {
399 let y_radius = signed_radius - x_offset.abs();
400 let min_y = centre.y.saturating_add(-y_radius);
401 let max_y = centre.y.saturating_add(y_radius);
402 range_inclusive(min_y, max_y).map(move |y| RoomXY { x, y })
403 })
404}
405
406#[cfg(test)]
407mod test {
408 use super::*;
409
410 use std::collections::HashSet;
411
412 fn make_xy(x: u8, y: u8) -> RoomXY {
413 RoomXY {
414 x: RoomCoordinate::new(x).unwrap(),
415 y: RoomCoordinate::new(y).unwrap(),
416 }
417 }
418
419 #[test]
420 fn test_chebyshev_basic() {
421 let expected: HashSet<_> = [
422 make_xy(10, 10),
423 make_xy(9, 10),
424 make_xy(9, 9),
425 make_xy(9, 11),
426 make_xy(10, 9),
427 make_xy(10, 11),
428 make_xy(11, 9),
429 make_xy(11, 10),
430 make_xy(11, 11),
431 ]
432 .into_iter()
433 .collect();
434 let actual: HashSet<_> = chebyshev_range_iter(make_xy(10, 10), 1).collect();
435 assert_eq!(expected, actual);
436 }
437
438 #[test]
439 fn test_chebyshev_0_radius() {
440 let expected: HashSet<_> = [make_xy(11, 11)].into_iter().collect();
441 let actual: HashSet<_> = chebyshev_range_iter(make_xy(11, 11), 0).collect();
442 assert_eq!(expected, actual);
443 }
444
445 #[test]
446 fn test_chebyshev_boundary() {
447 let expected: HashSet<_> = [
448 make_xy(0, 0),
449 make_xy(0, 1),
450 make_xy(0, 2),
451 make_xy(1, 0),
452 make_xy(1, 1),
453 make_xy(1, 2),
454 make_xy(2, 0),
455 make_xy(2, 1),
456 make_xy(2, 2),
457 ]
458 .into_iter()
459 .collect();
460 let actual: HashSet<_> = chebyshev_range_iter(make_xy(0, 0), 2).collect();
461 assert_eq!(expected, actual);
462 }
463
464 #[test]
465 fn test_manhattan_basic() {
466 let expected: HashSet<_> = [
467 make_xy(9, 10),
468 make_xy(10, 10),
469 make_xy(11, 10),
470 make_xy(10, 9),
471 make_xy(10, 11),
472 ]
473 .into_iter()
474 .collect();
475 let actual: HashSet<_> = manhattan_range_iter(make_xy(10, 10), 1).collect();
476 assert_eq!(expected, actual);
477 }
478
479 #[test]
480 fn test_manhattan_0_radius() {
481 let expected: HashSet<_> = [make_xy(10, 10)].into_iter().collect();
482 let actual: HashSet<_> = manhattan_range_iter(make_xy(10, 10), 0).collect();
483 assert_eq!(expected, actual);
484 }
485
486 #[test]
487 fn test_manhattan_boundary() {
488 let expected: HashSet<_> = [
489 make_xy(0, 1),
490 make_xy(0, 2),
491 make_xy(0, 3),
492 make_xy(1, 0),
493 make_xy(1, 1),
494 make_xy(1, 2),
495 make_xy(1, 3),
496 make_xy(1, 4),
497 make_xy(2, 1),
498 make_xy(2, 2),
499 make_xy(2, 3),
500 make_xy(3, 2),
501 ]
502 .into_iter()
503 .collect();
504 let actual: HashSet<_> = manhattan_range_iter(make_xy(1, 2), 2).collect();
505 assert_eq!(expected, actual);
506 }
507
508 #[test]
509 fn test_grid_iter_basic() {
510 let mut iter = GridIter::new(make_xy(0, 0), make_xy(1, 1), Order::XMajor);
511 assert_eq!(make_xy(0, 0), iter.next().unwrap());
512 assert_eq!(make_xy(0, 1), iter.next().unwrap());
513 assert_eq!(make_xy(1, 0), iter.next().unwrap());
514 assert_eq!(make_xy(1, 1), iter.next().unwrap());
515 assert_eq!(None, iter.next());
516
517 iter = GridIter::new(make_xy(0, 0), make_xy(1, 1), Order::YMajor);
518 assert_eq!(make_xy(0, 0), iter.next().unwrap());
519 assert_eq!(make_xy(1, 0), iter.next().unwrap());
520 assert_eq!(make_xy(0, 1), iter.next().unwrap());
521 assert_eq!(make_xy(1, 1), iter.next().unwrap());
522 assert_eq!(None, iter.next());
523 }
524
525 #[test]
526 fn test_grid_iter_reverse() {
527 let mut iter = GridIter::new(make_xy(0, 0), make_xy(1, 1), Order::XMajor);
528 assert_eq!(make_xy(1, 1), iter.next_back().unwrap());
529 assert_eq!(make_xy(1, 0), iter.next_back().unwrap());
530 assert_eq!(make_xy(0, 1), iter.next_back().unwrap());
531 assert_eq!(make_xy(0, 0), iter.next_back().unwrap());
532 assert_eq!(None, iter.next_back());
533
534 iter = GridIter::new(make_xy(0, 0), make_xy(1, 1), Order::YMajor);
535 assert_eq!(make_xy(1, 1), iter.next_back().unwrap());
536 assert_eq!(make_xy(0, 1), iter.next_back().unwrap());
537 assert_eq!(make_xy(1, 0), iter.next_back().unwrap());
538 assert_eq!(make_xy(0, 0), iter.next_back().unwrap());
539 assert_eq!(None, iter.next_back());
540 }
541
542 #[test]
543 fn test_grid_iter_len() {
544 let mut iter = GridIter::new(make_xy(0, 0), make_xy(2, 1), Order::XMajor);
545 for i in (1..=6).rev() {
546 assert_eq!(iter.len(), i);
547 iter.next().unwrap();
548 }
549 assert_eq!(iter.len(), 0);
550 assert_eq!(iter.next(), None);
551
552 iter = GridIter::new(make_xy(0, 0), make_xy(2, 1), Order::XMajor);
553 for i in (1..=6).rev() {
554 assert_eq!(iter.len(), i);
555 iter.next_back().unwrap();
556 }
557 assert_eq!(iter.len(), 0);
558 assert_eq!(iter.next_back(), None);
559 }
560
561 #[test]
562 fn test_grid_iter_bad_corners() {
563 let mut iter = GridIter::new(make_xy(10, 10), make_xy(10, 9), Order::XMajor);
564 assert_eq!(iter.len(), 0);
565 assert_eq!(iter.next(), None);
566
567 iter = GridIter::new(make_xy(10, 10), make_xy(9, 10), Order::XMajor);
568 assert_eq!(iter.len(), 0);
569 assert_eq!(iter.next(), None);
570
571 iter = GridIter::new(make_xy(10, 10), make_xy(9, 9), Order::XMajor);
572 assert_eq!(iter.len(), 0);
573 assert_eq!(iter.next(), None);
574 }
575
576 #[test]
577 fn test_grid_iter_single_square() {
578 let coords: Vec<_> =
579 GridIter::new(make_xy(25, 25), make_xy(25, 25), Order::XMajor).collect();
580 assert_eq!(coords, [make_xy(25, 25)]);
581 }
582
583 #[test]
584 fn test_grid_iter_mixing_forward_and_back() {
585 let mut iter = GridIter::new(make_xy(0, 0), make_xy(2, 1), Order::XMajor);
586 assert_eq!(iter.next().unwrap(), make_xy(0, 0));
587 assert_eq!(iter.next_back().unwrap(), make_xy(2, 1));
588 assert_eq!(iter.next_back().unwrap(), make_xy(2, 0));
589 assert_eq!(iter.next().unwrap(), make_xy(0, 1));
590 assert_eq!(iter.next().unwrap(), make_xy(1, 0));
591 assert_eq!(iter.next_back().unwrap(), make_xy(1, 1));
592 assert_eq!(iter.next_back(), None);
593 assert_eq!(iter.next(), None);
594 }
595
596 #[test]
597 fn test_grid_iter_fold() {
598 let expected = [
599 make_xy(0, 0),
600 make_xy(0, 1),
601 make_xy(0, 2),
602 make_xy(1, 0),
603 make_xy(1, 1),
604 make_xy(1, 2),
605 ];
606 let actual = GridIter::new(make_xy(0, 0), make_xy(1, 2), Order::XMajor).fold(
607 Vec::new(),
608 |mut v, xy| {
609 v.push(xy);
610 v
611 },
612 );
613 assert_eq!(expected.as_slice(), actual);
614 }
615
616 #[test]
617 fn test_grid_iter_rfold() {
618 let expected = [
619 make_xy(1, 2),
620 make_xy(0, 2),
621 make_xy(1, 1),
622 make_xy(0, 1),
623 make_xy(1, 0),
624 make_xy(0, 0),
625 ];
626 let actual = GridIter::new(make_xy(0, 0), make_xy(1, 2), Order::YMajor).rfold(
627 Vec::new(),
628 |mut v, xy| {
629 v.push(xy);
630 v
631 },
632 );
633 assert_eq!(expected.as_slice(), actual);
634 }
635
636 #[test]
637 fn test_grid_iter_single_row_fold() {
638 let mut base_iter = GridIter::new(make_xy(0, 0), make_xy(0, 10), Order::XMajor);
639 base_iter.next().unwrap();
640 base_iter.next_back().unwrap();
641 let expected: Vec<_> = (1..=9).map(|y| make_xy(0, y)).collect();
642 let actual = base_iter.clone().fold(Vec::new(), |mut v, xy| {
643 v.push(xy);
644 v
645 });
646 assert_eq!(expected, actual);
647
648 let expected: Vec<_> = (1..=9).rev().map(|y| make_xy(0, y)).collect();
649 let actual = base_iter.rfold(Vec::new(), |mut v, xy| {
650 v.push(xy);
651 v
652 });
653 assert_eq!(expected, actual);
654 }
655
656 #[test]
657 fn test_grid_iter_fold_general_case() {
658 let mut base_iter = GridIter::new(make_xy(0, 0), make_xy(3, 1), Order::XMajor);
659 base_iter.next().unwrap();
660 base_iter.next_back().unwrap();
661 let mut expected = [
662 make_xy(0, 1),
663 make_xy(1, 0),
664 make_xy(1, 1),
665 make_xy(2, 0),
666 make_xy(2, 1),
667 make_xy(3, 0),
668 ];
669 let actual = base_iter.clone().fold(Vec::new(), |mut v, xy| {
670 v.push(xy);
671 v
672 });
673 assert_eq!(expected.as_slice(), actual);
674
675 expected.reverse();
676 let actual = base_iter.rfold(Vec::new(), |mut v, xy| {
677 v.push(xy);
678 v
679 });
680 assert_eq!(expected.as_slice(), actual);
681 }
682}