use std::{
collections::HashMap,
fs::File,
io::{BufRead, BufReader},
path::Path,
};
pub fn solve(input: &Path) -> anyhow::Result<()> {
println!("part one: {}", part_one(input)?);
println!("part two: {}", part_two(input)?);
Ok(())
}
fn navigate_one(
map: &[Vec<u8>],
h: u8,
p: (&usize, &usize),
nines: &mut HashMap<(usize, usize), ()>,
) {
let mut around_us = vec![];
if *p.0 > 0 {
let (y, x) = (p.0 - 1, *p.1);
around_us.push((map[y][x], y, x));
}
if let Some(row) = map.get(p.0 + 1) {
let (y, x) = (p.0 + 1, *p.1);
around_us.push((row[x], y, x));
}
if *p.1 > 0 {
let (y, x) = (*p.0, p.1 - 1);
around_us.push((map[y][x], y, x));
}
if let Some(height) = map[*p.0].get(p.1 + 1) {
let (y, x) = (*p.0, p.1 + 1);
around_us.push((*height, y, x));
}
for (n, y, x) in around_us {
if h == 8 && n == 9 {
nines.insert((y, x), ());
} else if n == h + 1 {
navigate_one(map, h + 1, (&y, &x), nines);
}
}
}
fn part_one(input: &Path) -> anyhow::Result<usize> {
let reader = BufReader::new(File::open(input)?);
let mut map: Vec<Vec<u8>> = vec![];
for line in reader.lines() {
map.push(
line?
.chars()
.map(|c| -> u8 { c.to_string().parse().unwrap() })
.collect(),
);
}
let trailheads: Vec<(usize, usize)> = map
.iter()
.enumerate()
.flat_map(|(y, row)| -> Vec<(usize, usize)> {
row.iter()
.enumerate()
.filter_map(|(x, n)| if *n == 0 { Some((y, x)) } else { None })
.collect()
})
.collect();
let mut answer = 0;
for (head_y, head_x) in &trailheads {
let mut nines: HashMap<(usize, usize), ()> = HashMap::new();
navigate_one(&map, 0, (head_y, head_x), &mut nines);
answer += nines.len();
}
Ok(answer)
}
fn navigate_two(map: &[Vec<u8>], h: u8, p: (&usize, &usize)) -> i32 {
let mut nines = 0;
let mut around_us = vec![];
if *p.0 > 0 {
let (y, x) = (p.0 - 1, *p.1);
around_us.push((map[y][x], y, x));
}
if let Some(row) = map.get(p.0 + 1) {
let (y, x) = (p.0 + 1, *p.1);
around_us.push((row[x], y, x));
}
if *p.1 > 0 {
let (y, x) = (*p.0, p.1 - 1);
around_us.push((map[y][x], y, x));
}
if let Some(height) = map[*p.0].get(p.1 + 1) {
let (y, x) = (*p.0, p.1 + 1);
around_us.push((*height, y, x));
}
for (n, y, x) in around_us {
if h == 8 && n == 9 {
nines += 1;
} else if n == h + 1 {
nines += navigate_two(map, h + 1, (&y, &x));
}
}
nines
}
fn part_two(input: &Path) -> anyhow::Result<i32> {
let reader = BufReader::new(File::open(input)?);
let mut map: Vec<Vec<u8>> = vec![];
for line in reader.lines() {
map.push(
line?
.chars()
.map(|c| -> u8 { c.to_string().parse().unwrap() })
.collect(),
);
}
let trailheads: Vec<(usize, usize)> = map
.iter()
.enumerate()
.flat_map(|(y, row)| -> Vec<(usize, usize)> {
row.iter()
.enumerate()
.filter_map(|(x, n)| if *n == 0 { Some((y, x)) } else { None })
.collect()
})
.collect();
let mut answer = 0;
for (head_y, head_x) in &trailheads {
answer += navigate_two(&map, 0, (head_y, head_x));
}
Ok(answer)
}