diff --git a/2022/src/bin/day12.rs b/2022/src/bin/day12.rs index 5c0a697..c9b3883 100644 --- a/2022/src/bin/day12.rs +++ b/2022/src/bin/day12.rs @@ -1,5 +1,7 @@ #![feature(test)] extern crate test; +use std::collections::HashSet; + use aoc2022::{ boilerplate, common::*, @@ -35,36 +37,33 @@ fn parse_input(raw: &str) -> Parsed { (start, end, grid) } -/// This is like… O(n³) or something for grid size n :tehe: fn part1((start, end, grid): &Parsed) -> usize { let xbounds = 0..grid.len(); let ybounds = 0..grid.fields[0].len(); let mut distances = VecGrid { fields: vec![vec![usize::MAX; ybounds.end]; xbounds.end] }; + let mut visited = VecGrid { fields: vec![vec![false; ybounds.end]; xbounds.end] }; + let mut points_to_consider = HashSet::from([*start]); distances[*start] = 0; let mut curr = *start; loop { if &curr == end { return distances[curr]; } + points_to_consider.remove(&curr); for n in curr .neighbors_no_diagonals() .into_iter() .filter(|&PositionND([x, y])| xbounds.contains(&(x as usize)) && ybounds.contains(&(y as usize))) { - if grid[curr] >= grid[n] || grid[n] - grid[curr] == 1 { - distances[n] = distances[n].min(distances[curr] + 1); + if !visited[n] { + if grid[curr] >= grid[n] || grid[n] - grid[curr] == 1 { + distances[n] = distances[n].min(distances[curr] + 1); + } + points_to_consider.insert(n); } } - distances[curr] = usize::MAX; - let min = distances.fields.iter().flatten().min().unwrap(); - curr = distances - .fields - .iter() - .enumerate() - .find_map(|(x, row)| { - row.iter().enumerate().find_map(|(y, e)| (e == min).then_some(y)).map(|y| PositionND([x as i64, y as i64])) - }) - .unwrap(); + visited[curr] = true; + curr = *points_to_consider.iter().min_by_key(|&&p| distances[p]).unwrap(); } } @@ -72,31 +71,29 @@ fn part2((_, end, grid): &Parsed) -> usize { let xbounds = 0..grid.len(); let ybounds = 0..grid.fields[0].len(); let mut distances = VecGrid { fields: vec![vec![usize::MAX; ybounds.end]; xbounds.end] }; + let mut visited = VecGrid { fields: vec![vec![false; ybounds.end]; xbounds.end] }; + let mut points_to_consider = HashSet::from([*end]); distances[*end] = 0; let mut curr = *end; loop { if grid[curr] == b'a' { return distances[curr]; } + points_to_consider.remove(&curr); for n in curr .neighbors_no_diagonals() .into_iter() .filter(|&PositionND([x, y])| xbounds.contains(&(x as usize)) && ybounds.contains(&(y as usize))) { - if grid[curr] <= grid[n] || grid[curr] - grid[n] == 1 { - distances[n] = distances[n].min(distances[curr] + 1); + if !visited[n] { + if grid[curr] <= grid[n] || grid[curr] - grid[n] == 1 { + distances[n] = distances[n].min(distances[curr] + 1); + } + points_to_consider.insert(n); } } - distances[curr] = usize::MAX; - let min = distances.fields.iter().flatten().min().unwrap(); - curr = distances - .fields - .iter() - .enumerate() - .find_map(|(x, row)| { - row.iter().enumerate().find_map(|(y, e)| (e == min).then_some(y)).map(|y| PositionND([x as i64, y as i64])) - }) - .unwrap(); + visited[curr] = true; + curr = *points_to_consider.iter().min_by_key(|&&p| distances[p]).unwrap(); } }