generated from janezicmatej/aoc-template
	solution: day 16
This commit is contained in:
		
							
								
								
									
										119
									
								
								src/bin/16.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/bin/16.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/grid_vec/direction.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/grid_vec/direction.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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 }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								src/grid_vec/grid.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/grid_vec/grid.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/grid_vec/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/grid_vec/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
mod grid;
 | 
			
		||||
mod direction;
 | 
			
		||||
mod point;
 | 
			
		||||
 | 
			
		||||
pub use grid::Grid;
 | 
			
		||||
pub use direction::Direction;
 | 
			
		||||
pub use point::Point;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										91
									
								
								src/grid_vec/point.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/grid_vec/point.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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)]
 | 
			
		||||
 | 
			
		||||
pub mod grid_vec;
 | 
			
		||||
pub mod parsers;
 | 
			
		||||
pub mod template;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user