|
@@ -0,0 +1,122 @@
|
|
|
|
+fn or_bitrow(first: &Vec<bool>, second: &Vec<bool>) -> Vec<bool> {
|
|
|
|
+ first.iter().zip(second.iter().rev()).map(|(l, r)| *l || *r).collect()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn look_down_treeline(line: &Vec<u32>) -> Vec<bool> {
|
|
|
|
+ let (ltr_viz, _ltr_biggest) = line.iter().skip(1).fold((vec![true], line[0]), |mut acc, el| if *el > acc.1 { acc.0.push(true); (acc.0, *el)} else {acc.0.push(false); (acc.0, acc.1)});
|
|
|
|
+ // right to left
|
|
|
|
+ let (rtl_viz, _rtl_biggest) = line.iter().rev().skip(1).fold((vec![true], *(line.last().unwrap())), |mut acc, el| if *el > acc.1 { acc.0.push(true); (acc.0, *el)} else {acc.0.push(false); (acc.0, acc.1)});
|
|
|
|
+
|
|
|
|
+ let thing = or_bitrow(<r_viz, &rtl_viz);
|
|
|
|
+ thing
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn part_one(input: &str) -> Option<u32> {
|
|
|
|
+ let trees: Vec<Vec<u32>> =
|
|
|
|
+ input.lines()
|
|
|
|
+ .map(|line| line.chars()
|
|
|
|
+ .map(|c| c.to_digit(10).unwrap()).collect()
|
|
|
|
+ ).collect();
|
|
|
|
+
|
|
|
|
+ let mut bitfield: Vec<Vec<bool>> = (0..trees.len()).map(|_| (0..trees[0].len()).map(|_| false).collect()).collect();
|
|
|
|
+
|
|
|
|
+ for (row_idx, row) in (&trees).iter().enumerate() {
|
|
|
|
+ let mut rowtreeline = or_bitrow(&bitfield[row_idx], &look_down_treeline(row));
|
|
|
|
+ // dunno why the rows are reversed, but they are
|
|
|
|
+ rowtreeline.reverse();
|
|
|
|
+ bitfield[row_idx] = rowtreeline;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for col in 0..trees[0].len() {
|
|
|
|
+ let column: Vec<u32> = trees.iter().map(|row| *(row.get(col).unwrap())).collect();
|
|
|
|
+ let seen_trees = look_down_treeline(&column);
|
|
|
|
+
|
|
|
|
+ for row_idx in 0..trees.len() {
|
|
|
|
+ bitfield[row_idx][col] |= seen_trees[row_idx];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let visible = bitfield.iter().fold(0, |acc, row| acc + row.iter().fold(0, |acc, tree| if *tree { acc + 1} else { acc}));
|
|
|
|
+ Some(visible)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn look_down_single_row<'a, I>(trees: I, height: u32) -> u32 where I: Iterator<Item=&'a u32> {
|
|
|
|
+ let mut seen = 0;
|
|
|
|
+ for tree in trees {
|
|
|
|
+ seen += 1;
|
|
|
|
+ if *tree >= height {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ seen
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn get_scenic_score_for_tree(row: usize, col: usize, trees: &Vec<Vec<u32>>) -> u32 {
|
|
|
|
+ let our_tree = trees[row][col];
|
|
|
|
+ let mut our_score = 1;
|
|
|
|
+ let rowlen = trees[0].len();
|
|
|
|
+
|
|
|
|
+ if col < rowlen - 1 {
|
|
|
|
+ let right = &trees[row][col+1..rowlen];
|
|
|
|
+ our_score *= look_down_single_row(right.iter(), our_tree);
|
|
|
|
+ } else { return 0 }
|
|
|
|
+ if 0 < col {
|
|
|
|
+ let left = &trees[row][0..col];
|
|
|
|
+ our_score *= look_down_single_row(left.iter().rev(), our_tree);
|
|
|
|
+ } else { return 0}
|
|
|
|
+ if row > 0 {
|
|
|
|
+ let up: Vec<u32> = (0..row).map(|idx| trees[idx][col]).collect();
|
|
|
|
+ our_score *= look_down_single_row(up.iter().rev(), our_tree);
|
|
|
|
+ } else { return 0}
|
|
|
|
+ if row < trees.len() - 1 {
|
|
|
|
+ let down: Vec<u32> = (row+1..rowlen).map(|idx| trees[idx][col]).collect();
|
|
|
|
+ our_score *= look_down_single_row(down.iter(), our_tree);
|
|
|
|
+ } else { return 0}
|
|
|
|
+ our_score
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn part_two(input: &str) -> Option<u32> {
|
|
|
|
+ let trees: Vec<Vec<u32>> =
|
|
|
|
+ input.lines()
|
|
|
|
+ .map(|line| line.chars()
|
|
|
|
+ .map(|c| c.to_digit(10).unwrap()).collect()
|
|
|
|
+ ).collect();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let mut best: u32 = 0;
|
|
|
|
+
|
|
|
|
+ for row_idx in 0..trees.len() {
|
|
|
|
+ for col_idx in 0..trees[0].len() {
|
|
|
|
+ let this_tree = get_scenic_score_for_tree(row_idx, col_idx, &trees);
|
|
|
|
+ if this_tree > best {
|
|
|
|
+ best = this_tree;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Some(best)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn main() {
|
|
|
|
+ let input = &advent_of_code::read_file("inputs", 8);
|
|
|
|
+ advent_of_code::solve!(1, part_one, input);
|
|
|
|
+ advent_of_code::solve!(2, part_two, input);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(test)]
|
|
|
|
+mod tests {
|
|
|
|
+ use super::*;
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn test_part_one() {
|
|
|
|
+ let input = advent_of_code::read_file("examples", 8);
|
|
|
|
+ assert_eq!(part_one(&input), Some(21));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn test_part_two() {
|
|
|
|
+ let input = advent_of_code::read_file("examples", 8);
|
|
|
|
+ assert_eq!(part_two(&input), Some(8));
|
|
|
|
+ }
|
|
|
|
+}
|