day(24): add solution
Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
parent
113e927a65
commit
f72e98c586
2 changed files with 150 additions and 0 deletions
6
samples/day24.txt
Normal file
6
samples/day24.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
#.######
|
||||
#>>.<^<#
|
||||
#.<..<<#
|
||||
#>v.><>#
|
||||
#<^v^^>#
|
||||
######.#
|
144
src/bin/day24.rs
Normal file
144
src/bin/day24.rs
Normal file
|
@ -0,0 +1,144 @@
|
|||
use std::{collections::HashSet, ops::Index};
|
||||
|
||||
use aoc_2022::*;
|
||||
|
||||
type Input = Basin;
|
||||
type Output = isize;
|
||||
|
||||
type Position = Vector3D<isize>;
|
||||
|
||||
struct Basin {
|
||||
map: Vec<Vec<char>>,
|
||||
rows: isize,
|
||||
cols: isize,
|
||||
entry: Position,
|
||||
exit: Position,
|
||||
}
|
||||
|
||||
impl Index<Position> for Basin {
|
||||
type Output = char;
|
||||
|
||||
fn index(&self, index: Position) -> &Self::Output {
|
||||
if index.y() == 0 && index.x() == 1 {
|
||||
// entry
|
||||
return &'.';
|
||||
}
|
||||
|
||||
if index.y() == self.rows - 1 && index.x() == self.cols - 2 {
|
||||
// exit
|
||||
return &'.';
|
||||
}
|
||||
|
||||
if index.y() <= 0
|
||||
|| index.y() >= self.rows - 1
|
||||
|| index.x() <= 0
|
||||
|| index.x() >= self.cols - 1
|
||||
{
|
||||
// out of bounds
|
||||
return &'#';
|
||||
}
|
||||
|
||||
// We need to account for the loops of the blizzards
|
||||
let x_mod = self.cols - 2;
|
||||
let y_mod = self.rows - 2;
|
||||
|
||||
let x_w = ((index.x() - 1 + x_mod - (index.z() % x_mod)) % x_mod + 1) as usize;
|
||||
let x_e = ((index.x() - 1 + x_mod + (index.z() % x_mod)) % x_mod + 1) as usize;
|
||||
let y_n = ((index.y() - 1 + y_mod - (index.z() % y_mod)) % y_mod + 1) as usize;
|
||||
let y_s = ((index.y() - 1 + y_mod + (index.z() % y_mod)) % y_mod + 1) as usize;
|
||||
|
||||
if self.map[index.y() as usize][x_w] == '>' {
|
||||
return &self.map[index.y() as usize][x_w];
|
||||
}
|
||||
|
||||
if self.map[index.y() as usize][x_e] == '<' {
|
||||
return &self.map[index.y() as usize][x_e];
|
||||
}
|
||||
|
||||
if self.map[y_n][index.x() as usize] == 'v' {
|
||||
return &self.map[y_n][index.x() as usize];
|
||||
}
|
||||
|
||||
if self.map[y_s][index.x() as usize] == '^' {
|
||||
return &self.map[y_s][index.x() as usize];
|
||||
}
|
||||
|
||||
&'.'
|
||||
}
|
||||
}
|
||||
|
||||
fn find_exit(basin: &Input, entry: Position, exit: Position) -> Position {
|
||||
let next_positions = |p| {
|
||||
[(0, 0, 1), (0, -1, 1), (0, 1, 1), (-1, 0, 1), (1, 0, 1)]
|
||||
.iter()
|
||||
.filter_map(move |&(x, y, t)| {
|
||||
let next_p = p + Vector3D::new(x, y, t);
|
||||
|
||||
if basin[next_p] == '.' {
|
||||
Some(next_p)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let cost = |p: Position| p.z() as usize + exit.y().abs_diff(p.y()) + exit.x().abs_diff(p.x());
|
||||
|
||||
let mut seen: HashSet<Position> = HashSet::new();
|
||||
let mut q: MinHeap<(usize, Position)> = MinHeap::new();
|
||||
q.push((cost(entry), entry));
|
||||
|
||||
while let Some((_, pos)) = q.pop() {
|
||||
// debug!("Dequeued: {:?}", pos);
|
||||
if pos.y() == exit.y() && pos.x() == exit.x() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
for next_pos in next_positions(pos) {
|
||||
if !seen.contains(&next_pos) {
|
||||
seen.insert(next_pos);
|
||||
q.push((cost(next_pos), next_pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
struct Day24;
|
||||
impl Solution<Input, Output> for Day24 {
|
||||
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||
let map: Vec<Vec<char>> = file_to_string(pathname)
|
||||
.lines()
|
||||
.map(|l| l.chars().collect())
|
||||
.collect();
|
||||
let (rows, cols) = (map.len() as isize, map[0].len() as isize);
|
||||
|
||||
Basin {
|
||||
map,
|
||||
rows,
|
||||
cols,
|
||||
entry: Vector3D::new(1, 0, 0),
|
||||
exit: Vector3D::new(cols - 2, rows - 1, isize::MAX),
|
||||
}
|
||||
}
|
||||
|
||||
fn part_1(input: &Input) -> Output {
|
||||
find_exit(input, input.entry, input.exit).z()
|
||||
}
|
||||
|
||||
fn part_2(input: &Input) -> Output {
|
||||
let to_exit = find_exit(input, input.entry, input.exit);
|
||||
let to_entry = find_exit(input, to_exit, input.entry);
|
||||
let back_to_exit = find_exit(input, to_entry, input.exit);
|
||||
|
||||
back_to_exit.z()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Day24::run("sample")
|
||||
Day24::main()
|
||||
}
|
||||
|
||||
test_sample!(day_24, Day24, 18, 54);
|
Loading…
Reference in a new issue