advent-of-code/2022/src/bin/day08.rs
2022-12-08 12:16:39 +01:00

87 lines
2.7 KiB
Rust

#![feature(test)]
extern crate test;
use itertools::Itertools;
use std::iter::repeat;
use aoc2022::{boilerplate, common::*};
const DAY: usize = 08;
type Parsed = Vec<Vec<u8>>;
fn parse_input(raw: &str) -> Parsed {
raw.lines().map(|l| l.as_bytes().to_vec()).collect()
}
fn is_visible_1d<'a>(iter: impl IntoIterator<Item = &'a u8>) -> Vec<bool> {
iter.into_iter()
.scan(0, |max, tree| {
let visible = tree > max;
*max = *tree.max(max);
Some(visible)
})
.collect()
}
fn part1(parsed: &Parsed) -> usize {
let size = parsed.len(); // input is always square
let a: Vec<_> = parsed.iter().map(is_visible_1d).collect();
let b: Vec<_> = parsed
.iter()
.map(|l| {
let mut v = is_visible_1d(l.iter().rev());
v.reverse();
v
})
.collect();
let c: Vec<_> = (0..size).map(|i| is_visible_1d(parsed.iter().map(|row| &row[i]))).collect();
let d: Vec<_> = (0..size)
.map(|i| {
let mut v = is_visible_1d(parsed.iter().rev().map(|row| &row[i]));
v.reverse();
v
})
.collect();
(0..size).flat_map(|i| repeat(i).zip(0..size)).filter(|&(i, j)| a[i][j] || b[i][j] || c[j][i] || d[j][i]).count()
}
fn part2(parsed: &Parsed) -> usize {
let size = parsed.len(); // input is always square
(1..size - 1)
.flat_map(|i| repeat(i).zip(1..size - 1))
.map(|(i, j)| {
let tree = parsed[i][j];
let mut heights = ((i + 1)..size).map(|i| parsed[i][j]).peekable();
let a = heights.peeking_take_while(|&t| t < tree).count() + heights.peek().map(|_| 1).unwrap_or(0);
let mut heights = (0..i).rev().map(|i| parsed[i][j]).peekable();
let b = heights.peeking_take_while(|&t| t < tree).count() + heights.peek().map(|_| 1).unwrap_or(0);
let mut heights = ((j + 1)..size).map(|j| parsed[i][j]).peekable();
let c = heights.peeking_take_while(|&t| t < tree).count() + heights.peek().map(|_| 1).unwrap_or(0);
let mut heights = (0..j).rev().map(|j| parsed[i][j]).peekable();
let d = heights.peeking_take_while(|&t| t < tree).count() + heights.peek().map(|_| 1).unwrap_or(0);
a * b * c * d
})
.max()
.unwrap()
}
#[cfg(test)]
const TEST_OUTPUT: &[bool] = &[true, true, false, true, false];
boilerplate! {
TEST_INPUT == "30373
25512
65332
33549
35390",
tests: {
part1: { TEST_INPUT => 21 },
part2: { TEST_INPUT => 8 },
},
unittests: {
is_visible_1d: { [1, 3, 2, 4, 2] => TEST_OUTPUT, },
},
bench1 == 1543,
bench2 == 595080,
bench_parse: Vec::len => 99,
}