Skip to content

Commit 7d62527

Browse files
committed
Optimized the Grid entries function quite a lot
1 parent 71b7775 commit 7d62527

File tree

2 files changed

+76
-17
lines changed

2 files changed

+76
-17
lines changed

2022/src/bin/day23.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use advent_lib::direction::Direction;
44
use advent_lib::geometry::{point2, vector2, Vector};
55
use advent_lib::{
6-
direction::CardinalDirection,
76
grid::{Grid, Location},
87
*,
98
};
@@ -39,10 +38,10 @@ const DIRECTIONS: [(Direction, [usize; 3]); 4] = [
3938
(Direction::East, [1, 2, 3]),
4039
];
4140

42-
fn find_possible_move(round: usize, has_elfs: [bool; 8]) -> Option<Direction> {
41+
fn find_possible_move(round: usize, has_elfs: [&Ground; 8]) -> Option<Direction> {
4342
for ix in 0..4 {
4443
let (dir, ixs) = DIRECTIONS[(round + ix) % 4];
45-
if ixs.iter().all(|&ix| !has_elfs[ix]) {
44+
if ixs.iter().all(|&ix| has_elfs[ix] == &Ground::Empty) {
4645
return Some(dir);
4746
}
4847
}
@@ -52,16 +51,16 @@ fn find_possible_move(round: usize, has_elfs: [bool; 8]) -> Option<Direction> {
5251
fn step(elfs: &mut Elfs, round: usize) -> bool {
5352
let mut proposals = Vec::<(Location, Location)>::with_capacity(elfs.len());
5453
let mut proposal_count = FxHashMap::with_capacity_and_hasher(elfs.len(), Default::default());
55-
elfs.entries().filter(|&(_, g)| g == &Ground::Elf).for_each(|(loc, _)| {
56-
let has_elfs = CardinalDirection::ALL.map(|dir| elfs.get(loc + dir) == Some(&Ground::Elf));
57-
if has_elfs.iter().any(|&has_elf| has_elf) {
58-
if let Some(dir) = find_possible_move(round, has_elfs) {
54+
for (loc, _) in elfs.entries().filter(|&(_, g)| g == &Ground::Elf) {
55+
let neighbours = elfs.cardinal_neighbours(loc).unwrap();
56+
if neighbours.contains(&&Ground::Elf) {
57+
if let Some(dir) = find_possible_move(round, neighbours) {
5958
let target = loc + dir;
6059
proposals.push((loc, target));
6160
*proposal_count.entry(target).or_default() += 1;
6261
}
6362
}
64-
});
63+
}
6564

6665
let mut some_change = false;
6766
for &(current, target) in proposals.iter() {
@@ -126,4 +125,4 @@ fn calculate_part2(elfs: &Elfs) -> usize {
126125

127126
day_main!(prepare => calculate_part1, calculate_part2);
128127
day_test!(23, example => 110, 20 ; crate::prepare );
129-
day_test!(23 => 3762 ; crate::prepare ); // Part 2 is 997 but takes 5 seconds in test mode
128+
day_test!(23 => 3762, 997 ; crate::prepare );

shared/src/grid.rs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,37 @@ impl<T> Grid<T> {
132132
}
133133
}
134134

135+
pub fn cardinal_neighbours(&self, location: Location) -> Option<[&T; 8]>
136+
where
137+
T: Default + Copy,
138+
{
139+
// Check boundaries, we don't support fetching the neighbours at the edge
140+
if location.x() <= 0
141+
|| location.x() >= self.width()
142+
|| location.y() <= 0
143+
|| location.y() >= self.height()
144+
{
145+
return None;
146+
}
147+
148+
let ix = (location.x() + location.y() * self.width()) as usize;
149+
let y_step = self.width() as usize;
150+
151+
// We've checked the bounds
152+
unsafe {
153+
Some([
154+
self.items.get_unchecked(ix - y_step),
155+
self.items.get_unchecked(ix - y_step + 1),
156+
self.items.get_unchecked(ix + 1),
157+
self.items.get_unchecked(ix + y_step + 1),
158+
self.items.get_unchecked(ix + y_step),
159+
self.items.get_unchecked(ix + y_step - 1),
160+
self.items.get_unchecked(ix - 1),
161+
self.items.get_unchecked(ix - y_step - 1),
162+
])
163+
}
164+
}
165+
135166
pub fn get(&self, location: Location) -> Option<&T> {
136167
let ix = self.index_from_location(location)?;
137168
self.items.get(ix)
@@ -172,17 +203,12 @@ impl<T> Grid<T> {
172203
}
173204

174205
pub fn entries(&self) -> impl Iterator<Item = (Location, &T)> {
175-
self.items
176-
.iter()
177-
.enumerate()
178-
.map(|(index, value)| ((self.size, index).into(), value))
206+
Indexed::new(self.items.iter(), self.width())
179207
}
180208

181209
pub fn entries_mut(&mut self) -> impl Iterator<Item = (Location, &mut T)> {
182-
self.items
183-
.iter_mut()
184-
.enumerate()
185-
.map(|(index, value)| ((self.size, index).into(), value))
210+
let width = self.width();
211+
Indexed::new(self.items.iter_mut(), width)
186212
}
187213

188214
pub fn values(&self) -> impl Iterator<Item = &T> { self.items.iter() }
@@ -658,3 +684,37 @@ mod tests {
658684
);
659685
}
660686
}
687+
688+
#[derive(Clone, Debug)]
689+
pub struct Indexed<I> {
690+
iter: I,
691+
x: i32,
692+
y: i32,
693+
width: i32,
694+
}
695+
696+
impl<I> Indexed<I> {
697+
fn new(iter: I, width: i32) -> Indexed<I> { Indexed { iter, x: 0, y: 0, width } }
698+
}
699+
700+
impl<I> Iterator for Indexed<I>
701+
where
702+
I: Iterator,
703+
{
704+
type Item = (Location, <I as Iterator>::Item);
705+
706+
#[inline]
707+
fn next(&mut self) -> Option<Self::Item> {
708+
let item = self.iter.next()?;
709+
let location = point2(self.x, self.y);
710+
self.x += 1;
711+
if self.x >= self.width {
712+
self.x = 0;
713+
self.y += 1;
714+
}
715+
Some((location, item))
716+
}
717+
718+
#[inline]
719+
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
720+
}

0 commit comments

Comments
 (0)