day(12): add initial solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
fabef3ee41
commit
ce35175ccb
2 changed files with 151 additions and 0 deletions
5
samples/day12.txt
Normal file
5
samples/day12.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Sabqponm
|
||||||
|
abcryxxl
|
||||||
|
accszExk
|
||||||
|
acctuvwj
|
||||||
|
abdefghi
|
146
src/bin/day12.rs
Normal file
146
src/bin/day12.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeSet, VecDeque},
|
||||||
|
};
|
||||||
|
|
||||||
|
use aoc_2022::*;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
type Input = Vec<Vec<char>>;
|
||||||
|
type Output = usize;
|
||||||
|
|
||||||
|
type Position = Vector2D<isize>;
|
||||||
|
|
||||||
|
fn find(map: &[Vec<char>], expected: char) -> Option<Position> {
|
||||||
|
for (y, row) in map.iter().enumerate() {
|
||||||
|
for (x, &c) in row.iter().enumerate() {
|
||||||
|
if c == expected {
|
||||||
|
return Some(Position::new(x as isize, y as isize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_start(map: &[Vec<char>]) -> Position {
|
||||||
|
if let Some(pos) = find(map, 'S') {
|
||||||
|
pos
|
||||||
|
} else {
|
||||||
|
panic!("haven't found start")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_target(map: &[Vec<char>]) -> Position {
|
||||||
|
if let Some(pos) = find(map, 'E') {
|
||||||
|
pos
|
||||||
|
} else {
|
||||||
|
panic!("haven't found target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Vertex {
|
||||||
|
position: Position,
|
||||||
|
distance: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
fn new(position: Position, distance: usize) -> Self {
|
||||||
|
Self { position, distance }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_elevation(c: char) -> i32 {
|
||||||
|
match c {
|
||||||
|
'S' => get_elevation('a'),
|
||||||
|
'E' => get_elevation('z'),
|
||||||
|
_ => c as i32 - 'a' as i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Day12;
|
||||||
|
impl Solution<Input, Output> for Day12 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
|
file_to_lines(pathname)
|
||||||
|
.into_iter()
|
||||||
|
.map(|line| line.chars().collect_vec())
|
||||||
|
.collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.insert(neighbour);
|
||||||
|
queue.push_back(Vertex::new(neighbour, v.distance + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("haven't found path to target")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("haven't found path to target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
// Day12::run("sample")
|
||||||
|
Day12::main()
|
||||||
|
}
|
||||||
|
|
||||||
|
test_sample!(day_12, Day12, 31, 29);
|
Loading…
Reference in a new issue