less code duplication
This commit is contained in:
parent
f71090babf
commit
9e3e03bcd3
|
@ -24,7 +24,7 @@ fn parse_input(raw: &str) -> Node<'_> {
|
|||
let mut fs = Node::Dir("/", Vec::new(), 0);
|
||||
for cmd in raw.trim_start_matches("$ cd /\n$ ").split("\n$ ") {
|
||||
match cmd.bytes().next() {
|
||||
Some(b'c') => if cmd.ends_with(".") { drop(pwd.pop()) } else { pwd.push(&cmd[3..]) },
|
||||
Some(b'c') => if cmd.ends_with('.') { pwd.pop(); } else { pwd.push(&cmd[3..]) },
|
||||
// ls
|
||||
_ if let Some(Node::Dir(_, contents, _)) = pwd.iter().try_fold(&mut fs, |cd, p| cd.subdir_mut(p)) => contents.extend(
|
||||
cmd.lines()
|
||||
|
@ -45,7 +45,7 @@ fn compute_dir_sizes(node: &mut Node<'_>) -> usize {
|
|||
match node {
|
||||
Node::File(s) => *s,
|
||||
Node::Dir(_, c, size) => {
|
||||
*size = c.iter_mut().map(|d| compute_dir_sizes(d)).sum();
|
||||
*size = c.iter_mut().map(compute_dir_sizes).sum();
|
||||
*size
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,43 +5,42 @@ use std::iter::repeat;
|
|||
|
||||
use aoc2022::{boilerplate, common::*};
|
||||
|
||||
const DAY: usize = 08;
|
||||
const DAY: usize = 8;
|
||||
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()
|
||||
fn is_visible_1d<'a>(iter: impl IntoIterator<Item = &'a u8>, rev: bool) -> Vec<bool> {
|
||||
let mut v: Vec<_> = iter
|
||||
.into_iter()
|
||||
.scan(0, |max, tree| {
|
||||
let visible = tree > max;
|
||||
*max = *tree.max(max);
|
||||
Some(visible)
|
||||
})
|
||||
.collect()
|
||||
.collect();
|
||||
if rev {
|
||||
v.reverse();
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn transpose<T: Copy>(v: &Vec<Vec<T>>) -> Vec<Vec<T>> {
|
||||
let len = v.len();
|
||||
let mut iters: Vec<_> = v.iter().map(|n| n.iter()).collect();
|
||||
(0..len).map(|_| iters.iter_mut().map(|i| i.next().unwrap()).copied().collect::<Vec<T>>()).collect()
|
||||
}
|
||||
|
||||
fn horizontally_visible(v: &[Vec<u8>]) -> Vec<Vec<bool>> {
|
||||
v.iter().map(|l| is_visible_1d(l, false).into_iter().zip(is_visible_1d(l.iter().rev(), true)).map(|(a, b)| a || b).collect()).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()
|
||||
let horizontal = horizontally_visible(parsed);
|
||||
let vertical = horizontally_visible(&transpose(parsed));
|
||||
(0..parsed.len()).flat_map(|i| repeat(i).zip(0..parsed.len())).filter(|&(i, j)| horizontal[i][j] || vertical[j][i]).count()
|
||||
}
|
||||
|
||||
fn part2(parsed: &Parsed) -> usize {
|
||||
|
@ -50,20 +49,22 @@ fn part2(parsed: &Parsed) -> usize {
|
|||
.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);
|
||||
let a = visible_trees(((i + 1)..size).map(|i| parsed[i][j]), tree);
|
||||
let b = visible_trees((0..i).rev().map(|i| parsed[i][j]), tree);
|
||||
let c = visible_trees(((j + 1)..size).map(|j| parsed[i][j]), tree);
|
||||
let d = visible_trees((0..j).rev().map(|j| parsed[i][j]), tree);
|
||||
a * b * c * d
|
||||
})
|
||||
.max()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[inline] // this inline actually saves ~40% runtime
|
||||
fn visible_trees(heights: impl Iterator<Item = u8>, tree: u8) -> usize {
|
||||
let mut heights = heights.peekable();
|
||||
heights.peeking_take_while(|&t| t < tree).count() + heights.peek().map(|_| 1).unwrap_or(0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
const TEST_OUTPUT: &[bool] = &[true, true, false, true, false];
|
||||
|
||||
|
@ -78,7 +79,7 @@ boilerplate! {
|
|||
part2: { TEST_INPUT => 8 },
|
||||
},
|
||||
unittests: {
|
||||
is_visible_1d: { [1, 3, 2, 4, 2] => TEST_OUTPUT, },
|
||||
is_visible_1d: { [1, 3, 2, 4, 2].iter(), false => TEST_OUTPUT, },
|
||||
},
|
||||
bench1 == 1543,
|
||||
bench2 == 595080,
|
||||
|
|
|
@ -6,7 +6,7 @@ macro_rules! boilerplate {
|
|||
$($part: ident: { $($tpi: expr => $to: expr),+$(,)? }),*$(,)?
|
||||
},
|
||||
$(unittests: {
|
||||
$($unittest: ident: { $($utpi: expr => $uto: expr),+$(,)? }),*$(,)?
|
||||
$($unittest: ident: { $($($utpi: expr),+ => $uto: expr),+$(,)? }),*$(,)?
|
||||
},)?
|
||||
bench1 == $b1: literal,
|
||||
bench2 == $b2: literal,
|
||||
|
@ -29,7 +29,7 @@ macro_rules! boilerplate {
|
|||
$($($(paste::paste! {
|
||||
#[test]
|
||||
fn [<$unittest _test_ $uto:lower>]() {
|
||||
assert_eq!($unittest(&$utpi), $uto);
|
||||
assert_eq!($unittest($($utpi),+), $uto);
|
||||
}
|
||||
})+)*)?
|
||||
$($(paste::paste! {
|
||||
|
|
Loading…
Reference in New Issue
Block a user