Compare commits

...

2 Commits

5 changed files with 151 additions and 6 deletions

25
data/examples/18.txt Normal file
View File

@ -0,0 +1,25 @@
5,4
4,2
4,5
3,0
2,1
6,3
2,4
1,5
0,6
3,3
2,6
5,1
1,2
5,5
2,5
6,5
1,4
0,4
6,4
1,1
6,1
1,0
0,5
1,6
2,0

View File

@ -22,7 +22,7 @@ fn dijkstra(grid: &Grid, start: Point) -> (Visited, Prev) {
let mut visited: Visited = HashMap::new();
let mut bh = BinaryHeap::new();
bh.push(Reverse((0, start, Direction::EAST, start, Direction::EAST)));
bh.push(Reverse((0, start, Direction::E, start, Direction::E)));
while let Some(Reverse((len, loc, dir, ploc, pdir))) = bh.pop() {
let best = visited.entry((loc, dir)).or_insert(usize::MAX);

94
src/bin/18.rs Normal file
View File

@ -0,0 +1,94 @@
use std::collections::VecDeque;
use hashbrown::{HashMap, HashSet};
use itertools::Itertools;
use aoc::{
grid_vec::{Direction, Point},
pnt,
};
fn parse_input(input: &str) -> Vec<Point> {
input
.lines()
.map(|x| {
x.split(',')
.filter_map(|y| y.parse().ok())
.collect_tuple()
.unwrap()
})
.map(|x: (usize, usize)| Point { i: x.1, j: x.0 })
.collect_vec()
}
fn bfs(
visited: &mut HashMap<Point, usize>,
queue: &mut VecDeque<(Point, usize)>,
corruption: &HashSet<Point>,
end: Point,
) -> Option<usize> {
visited.clear();
queue.clear();
queue.push_back((pnt!(0, 0), 0));
while let Some((p, l)) = queue.pop_front() {
if visited.contains_key(&p) {
continue;
}
visited.insert(p, l);
if p == end {
break;
}
for d in Direction::CROSS {
let n = p + d;
let in_bounds = n.bounded_by(&end);
let not_visited = !visited.contains_key(&n);
let not_corrupted = !corruption.contains(&n);
if in_bounds && not_visited && not_corrupted {
queue.push_back((n, l + 1));
}
}
}
visited.get(&end).copied()
}
pub fn part_one(input: &str) -> Option<usize> {
let falling_bytes = parse_input(input);
let mut visited = HashMap::new();
let mut queue = VecDeque::new();
let end = pnt!(70, 70);
let corruption = HashSet::from_iter(falling_bytes.iter().copied().take(1024));
bfs(&mut visited, &mut queue, &corruption, end)
}
pub fn part_two(input: &str) -> Option<String> {
let falling_bytes = parse_input(input);
let mut visited = HashMap::new();
let mut queue = VecDeque::new();
let end = pnt!(70, 70);
let mut corruption = HashSet::new();
let mut c = 0;
while bfs(&mut visited, &mut queue, &corruption, end).is_some() {
corruption.insert(falling_bytes[c]);
c += 1;
}
let fb = falling_bytes[c - 1];
Some(format!("{},{}", fb.j, fb.i))
}
aoc::solution!(18);

View File

@ -1,4 +1,4 @@
use std::fmt::Display;
use std::{fmt::Display, ops::Mul};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Direction {
@ -12,11 +12,33 @@ impl Display for Direction {
}
}
impl Mul<usize> for Direction {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
Self {
i: self.i * rhs as isize,
j: self.j * rhs as isize,
}
}
}
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 const N: Self = Direction { i: -1, j: 0 };
pub const E: Self = Direction { i: 0, j: 1 };
pub const S: Self = Direction { i: 1, j: 0 };
pub const W: Self = Direction { i: 0, j: -1 };
pub const NE: Self = Direction { i: -1, j: 1 };
pub const NW: Self = Direction { i: -1, j: -1 };
pub const SE: Self = Direction { i: 1, j: 1 };
pub const SW: Self = Direction { i: 1, j: -1 };
pub const CROSS: [Self; 4] = [Self::N, Self::E, Self::S, Self::W];
#[rustfmt::skip]
pub const OMNI: [Self; 8] = [
Self::N, Self::E, Self::S, Self::W,
Self::NE, Self::NW, Self::SE, Self::SW
];
pub fn new(i: isize, j: isize) -> Self {
Self { i, j }

View File

@ -81,6 +81,10 @@ impl Point {
pub fn sw(self) -> Self {
self.s().w()
}
pub fn bounded_by(&self, other: &Self) -> bool {
self.i <= other.i && self.j <= other.j
}
}
#[macro_export]