124 lines
3.4 KiB
Rust
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();
|
||
|
}
|