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