Day 18
This commit is contained in:
parent
ca60c2b164
commit
cd4268a9ce
1 changed files with 211 additions and 0 deletions
211
src/bin/day18.rs
Normal file
211
src/bin/day18.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BinaryHeap, HashMap, HashSet},
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
|
use aoc_2024::{load, print_res};
|
||||||
|
use bstr::BString;
|
||||||
|
use color_eyre::eyre::OptionExt;
|
||||||
|
|
||||||
|
type Parsed = Vec<(usize, usize)>;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn parsing(input: &BString) -> color_eyre::Result<Parsed> {
|
||||||
|
std::str::from_utf8(input)?
|
||||||
|
.lines()
|
||||||
|
.map(|l| {
|
||||||
|
let (x, y) = l.split_once(',').ok_or_eyre("Missing ,")?;
|
||||||
|
|
||||||
|
Ok((x.parse()?, y.parse()?))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a_star(grid: &[[bool; GRID_SIZE]; GRID_SIZE]) -> Option<usize> {
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
struct Path {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
score: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Path {
|
||||||
|
fn heuristic(&self) -> usize {
|
||||||
|
self.score + (GRID_SIZE - 1 - self.x) + (GRID_SIZE - 1 - self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Path {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
other.heuristic().cmp(&self.heuristic())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Path {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut prev = HashMap::new();
|
||||||
|
|
||||||
|
let mut visited = HashMap::new();
|
||||||
|
visited.insert((0, 0), 0);
|
||||||
|
|
||||||
|
let mut current = BinaryHeap::new();
|
||||||
|
current.push(Path {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
score: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
while let Some(p) = current.pop() {
|
||||||
|
if p.x == GRID_SIZE - 1 && p.y == GRID_SIZE - 1 {
|
||||||
|
return Some(p.score);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut try_insert = |n: Path| {
|
||||||
|
if !grid[n.x][n.y] {
|
||||||
|
match visited.get(&(n.x, n.y)) {
|
||||||
|
Some(&s) if s >= n.score => (),
|
||||||
|
_ => {
|
||||||
|
visited.insert((n.x, n.y), n.score);
|
||||||
|
prev.insert((n.x, n.y), (p.x, p.y));
|
||||||
|
current.push(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let x = p.x;
|
||||||
|
let y = p.y;
|
||||||
|
let score = p.score + 1;
|
||||||
|
|
||||||
|
if x > 0 {
|
||||||
|
let new_path = Path { x: x - 1, y, score };
|
||||||
|
try_insert(new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if x < GRID_SIZE - 1 {
|
||||||
|
let new_path = Path { x: x + 1, y, score };
|
||||||
|
try_insert(new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if y > 0 {
|
||||||
|
let new_path = Path { x, y: y - 1, score };
|
||||||
|
try_insert(new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if y < GRID_SIZE - 1 {
|
||||||
|
let new_path = Path { x, y: y + 1, score };
|
||||||
|
try_insert(new_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
const GRID_SIZE: usize = 70 + 1;
|
||||||
|
const CUTTOF: usize = 1024;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part1(input: Parsed) {
|
||||||
|
let mut grid = [[false; GRID_SIZE]; GRID_SIZE];
|
||||||
|
|
||||||
|
for &(x, y) in &input[0..CUTTOF] {
|
||||||
|
grid[x][y] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = a_star(&grid).unwrap();
|
||||||
|
print_res!("Steps to take: {result}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bfs(grid: &[[bool; GRID_SIZE]; GRID_SIZE]) -> Option<HashSet<(usize, usize)>> {
|
||||||
|
let mut seen = HashMap::new();
|
||||||
|
seen.insert((0, 0), (0, 0));
|
||||||
|
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
paths.push((0, 0));
|
||||||
|
|
||||||
|
while let Some((x, y)) = paths.pop() {
|
||||||
|
if x == GRID_SIZE - 1 && y == GRID_SIZE - 1 {
|
||||||
|
let mut paths = HashSet::new();
|
||||||
|
let mut current = (x, y);
|
||||||
|
|
||||||
|
while current != (0, 0) {
|
||||||
|
paths.insert(current);
|
||||||
|
current = seen[¤t];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut try_insert = |nx: usize, ny: usize| {
|
||||||
|
if !grid[nx][ny] && !seen.contains_key(&(nx, ny)) {
|
||||||
|
seen.insert((nx, ny), (x, y));
|
||||||
|
paths.push((nx, ny));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if x > 0 {
|
||||||
|
try_insert(x - 1, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if x < GRID_SIZE - 1 {
|
||||||
|
try_insert(x + 1, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if y > 0 {
|
||||||
|
try_insert(x, y - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if y < GRID_SIZE - 1 {
|
||||||
|
try_insert(x, y + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part2(input: Parsed) {
|
||||||
|
let mut grid = [[false; GRID_SIZE]; GRID_SIZE];
|
||||||
|
let mut seen = bfs(&grid).unwrap();
|
||||||
|
|
||||||
|
for (x, y) in input {
|
||||||
|
grid[x][y] = true;
|
||||||
|
|
||||||
|
if seen.contains(&(x, y)) {
|
||||||
|
match bfs(&grid) {
|
||||||
|
Some(p) => seen = p,
|
||||||
|
None => {
|
||||||
|
print_res!("Breaking block: {x},{y}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Did not find a breaking block");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() -> color_eyre::Result<()> {
|
||||||
|
let context = load()?;
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let parsed = parsing(&context.input)?;
|
||||||
|
let elapsed = humantime::format_duration(start.elapsed());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
if context.part == 1 {
|
||||||
|
part1(parsed);
|
||||||
|
} else {
|
||||||
|
part2(parsed);
|
||||||
|
}
|
||||||
|
let elapsed_part = humantime::format_duration(start.elapsed());
|
||||||
|
|
||||||
|
println!(" Parsing: {elapsed}");
|
||||||
|
println!(" Solving: {elapsed_part}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue