1
0
Fork 0

day(12): add initial solution

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-12-12 10:31:14 +01:00
parent fabef3ee41
commit ce35175ccb
Signed by: mfocko
GPG key ID: 7C47D46246790496
2 changed files with 151 additions and 0 deletions

5
samples/day12.txt Normal file
View file

@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

146
src/bin/day12.rs Normal file
View 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);