aoc_2024/day10/src/main.rs
2024-12-12 10:40:37 -05:00

124 lines
3.4 KiB
Rust

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<String> = 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<Coord, i8> = HashMap::new();
let mut trailheads: HashSet<Coord> = 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::<i8>().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<Coord, i8>) -> i32 {
let mut visited: HashSet<Coord> = HashSet::new();
let mut front: HashSet<Coord> = HashSet::from([head]);
let mut peaks: HashSet<Coord> = HashSet::new();
while !front.is_empty() {
let mut new_front: HashSet<Coord> = 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<Coord, i8>) -> i32 {
let mut visited: HashSet<Coord> = HashSet::new();
let mut front: Vec<Coord> = vec![head];
let mut points = 0;
while !front.is_empty() {
let mut new_front: Vec<Coord> = 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<Coord, i8>) -> HashSet<Coord> {
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();
}