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
110
src/bin/day12.rs
110
src/bin/day12.rs
|
@ -1,6 +1,4 @@
|
||||||
use std::{
|
use std::collections::{BTreeSet, VecDeque};
|
||||||
collections::{BTreeSet, VecDeque},
|
|
||||||
};
|
|
||||||
|
|
||||||
use aoc_2022::*;
|
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;
|
struct Day12;
|
||||||
impl Solution<Input, Output> for Day12 {
|
impl Solution<Input, Output> for Day12 {
|
||||||
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
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 {
|
fn part_1(input: &Input) -> Output {
|
||||||
let start = find_start(input);
|
fn has_edge(graph: &[Vec<char>], from: &Position, to: &Position) -> bool {
|
||||||
let target = find_target(input);
|
get_elevation(*index(graph, to)) - get_elevation(*index(graph, from)) <= 1
|
||||||
|
}
|
||||||
|
|
||||||
let mut visited: BTreeSet<Position> = BTreeSet::new();
|
let (start, target) = (find_start(input), find_target(input));
|
||||||
let mut queue: VecDeque<Vertex> = VecDeque::new();
|
if let Some(distance) = bfs(input, &start, has_edge, |_, &v| v == target) {
|
||||||
visited.insert(start);
|
return distance;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
visited.insert(neighbour);
|
|
||||||
queue.push_back(Vertex::new(neighbour, v.distance + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!("haven't found path to target")
|
panic!("haven't found path to target")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
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 start = find_target(input);
|
||||||
|
if let Some(distance) = bfs(input, &start, has_edge, is_target) {
|
||||||
let mut visited: BTreeSet<Position> = BTreeSet::new();
|
return distance;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!("haven't found path to target")
|
panic!("haven't found path to target")
|
||||||
|
|
Loading…
Reference in a new issue