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], 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 { let reader = BufReader::new(File::open(input)?); let mut map: Vec> = 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], 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 { let reader = BufReader::new(File::open(input)?); let mut map: Vec> = 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) }