day16
This commit is contained in:
parent
4ce7184b1e
commit
dc5f488212
|
@ -0,0 +1,287 @@
|
|||
use std::{
|
||||
cmp::{Ordering, Reverse},
|
||||
collections::BinaryHeap,
|
||||
};
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use hashbrown::HashSet;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Cell {
|
||||
Empty,
|
||||
Wall,
|
||||
}
|
||||
|
||||
type Input = ((usize, usize), (usize, usize), Vec<Vec<Cell>>);
|
||||
|
||||
#[aoc_generator(day16)]
|
||||
fn parse(input: &str) -> Input {
|
||||
let mut pos = (0, 0);
|
||||
let mut end = (0, 0);
|
||||
let map = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(y, line)| {
|
||||
line.chars()
|
||||
.enumerate()
|
||||
.map(|(x, c)| match c {
|
||||
'#' => Cell::Wall,
|
||||
'.' => Cell::Empty,
|
||||
'E' => {
|
||||
end = (x, y);
|
||||
Cell::Empty
|
||||
}
|
||||
'S' => {
|
||||
pos = (x, y);
|
||||
Cell::Empty
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
(pos, end, map)
|
||||
}
|
||||
|
||||
#[aoc(day16, part1)]
|
||||
fn part1(input: &Input) -> i64 {
|
||||
let start = (input.0 .0 as i64, input.0 .1 as i64);
|
||||
let end = (input.1 .0 as i64, input.1 .1 as i64);
|
||||
let map = input.2.clone();
|
||||
let w = map[0].len();
|
||||
let h = map.len();
|
||||
let mut d = vec![vec![[i64::MAX; 4]; w]; h];
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new();
|
||||
d[start.1 as usize][start.0 as usize][1] = 0;
|
||||
queue.push(Reverse((0, start.0, start.1, 1, 0)));
|
||||
|
||||
while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() {
|
||||
let dir_num = match (dir_x, dir_y) {
|
||||
(0, -1) => 0,
|
||||
(1, 0) => 1,
|
||||
(0, 1) => 2,
|
||||
(-1, 0) => 3,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if d[pos_y as usize][pos_x as usize][dir_num] < dist {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pos_x, pos_y) == end {
|
||||
break;
|
||||
}
|
||||
|
||||
if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty {
|
||||
let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num];
|
||||
if (dist + 1).cmp(dist_next) == Ordering::Less {
|
||||
*dist_next = dist + 1;
|
||||
queue.push(Reverse((
|
||||
*dist_next,
|
||||
pos_x + dir_x,
|
||||
pos_y + dir_y,
|
||||
dir_x,
|
||||
dir_y,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4];
|
||||
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||
*dist_next = dist + 1000;
|
||||
queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4];
|
||||
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||
*dist_next = dist + 1000;
|
||||
queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*d[end.1 as usize][end.0 as usize].iter().min().unwrap()
|
||||
}
|
||||
|
||||
#[aoc(day16, part2)]
|
||||
fn part2(input: &Input) -> i64 {
|
||||
let start = (input.0 .0 as i64, input.0 .1 as i64);
|
||||
let end = (input.1 .0 as i64, input.1 .1 as i64);
|
||||
let map = input.2.clone();
|
||||
let w = map[0].len();
|
||||
let h = map.len();
|
||||
let mut d = vec![vec![[i64::MAX; 4]; w]; h];
|
||||
let mut b = vec![vec![[vec![], vec![], vec![], vec![]]; w]; h];
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new();
|
||||
d[start.1 as usize][start.0 as usize][1] = 0;
|
||||
queue.push(Reverse((0, start.0, start.1, 1, 0)));
|
||||
|
||||
while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() {
|
||||
let dir_num = match (dir_x, dir_y) {
|
||||
(0, -1) => 0,
|
||||
(1, 0) => 1,
|
||||
(0, 1) => 2,
|
||||
(-1, 0) => 3,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if d[pos_y as usize][pos_x as usize][dir_num] < dist {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pos_x, pos_y) == end {
|
||||
break;
|
||||
}
|
||||
|
||||
if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty {
|
||||
let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num];
|
||||
let back_next = &mut b[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num];
|
||||
if (dist + 1).cmp(dist_next) == Ordering::Less {
|
||||
*dist_next = dist + 1;
|
||||
back_next.clear();
|
||||
back_next.push((pos_x, pos_y, dir_num));
|
||||
queue.push(Reverse((
|
||||
*dist_next,
|
||||
pos_x + dir_x,
|
||||
pos_y + dir_y,
|
||||
dir_x,
|
||||
dir_y,
|
||||
)));
|
||||
} else if (dist + 1).cmp(dist_next) == Ordering::Equal {
|
||||
back_next.push((pos_x, pos_y, dir_num));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4];
|
||||
let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 3) % 4];
|
||||
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||
*dist_next = dist + 1000;
|
||||
back_next.clear();
|
||||
back_next.push((pos_x, pos_y, dir_num));
|
||||
queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x)));
|
||||
} else if (dist + 1000).cmp(dist_next) == Ordering::Equal {
|
||||
back_next.push((pos_x, pos_y, dir_num));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4];
|
||||
let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 1) % 4];
|
||||
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||
*dist_next = dist + 1000;
|
||||
back_next.clear();
|
||||
back_next.push((pos_x, pos_y, dir_num));
|
||||
queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x)));
|
||||
} else if (dist + 1000).cmp(dist_next) == Ordering::Equal {
|
||||
back_next.push((pos_x, pos_y, dir_num));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visited = HashSet::new();
|
||||
let dist_min = *d[end.1 as usize][end.0 as usize].iter().min().unwrap();
|
||||
let mut stack = vec![];
|
||||
d[end.1 as usize][end.0 as usize]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, d)| {
|
||||
if *d == dist_min {
|
||||
stack.push((end.0, end.1, i));
|
||||
}
|
||||
});
|
||||
|
||||
while let Some((pos_x, pos_y, dir_num)) = stack.pop() {
|
||||
visited.insert((pos_x, pos_y));
|
||||
stack.append(&mut b[pos_y as usize][pos_x as usize][dir_num]);
|
||||
}
|
||||
|
||||
visited.len() as i64
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
assert_eq!(
|
||||
part1(&parse(
|
||||
"###############
|
||||
#.......#....E#
|
||||
#.#.###.#.###.#
|
||||
#.....#.#...#.#
|
||||
#.###.#####.#.#
|
||||
#.#.#.......#.#
|
||||
#.#.#####.###.#
|
||||
#...........#.#
|
||||
###.#.#####.#.#
|
||||
#...#.....#.#.#
|
||||
#.#.#.###.#.#.#
|
||||
#.....#...#.#.#
|
||||
#.###.#.#.#.#.#
|
||||
#S..#.....#...#
|
||||
###############"
|
||||
)),
|
||||
7036
|
||||
);
|
||||
assert_eq!(
|
||||
part1(&parse(include_str!("../input/2024/day16.txt"))),
|
||||
85420
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
assert_eq!(
|
||||
part2(&parse(
|
||||
"###############
|
||||
#.......#....E#
|
||||
#.#.###.#.###.#
|
||||
#.....#.#...#.#
|
||||
#.###.#####.#.#
|
||||
#.#.#.......#.#
|
||||
#.#.#####.###.#
|
||||
#...........#.#
|
||||
###.#.#####.#.#
|
||||
#...#.....#.#.#
|
||||
#.#.#.###.#.#.#
|
||||
#.....#...#.#.#
|
||||
#.###.#.#.#.#.#
|
||||
#S..#.....#...#
|
||||
###############"
|
||||
)),
|
||||
45
|
||||
);
|
||||
assert_eq!(
|
||||
part2(&parse(
|
||||
"#################
|
||||
#...#...#...#..E#
|
||||
#.#.#.#.#.#.#.#.#
|
||||
#.#.#.#...#...#.#
|
||||
#.#.#.#.###.#.#.#
|
||||
#...#.#.#.....#.#
|
||||
#.#.#.#.#.#####.#
|
||||
#.#...#.#.#.....#
|
||||
#.#.#####.#.###.#
|
||||
#.#.#.......#...#
|
||||
#.#.###.#####.###
|
||||
#.#.#...#.....#.#
|
||||
#.#.#.#####.###.#
|
||||
#.#.#.........#.#
|
||||
#.#.#.#########.#
|
||||
#S#.............#
|
||||
#################"
|
||||
)),
|
||||
64
|
||||
);
|
||||
assert_eq!(part2(&parse(include_str!("../input/2024/day16.txt"))), 492);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ mod day12;
|
|||
mod day13;
|
||||
mod day14;
|
||||
mod day15;
|
||||
mod day16;
|
||||
mod day2;
|
||||
mod day3;
|
||||
mod day4;
|
||||
|
|
Loading…
Reference in New Issue