Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/advent-of-code-2021
Path: blob/main/src/day09.rs
97 views
1
use std::collections::{HashMap, HashSet};
2
3
type Map = HashMap<(i32, i32), i32>;
4
5
pub fn run() {
6
let mut map: Map = Map::new();
7
for (y, line) in include_str!("inputs/day09").lines().enumerate() {
8
for (x, ch) in line.chars().enumerate() {
9
map.insert((x as i32, y as i32), ch.to_digit(10).unwrap() as i32);
10
}
11
}
12
13
let low_points = get_low_points(&map);
14
let risk: i32 = low_points.iter().map(|p| map.get(p).unwrap() + 1).sum();
15
println!("{}", risk);
16
17
let mut basin_sizes = get_basin_sizes(&map, &low_points);
18
basin_sizes.sort();
19
println!("{}", basin_sizes.iter().rev().take(3).fold(1, |a, b| a * b));
20
}
21
22
fn get_low_points(map: &Map) -> Vec<(i32, i32)> {
23
map
24
.iter()
25
.filter(|&(&(x, y), value)| {
26
[(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]
27
.iter()
28
.all(|point| value < map.get(point).unwrap_or(&10))
29
})
30
.map(|(&k, _)| k)
31
.collect()
32
}
33
34
fn get_basin_sizes(map: &Map, low_points: &Vec<(i32, i32)>) -> Vec<usize> {
35
low_points
36
.iter()
37
.map(|&(x, y)| {
38
let mut basin = HashSet::from([(x, y)]);
39
let mut unvisited = vec![(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)];
40
while let Some((x, y)) = unvisited.pop() {
41
if basin.contains(&(x, y)) {
42
continue;
43
}
44
match map.get(&(x, y)) {
45
None => continue,
46
Some(9) => continue,
47
Some(_) => {
48
basin.insert((x, y));
49
for point in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] {
50
unvisited.push(point)
51
}
52
}
53
}
54
}
55
basin.len()
56
})
57
.collect()
58
}
59
60