day(12): refactor
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
ce35175ccb
commit
6beaf1606c
1 changed files with 52 additions and 58 deletions
108
src/bin/day12.rs
108
src/bin/day12.rs
|
@ -1,6 +1,4 @@
|
|||
use std::{
|
||||
collections::{BTreeSet, VecDeque},
|
||||
};
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
|
||||
use aoc_2022::*;
|
||||
|
||||
|
@ -59,6 +57,41 @@ fn get_elevation(c: char) -> i32 {
|
|||
}
|
||||
}
|
||||
|
||||
fn bfs<F, G>(graph: &Vec<Vec<char>>, start: &Position, has_edge: F, is_target: G) -> Option<usize>
|
||||
where
|
||||
F: Fn(&[Vec<char>], &Position, &Position) -> bool,
|
||||
G: Fn(&[Vec<char>], &Position) -> bool,
|
||||
{
|
||||
let mut visited: BTreeSet<Position> = BTreeSet::new();
|
||||
let mut queue: VecDeque<Vertex> = VecDeque::new();
|
||||
visited.insert(*start);
|
||||
queue.push_back(Vertex::new(*start, 0));
|
||||
|
||||
while let Some(v) = queue.pop_front() {
|
||||
// debug!("Taking {:?} from queue at elevation {}", v, get_elevation(*index(input, &v.position)));
|
||||
|
||||
for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] {
|
||||
let d = Position::new(dx, dy);
|
||||
let neighbour = v.position + d;
|
||||
|
||||
if in_range(graph, &neighbour)
|
||||
&& has_edge(graph, &v.position, &neighbour)
|
||||
&& !visited.contains(&neighbour)
|
||||
{
|
||||
if is_target(graph, &neighbour) {
|
||||
// debug!("Found target at distance {}", v.distance + 1);
|
||||
return Some(v.distance + 1);
|
||||
}
|
||||
|
||||
visited.insert(neighbour);
|
||||
queue.push_back(Vertex::new(neighbour, v.distance + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
struct Day12;
|
||||
impl Solution<Input, Output> for Day12 {
|
||||
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||
|
@ -69,69 +102,30 @@ impl Solution<Input, Output> for Day12 {
|
|||
}
|
||||
|
||||
fn part_1(input: &Input) -> Output {
|
||||
let start = find_start(input);
|
||||
let target = find_target(input);
|
||||
|
||||
let mut visited: BTreeSet<Position> = BTreeSet::new();
|
||||
let mut queue: VecDeque<Vertex> = VecDeque::new();
|
||||
visited.insert(start);
|
||||
queue.push_back(Vertex::new(start, 0));
|
||||
|
||||
while let Some(v) = queue.pop_front() {
|
||||
// debug!("Taking {:?} from queue", v);
|
||||
|
||||
for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] {
|
||||
let d = Position::new(dx, dy);
|
||||
let neighbour = v.position + d;
|
||||
|
||||
let current = get_elevation(*index(input, &v.position));
|
||||
if in_range(input, &neighbour)
|
||||
&& (get_elevation(*index(input, &neighbour)) <= current + 1)
|
||||
&& !visited.contains(&neighbour)
|
||||
{
|
||||
if neighbour == target {
|
||||
// debug!("Found target at distance {}", v.distance + 1);
|
||||
return v.distance + 1;
|
||||
fn has_edge(graph: &[Vec<char>], from: &Position, to: &Position) -> bool {
|
||||
get_elevation(*index(graph, to)) - get_elevation(*index(graph, from)) <= 1
|
||||
}
|
||||
|
||||
visited.insert(neighbour);
|
||||
queue.push_back(Vertex::new(neighbour, v.distance + 1));
|
||||
}
|
||||
}
|
||||
let (start, target) = (find_start(input), find_target(input));
|
||||
if let Some(distance) = bfs(input, &start, has_edge, |_, &v| v == target) {
|
||||
return distance;
|
||||
}
|
||||
|
||||
panic!("haven't found path to target")
|
||||
}
|
||||
|
||||
fn part_2(input: &Input) -> Output {
|
||||
fn has_edge(graph: &[Vec<char>], from: &Position, to: &Position) -> bool {
|
||||
(get_elevation(*index(graph, from)) - get_elevation(*index(graph, to))) <= 1
|
||||
}
|
||||
|
||||
fn is_target(graph: &[Vec<char>], vertex: &Position) -> bool {
|
||||
get_elevation(*index(graph, vertex)) == 0
|
||||
}
|
||||
|
||||
let start = find_target(input);
|
||||
|
||||
let mut visited: BTreeSet<Position> = BTreeSet::new();
|
||||
let mut queue: VecDeque<Vertex> = VecDeque::new();
|
||||
visited.insert(start);
|
||||
queue.push_back(Vertex::new(start, 0));
|
||||
|
||||
while let Some(v) = queue.pop_front() {
|
||||
// debug!("Taking {:?} from queue at elevation {}", v, get_elevation(*index(input, &v.position)));
|
||||
|
||||
for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] {
|
||||
let d = Position::new(dx, dy);
|
||||
let neighbour = v.position + d;
|
||||
|
||||
let current = get_elevation(*index(input, &v.position));
|
||||
if in_range(input, &neighbour)
|
||||
&& (current - get_elevation(*index(input, &neighbour))) <= 1
|
||||
&& !visited.contains(&neighbour)
|
||||
{
|
||||
if get_elevation(*index(input, &neighbour)) == 0 {
|
||||
// debug!("Found target at distance {}", v.distance + 1);
|
||||
return v.distance + 1;
|
||||
}
|
||||
|
||||
visited.insert(neighbour);
|
||||
queue.push_back(Vertex::new(neighbour, v.distance + 1));
|
||||
}
|
||||
}
|
||||
if let Some(distance) = bfs(input, &start, has_edge, is_target) {
|
||||
return distance;
|
||||
}
|
||||
|
||||
panic!("haven't found path to target")
|
||||
|
|
Loading…
Reference in a new issue