generated from janezicmatej/aoc-template
solution: day 16
This commit is contained in:
parent
0000019062
commit
0000020047
|
@ -0,0 +1,17 @@
|
||||||
|
#################
|
||||||
|
#...#...#...#..E#
|
||||||
|
#.#.#.#.#.#.#.#.#
|
||||||
|
#.#.#.#...#...#.#
|
||||||
|
#.#.#.#.###.#.#.#
|
||||||
|
#...#.#.#.....#.#
|
||||||
|
#.#.#.#.#.#####.#
|
||||||
|
#.#...#.#.#.....#
|
||||||
|
#.#.#####.#.###.#
|
||||||
|
#.#.#.......#...#
|
||||||
|
#.#.###.#####.###
|
||||||
|
#.#.#...#.....#.#
|
||||||
|
#.#.#.#####.###.#
|
||||||
|
#.#.#.........#.#
|
||||||
|
#.#.#.#########.#
|
||||||
|
#S#.............#
|
||||||
|
#################
|
|
@ -0,0 +1,119 @@
|
||||||
|
use std::{cmp::Reverse, collections::BinaryHeap};
|
||||||
|
|
||||||
|
use aoc::grid_vec::{Direction, Grid, Point};
|
||||||
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
|
||||||
|
fn parse_input(input: &str) -> (Grid, Point, Point) {
|
||||||
|
let mut grid: Grid = input.parse().unwrap();
|
||||||
|
let start = grid.find(b'S').unwrap();
|
||||||
|
let end = grid.find(b'E').unwrap();
|
||||||
|
|
||||||
|
grid[start] = b'.';
|
||||||
|
grid[end] = b'.';
|
||||||
|
|
||||||
|
(grid, start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Prev = HashMap<(Point, Direction), HashSet<(Point, Direction)>>;
|
||||||
|
type Visited = HashMap<(Point, Direction), usize>;
|
||||||
|
|
||||||
|
fn dijkstra(grid: &Grid, start: Point) -> (Visited, Prev) {
|
||||||
|
let mut prev: Prev = HashMap::new();
|
||||||
|
let mut visited: Visited = HashMap::new();
|
||||||
|
|
||||||
|
let mut bh = BinaryHeap::new();
|
||||||
|
bh.push(Reverse((0, start, Direction::EAST, start, Direction::EAST)));
|
||||||
|
|
||||||
|
while let Some(Reverse((len, loc, dir, ploc, pdir))) = bh.pop() {
|
||||||
|
let best = visited.entry((loc, dir)).or_insert(usize::MAX);
|
||||||
|
|
||||||
|
if len > *best {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev.entry((loc, dir)).or_default().insert((ploc, pdir));
|
||||||
|
|
||||||
|
*best = len;
|
||||||
|
|
||||||
|
let n = loc + dir;
|
||||||
|
|
||||||
|
if grid.get(&n).filter(|&&c| c == b'.').is_some() && !visited.contains_key(&(n, dir)) {
|
||||||
|
bh.push(Reverse((len + 1, n, dir, loc, dir)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let rl = dir.rotate_left();
|
||||||
|
if !visited.contains_key(&(loc, rl)) {
|
||||||
|
bh.push(Reverse((len + 1000, loc, rl, loc, dir)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let rr = dir.rotate_right();
|
||||||
|
if !visited.contains_key(&(loc, rr)) {
|
||||||
|
bh.push(Reverse((len + 1000, loc, rr, loc, dir)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(visited, prev)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_one(input: &str) -> Option<usize> {
|
||||||
|
let (grid, start, end) = parse_input(input);
|
||||||
|
dijkstra(&grid, start)
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(k, _)| k.0 == end)
|
||||||
|
.map(|(_, v)| v)
|
||||||
|
.min()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_two(input: &str) -> Option<usize> {
|
||||||
|
let (grid, start, end) = parse_input(input);
|
||||||
|
|
||||||
|
let (visited, prev) = dijkstra(&grid, start);
|
||||||
|
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
stack.push(
|
||||||
|
prev.keys()
|
||||||
|
.filter(|&&k| k.0 == end)
|
||||||
|
.min_by_key(|&k| visited.get(k))
|
||||||
|
.copied()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
let mut seats = HashSet::new();
|
||||||
|
|
||||||
|
while let Some((loc, dir)) = stack.pop() {
|
||||||
|
if !visited.insert((loc, dir)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(prevs) = prev.get(&(loc, dir)) {
|
||||||
|
stack.extend(prevs);
|
||||||
|
}
|
||||||
|
|
||||||
|
seats.insert(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
seats.len().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
aoc::solution!(16);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_part_one() {
|
||||||
|
assert_eq!(
|
||||||
|
part_one(&aoc::template::read_file("examples", 16)),
|
||||||
|
Some(11048)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_part_two() {
|
||||||
|
assert_eq!(
|
||||||
|
part_two(&aoc::template::read_file("examples", 16)),
|
||||||
|
Some(64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||||
|
pub struct Direction {
|
||||||
|
pub i: isize,
|
||||||
|
pub j: isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Direction {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.i, self.j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
pub const NORTH: Self = Direction { i: -1, j: 0 };
|
||||||
|
pub const EAST: Self = Direction { i: 0, j: 1 };
|
||||||
|
pub const SOUTH: Self = Direction { i: 1, j: 0 };
|
||||||
|
pub const WEST: Self = Direction { i: 0, j: -1 };
|
||||||
|
|
||||||
|
pub fn new(i: isize, j: isize) -> Self {
|
||||||
|
Self { i, j }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate_left(self) -> Self {
|
||||||
|
Self {
|
||||||
|
i: -self.j,
|
||||||
|
j: self.i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate_right(self) -> Self {
|
||||||
|
Self {
|
||||||
|
i: self.j,
|
||||||
|
j: -self.i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! dir {
|
||||||
|
($i:literal, $j:literal) => {
|
||||||
|
Direction { i: $i, j: $j }
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Point;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Grid {
|
||||||
|
grid: Vec<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Grid {
|
||||||
|
type Err = ();
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let grid = s.lines().map(|x| x.as_bytes().to_vec()).collect();
|
||||||
|
Ok(Self { grid })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Grid {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for row in self.grid.iter() {
|
||||||
|
for cell in row.iter() {
|
||||||
|
write!(f, "{}", *cell as char)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<Point> for Grid {
|
||||||
|
type Output = u8;
|
||||||
|
fn index(&self, index: Point) -> &Self::Output {
|
||||||
|
&self.grid[index.i][index.j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<Point> for Grid {
|
||||||
|
fn index_mut(&mut self, index: Point) -> &mut Self::Output {
|
||||||
|
&mut self.grid[index.i][index.j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid {
|
||||||
|
pub fn find(&self, f: u8) -> Option<Point> {
|
||||||
|
let (i, j, _) = self
|
||||||
|
.grid
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(i, x)| x.iter().copied().enumerate().map(move |(j, y)| (i, j, y)))
|
||||||
|
.find(|x| x.2 == f)?;
|
||||||
|
|
||||||
|
Some(Point::new(i, j))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, p: &Point) -> Option<&u8> {
|
||||||
|
self.grid.get(p.i).and_then(|r| r.get(p.j))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, p: &Point) -> Option<&mut u8> {
|
||||||
|
self.grid.get_mut(p.i).and_then(|r| r.get_mut(p.j))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
mod grid;
|
||||||
|
mod direction;
|
||||||
|
mod point;
|
||||||
|
|
||||||
|
pub use grid::Grid;
|
||||||
|
pub use direction::Direction;
|
||||||
|
pub use point::Point;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
use super::Direction;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
|
ops::{Add, AddAssign},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||||
|
pub struct Point {
|
||||||
|
pub i: usize,
|
||||||
|
pub j: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Point {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.i, self.j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Direction> for Point {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Direction) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
i: self.i.wrapping_add(rhs.i as usize),
|
||||||
|
j: self.j.wrapping_add(rhs.j as usize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<Direction> for Point {
|
||||||
|
fn add_assign(&mut self, rhs: Direction) {
|
||||||
|
*self = *self + rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub fn new(i: usize, j: usize) -> Self {
|
||||||
|
Self { i, j }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn n(self) -> Self {
|
||||||
|
Self {
|
||||||
|
i: self.i.wrapping_sub(1),
|
||||||
|
j: self.j,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn s(self) -> Self {
|
||||||
|
Self {
|
||||||
|
i: self.i.wrapping_add(1),
|
||||||
|
j: self.j,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn e(self) -> Self {
|
||||||
|
Self {
|
||||||
|
i: self.i,
|
||||||
|
j: self.j.wrapping_sub(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn w(self) -> Self {
|
||||||
|
Self {
|
||||||
|
i: self.i,
|
||||||
|
j: self.j.wrapping_add(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ne(self) -> Self {
|
||||||
|
self.n().e()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nw(self) -> Self {
|
||||||
|
self.n().w()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn se(self) -> Self {
|
||||||
|
self.s().e()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sw(self) -> Self {
|
||||||
|
self.s().w()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pnt {
|
||||||
|
($i:literal, $j:literal) => {
|
||||||
|
Point { i: $i, j: $j }
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#![feature(pattern)]
|
#![feature(pattern)]
|
||||||
|
|
||||||
|
pub mod grid_vec;
|
||||||
pub mod parsers;
|
pub mod parsers;
|
||||||
pub mod template;
|
pub mod template;
|
||||||
|
|
Loading…
Reference in New Issue