--- /dev/null
+use std::io::BufRead;
+
+use nalgebra::DMatrix;
+
+type Map = DMatrix<u32>;
+type Position = (usize, usize);
+
+pub fn read_map(reader: &mut dyn BufRead) -> (Map, Vec<Position>) {
+ let mut map = Map::default();
+ let mut start_positions: Vec<Position> = Vec::new();
+
+ for (i, l) in reader.lines().enumerate() {
+ if map.nrows() < i + 1 {
+ map = map.insert_row(i, 0);
+ }
+ for (j, c) in l.unwrap().chars().enumerate() {
+ if map.ncols() < j + 1 {
+ map = map.insert_column(j, 0);
+ }
+ let level = c.to_digit(10).unwrap();
+ map[(i, j)] = level;
+ if level == 0 {
+ start_positions.push((i, j));
+ }
+ }
+ }
+
+ (map, start_positions)
+}
+
+pub fn score(map: &Map, start_positions: &[Position], multiple_paths: bool) -> u32 {
+ fn neighbors((i, j): Position, ncols: usize, nrows: usize) -> Vec<Position> {
+ let mut positions = Vec::new();
+ if i > 0 {
+ positions.push((i - 1, j));
+ }
+ if i < nrows - 1 {
+ positions.push((i + 1, j));
+ }
+ if j > 0 {
+ positions.push((i, j - 1));
+ }
+ if j < ncols - 1 {
+ positions.push((i, j + 1));
+ }
+ positions
+ }
+
+ fn get_nb_summits(
+ (i, j): Position,
+ map: &Map,
+ visited: &mut Option<&mut DMatrix<bool>>,
+ ) -> u32 {
+ if let Some(visited) = visited.as_mut() {
+ if visited[(i, j)] {
+ return 0;
+ } else {
+ visited[(i, j)] = true;
+ }
+ }
+
+ if map[(i, j)] == 9 {
+ 1
+ } else {
+ neighbors((i, j), map.ncols(), map.nrows())
+ .into_iter()
+ .filter_map(|(i2, j2)| {
+ if map[(i2, j2)] == map[(i, j)] + 1 {
+ Some(get_nb_summits((i2, j2), map, visited))
+ } else {
+ None
+ }
+ })
+ .sum()
+ }
+ }
+
+ start_positions
+ .into_iter()
+ .map(|pos| {
+ let mut visited = DMatrix::<bool>::repeat(map.nrows(), map.ncols(), false);
+ let n = get_nb_summits(
+ *pos,
+ map,
+ &mut if multiple_paths {
+ None
+ } else {
+ Some(&mut visited)
+ },
+ );
+ n
+ })
+ .sum()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ static MAP: &str = "89010123
+78121874
+87430965
+96549874
+45678903
+32019012
+01329801
+10456732";
+
+ #[test]
+ fn test_part1() {
+ let (map, start_positions) = read_map(&mut MAP.as_bytes());
+ let score = score(&map, &start_positions, false);
+ assert_eq!(score, 36);
+ }
+
+ #[test]
+ fn test_part2() {
+ let (map, start_positions) = read_map(&mut MAP.as_bytes());
+ let score = score(&map, &start_positions, true);
+ assert_eq!(score, 81);
+ }
+}
day09::checksum(&memory_defrag_v2),
)
}
+
+pub fn day10(reader: &mut dyn BufRead) -> String {
+ let (map, start_positions) = day10::read_map(reader);
+ format!(
+ "part1: {}, part2: {}",
+ day10::score(&map, &start_positions, false),
+ day10::score(&map, &start_positions, true),
+ )
+}