2022-12-09 00:47:08 +00:00
|
|
|
#![allow(dead_code)]
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io;
|
|
|
|
use std::io::BufRead;
|
|
|
|
use std::path::Path;
|
|
|
|
use std::time::Instant;
|
|
|
|
|
2022-12-09 01:29:02 +00:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
struct Tree(i8, bool); // height, visible from outside
|
2022-12-09 00:47:08 +00:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let now = Instant::now();
|
|
|
|
part_one();
|
|
|
|
let part_one_duration = now.elapsed();
|
|
|
|
part_two();
|
|
|
|
let part_two_duration = now.elapsed();
|
|
|
|
println!(
|
|
|
|
"p1: {}ms, p2: {}ms",
|
|
|
|
part_one_duration.as_millis(),
|
|
|
|
(part_two_duration - part_one_duration).as_millis()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
|
|
|
where
|
|
|
|
P: AsRef<Path>,
|
|
|
|
{
|
|
|
|
// note that this discards a final newline
|
|
|
|
let file = File::open(filename)?;
|
|
|
|
Ok(io::BufReader::new(file).lines())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn part_one() {
|
|
|
|
let mut grid: Vec<Vec<Tree>> = vec![];
|
|
|
|
let mut total = 0;
|
|
|
|
if let Ok(lines) = read_lines("./inputs/input") {
|
|
|
|
for (i, line) in lines.enumerate() {
|
|
|
|
if let Ok(row) = line {
|
|
|
|
grid.push(vec![]);
|
|
|
|
let mut max = -1;
|
|
|
|
for c in row.chars() {
|
|
|
|
if (c as i8) - 48 > max {
|
|
|
|
total += 1;
|
|
|
|
max = (c as i8) - 48;
|
|
|
|
grid[i].push(Tree((c as i8) - 48, true));
|
|
|
|
} else {
|
|
|
|
grid[i].push(Tree((c as i8) - 48, false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
max = -1;
|
|
|
|
let invert = grid[i].len() - 1;
|
|
|
|
for (j, t) in grid[i].clone().iter().rev().enumerate() {
|
|
|
|
if t.0 > max {
|
|
|
|
if !grid[i][invert - j].1 {
|
|
|
|
total += 1;
|
|
|
|
}
|
|
|
|
max = t.0;
|
|
|
|
grid[i][invert - j] = Tree(t.0, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let invert = grid.len() - 1;
|
|
|
|
for i in 0..grid.len() {
|
|
|
|
let mut in_max = -1;
|
|
|
|
let mut out_max = -1;
|
|
|
|
for j in 0..grid.len() {
|
|
|
|
if grid[j][i].0 > in_max {
|
|
|
|
if !grid[j][i].1 {
|
|
|
|
total += 1;
|
|
|
|
}
|
|
|
|
in_max = grid[j][i].0;
|
|
|
|
grid[j][i] = Tree(grid[j][i].0, true);
|
|
|
|
}
|
|
|
|
if grid[invert - j][i].0 > out_max {
|
|
|
|
if !grid[invert - j][i].1 {
|
|
|
|
total += 1;
|
|
|
|
}
|
|
|
|
out_max = grid[invert - j][i].0;
|
|
|
|
grid[invert - j][i] = Tree(grid[invert - j][i].0, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
println!("{}", total);
|
|
|
|
}
|
|
|
|
|
2022-12-09 01:29:02 +00:00
|
|
|
fn part_two() {
|
|
|
|
let mut grid: Vec<Vec<Tree>> = vec![];
|
|
|
|
let mut best = 0;
|
|
|
|
if let Ok(lines) = read_lines("./inputs/input") {
|
|
|
|
for (i, line) in lines.enumerate() {
|
|
|
|
if let Ok(row) = line {
|
|
|
|
grid.push(vec![]);
|
|
|
|
for c in row.chars() {
|
|
|
|
grid[i].push(Tree((c as i8) - 48, false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// alright, we'll do this the hard way
|
|
|
|
// we can skip the edges, because they all multiply by 0 in one way or another
|
|
|
|
for i in 1..grid.len() - 1 {
|
|
|
|
for j in 1..grid.len() - 1 {
|
|
|
|
let (mut score, mut acc) = (1, 0); // a base score and the counter we'll reuse
|
|
|
|
for x in (0..j).rev() {
|
|
|
|
// left
|
|
|
|
acc += 1;
|
|
|
|
if grid[i][x].0 >= grid[i][j].0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score *= acc;
|
|
|
|
acc = 0;
|
|
|
|
for x in (0..i).rev() {
|
|
|
|
// up
|
|
|
|
acc += 1;
|
|
|
|
if grid[x][j].0 >= grid[i][j].0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score *= acc;
|
|
|
|
acc = 0;
|
|
|
|
for x in (j + 1)..grid.len() {
|
|
|
|
// right
|
|
|
|
acc += 1;
|
|
|
|
if grid[i][x].0 >= grid[i][j].0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score *= acc;
|
|
|
|
acc = 0;
|
|
|
|
for x in (i + 1)..grid.len() {
|
|
|
|
// down
|
|
|
|
acc += 1;
|
|
|
|
if grid[x][j].0 >= grid[i][j].0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score *= acc;
|
|
|
|
if score > best {
|
|
|
|
best = score;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
println!("{}", best);
|
|
|
|
}
|