1use crate::util::grid::*;
17use crate::util::parse::*;
18use crate::util::point::*;
19
20pub fn parse(input: &str) -> Grid<u8> {
21 Grid::parse(input)
22}
23
24pub fn part1(grid: &Grid<u8>) -> u32 {
25 let mut risk_levels = 0;
26
27 for x in 0..grid.width {
28 for y in 0..grid.height {
29 let point = Point::new(x, y);
30 let cur = grid[point];
31 let low_point = ORTHOGONAL
32 .iter()
33 .map(|&n| point + n)
34 .filter(|&n| grid.contains(n))
35 .all(|n| grid[n] > cur);
36
37 if low_point {
38 risk_levels += 1 + cur.to_decimal() as u32;
39 }
40 }
41 }
42
43 risk_levels
44}
45
46pub fn part2(input: &Grid<u8>) -> u32 {
47 let mut grid = input.clone();
48 let mut basins = Vec::new();
49
50 for x in 0..grid.width {
51 for y in 0..grid.height {
52 let next = Point::new(x, y);
53 if grid[next] < b'9' {
54 basins.push(flood_fill(&mut grid, next));
55 }
56 }
57 }
58
59 basins.sort_unstable();
60 basins.iter().rev().take(3).product()
61}
62
63fn flood_fill(grid: &mut Grid<u8>, point: Point) -> u32 {
64 grid[point] = b'9';
65 let mut size = 1;
66
67 for next in ORTHOGONAL.iter().map(|&n| point + n) {
68 if grid.contains(next) && grid[next] < b'9' {
69 size += flood_fill(grid, next);
70 }
71 }
72
73 size
74}