Simplify implementation day 8

The second part doesn't actually need to start the search at the low
points; just iterating everything and keeping track of visited spaces is
enough.

Now that the iterator is only used in part 1, we inline the iterator to
remove some overhead from the code.
This commit is contained in:
2021-12-09 12:02:07 +01:00
parent 77ce31980b
commit e0e1bc26e8

View File

@@ -1,56 +1,6 @@
use std::cmp::Reverse;
use std::io::Read;
struct LowPointsIter<'a> {
lines: &'a [&'a [u8]],
x: usize,
y: usize,
}
impl<'a> LowPointsIter<'a> {
pub fn new(lines: &'a [&'a [u8]]) -> Self {
Self { lines, x: 0, y: 0 }
}
}
impl Iterator for LowPointsIter<'_> {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
let lines = self.lines;
for y in self.y..self.lines.len() {
for x in self.x..self.lines[y].len() {
if x > 0 && lines[y][x - 1] <= lines[y][x] {
continue;
}
if x + 1 < lines[y].len() && lines[y][x + 1] <= lines[y][x] {
continue;
}
if y > 0 && lines[y - 1][x] <= lines[y][x] {
continue;
}
if y + 1 < lines.len() && lines[y + 1][x] <= lines[y][x] {
continue;
}
self.x = x + 1;
self.y = y;
return Some((x, y));
}
self.x = 0;
}
self.y = lines.len();
None
}
}
pub fn part1(input: &mut dyn Read) -> String {
let mut buffer = Vec::new();
input.read_to_end(&mut buffer).unwrap();
@@ -60,10 +10,31 @@ pub fn part1(input: &mut dyn Read) -> String {
.filter(|s| !s.is_empty())
.collect();
LowPointsIter::new(&lines)
.map(|(x, y)| 1 + (lines[y][x] - b'0') as i32)
.sum::<i32>()
.to_string()
let mut total_danger = 0;
for y in 0..lines.len() {
for x in 0..lines[y].len() {
if x > 0 && lines[y][x - 1] <= lines[y][x] {
continue;
}
if x + 1 < lines[y].len() && lines[y][x + 1] <= lines[y][x] {
continue;
}
if y > 0 && lines[y - 1][x] <= lines[y][x] {
continue;
}
if y + 1 < lines.len() && lines[y + 1][x] <= lines[y][x] {
continue;
}
total_danger += 1 + (lines[y][x] - b'0') as i32;
}
}
total_danger.to_string()
}
pub fn part2(input: &mut dyn Read) -> String {
@@ -83,41 +54,46 @@ pub fn part2(input: &mut dyn Read) -> String {
let mut sizes = Vec::with_capacity(4);
for (x, y) in LowPointsIter::new(&lines) {
todo.push((x, y));
for y in 0..lines.len() {
for x in 0..lines[0].len() {
if visited[y][x] || lines[y][x] == b'9' {
continue;
}
let mut size = 1;
visited[y][x] = true;
todo.push((x, y));
let mut size = 1;
visited[y][x] = true;
while let Some((x, y)) = todo.pop() {
let mut add = |x: usize, y: usize| {
if lines[y][x] != b'9' && !visited[y][x] {
size += 1;
visited[y][x] = true;
todo.push((x, y));
while let Some((x, y)) = todo.pop() {
let mut add = |x: usize, y: usize| {
if lines[y][x] != b'9' && !visited[y][x] {
size += 1;
visited[y][x] = true;
todo.push((x, y));
}
};
if x > 0 {
add(x - 1, y);
}
};
if x > 0 {
add(x - 1, y);
if x + 1 < lines[y].len() {
add(x + 1, y);
}
if y > 0 {
add(x, y - 1)
}
if y + 1 < lines.len() {
add(x, y + 1);
}
}
if x + 1 < lines[y].len() {
add(x + 1, y);
}
if y > 0 {
add(x, y - 1)
}
if y + 1 < lines.len() {
add(x, y + 1);
}
sizes.push(Reverse(size));
sizes.sort_unstable();
sizes.truncate(3);
}
sizes.push(Reverse(size));
sizes.sort_unstable();
sizes.truncate(3);
}
sizes.into_iter().fold(1, |a, Reverse(b)| a * b).to_string()