1
0
Fork 0

day(12): refactor

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-12-12 10:47:56 +01:00
parent ce35175ccb
commit 6beaf1606c
Signed by: mfocko
GPG key ID: 7C47D46246790496

View file

@ -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 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;
} }
visited.insert(neighbour); let (start, target) = (find_start(input), find_target(input));
queue.push_back(Vertex::new(neighbour, v.distance + 1)); if let Some(distance) = bfs(input, &start, has_edge, |_, &v| v == target) {
} return distance;
}
} }
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")