use std::collections::HashSet; use std::collections::HashMap; use std::fs; use std::env; use crate::Dir::{North, South, East, West }; // nodes are (coord, direction) pairs. // neighbors are step1+turnleft, step2+turnleft, step3+turnleft, step1+turnright, etc #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] enum Dir { North, South, East, West } fn step(start: &Coord, d: Dir, steps: i32) -> Coord { match d { North => (start.0, start.1 - steps), South => (start.0, start.1 + steps), East => (start.0 + steps, start.1), West => (start.0 - steps, start.1), } } type Coord = (i32, i32); fn main() { println!("Hello, AoC day 04!"); let args: Vec = env::args().collect(); if args.len() != 2 { println!("wrong number of arguments!"); std::process::exit(1); } let file_path = &args[1]; let contents = fs::read_to_string(file_path).expect("Should have been able to read the file"); let mut grid: HashMap = HashMap::new(); let mut trailheads: HashSet = HashSet::new(); let mut x; // build our grid! let mut y = 0; for line in contents.lines() { x = 0; for c in line.chars() { let num = c.to_string().parse::().unwrap(); let coords = (x,y); if num == 0 { trailheads.insert(coords); } grid.insert(coords, num); x += 1; } y += 1; } let mut sum: i32 = 0; for head in &trailheads { sum += score(*head, &grid); } println!("there are {sum} points in score total"); let mut sum: i32 = 0; for head in &trailheads { sum += rating(*head, &grid); } println!("there are {sum} points in rating total") } fn score(head: Coord, grid: &HashMap) -> i32 { let mut visited: HashSet = HashSet::new(); let mut front: HashSet = HashSet::from([head]); let mut peaks: HashSet = HashSet::new(); while !front.is_empty() { let mut new_front: HashSet = HashSet::new(); for x in front.drain() { if grid[&x] == 9 { peaks.insert(x); } visited.insert(x); for x2 in neighbors(&x, &grid) { if visited.contains(&x2) { continue; } new_front.insert(x2); } } front = new_front; } return peaks.len() as i32; } fn rating(head: Coord, grid: &HashMap) -> i32 { let mut visited: HashSet = HashSet::new(); let mut front: Vec = vec![head]; let mut points = 0; while !front.is_empty() { let mut new_front: Vec = vec![]; for x in front.drain(..) { if grid[&x] == 9 { points += 1; } visited.insert(x); let x_neighbors = neighbors(&x, &grid); for x2 in x_neighbors { if visited.contains(&x2) { continue; } new_front.push(x2); } } front = new_front; } return points as i32; } fn neighbors(head: &Coord, grid: &HashMap) -> HashSet { let height = grid[head]; let neighbors = vec![North, South, East, West] .into_iter() .map(|x| step(head, x, 1)) .filter(|x| grid.contains_key(&x) && grid[&x]==height+1); return neighbors.collect(); }