day10: optimization
Part 2 doesn't actually require tracking state at all, it's enough to just follow the rules and count every DFS that lands on a target square. Part 1 optimized by only tracking which targets have been previously visited, instead of all squares. Both parts, pass position reference to recursive calls instead of by value for tiny improvement.
This commit is contained in:
parent
0716dde8b1
commit
d9d55b069f
@ -57,47 +57,38 @@ impl TrailMap {
|
|||||||
.map(|(i, _v)| self.map.coord(i as i64).unwrap())
|
.map(|(i, _v)| self.map.coord(i as i64).unwrap())
|
||||||
.collect_vec()
|
.collect_vec()
|
||||||
}
|
}
|
||||||
fn count_reachable_from(&self, pos: (i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 {
|
fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 {
|
||||||
visited.set(pos.0, pos.1, true);
|
let our_val = self.map.get(pos.0, pos.1).unwrap();
|
||||||
|
if our_val == needle && visited.get(pos.0, pos.1) == Some(false) {
|
||||||
|
visited.set(pos.0, pos.1, true);
|
||||||
|
return 1;
|
||||||
|
} else if our_val == needle {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// adjacents that are +1
|
||||||
|
[(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
||||||
|
.iter()
|
||||||
|
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
||||||
|
.map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position
|
||||||
|
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
||||||
|
.map(|(pos, _)| pos) // discard the value
|
||||||
|
.map(|pos| self.count_reachable_from(&pos, needle, visited))
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 {
|
||||||
let our_val = self.map.get(pos.0, pos.1).unwrap();
|
let our_val = self.map.get(pos.0, pos.1).unwrap();
|
||||||
if our_val == needle {
|
if our_val == needle {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// adjacents that are +1
|
[(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
||||||
let valid_moves = [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
||||||
.filter(|(x, y)| visited.get(*x, *y) == Some(false)) // skip already visited targets
|
|
||||||
.map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position
|
.map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position
|
||||||
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
||||||
.map(|(pos, _)| pos) // discard the value
|
.map(|(pos, _)| pos) // discard the value
|
||||||
.collect_vec(); // need to collect since the next map will also require access to `visited`
|
.map(|mov| self.count_paths_to(&mov, needle))
|
||||||
|
.sum::<u64>() as u64
|
||||||
valid_moves
|
|
||||||
.iter()
|
|
||||||
.map(|pos| self.count_reachable_from(*pos, needle, visited))
|
|
||||||
.sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paths_to(&self, pos: (i64, i64), needle: u8, mut path: Vec<(i64, i64)>) -> Vec<Vec<(i64, i64)>> {
|
|
||||||
path.push(pos);
|
|
||||||
let our_val = self.map.get(pos.0, pos.1).unwrap();
|
|
||||||
if our_val == needle {
|
|
||||||
return vec![path];
|
|
||||||
}
|
|
||||||
let valid_moves = [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
|
||||||
.iter()
|
|
||||||
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
|
||||||
.filter(|pos| !path.contains(pos)) // skip already visited targets
|
|
||||||
.map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position
|
|
||||||
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
|
||||||
.map(|(pos, _)| pos) // discard the value
|
|
||||||
.collect_vec(); // need to collect since the next map will also require access to `visited`
|
|
||||||
|
|
||||||
valid_moves
|
|
||||||
.iter()
|
|
||||||
.flat_map(|mov| self.paths_to(*mov, needle, path.clone()))
|
|
||||||
.collect_vec()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +101,7 @@ fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|pos| {
|
.map(|pos| {
|
||||||
let mut visited = Grid::with_shape(map.map.width(), map.map.height(), false);
|
let mut visited = Grid::with_shape(map.map.width(), map.map.height(), false);
|
||||||
map.count_reachable_from(*pos, b'9', &mut visited)
|
map.count_reachable_from(pos, b'9', &mut visited)
|
||||||
})
|
})
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
@ -121,8 +112,8 @@ fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
|||||||
|
|
||||||
map.trailheads()
|
map.trailheads()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|pos| map.paths_to(*pos, b'9', Vec::new()))
|
.map(|pos| map.count_paths_to(pos, b'9'))
|
||||||
.count() as u64
|
.sum::<u64>() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user