Solve 18
This commit is contained in:
parent
d848d977c6
commit
b2311337a1
1 changed files with 140 additions and 0 deletions
140
src/bin/18.rs
Normal file
140
src/bin/18.rs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
use aoc::*;
|
||||||
|
use glam::IVec2;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../../input/18");
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_example!(part1_example, "18-test", 22);
|
||||||
|
println!("Part 1: {}", part1(INPUT, 70, 1024));
|
||||||
|
assert_example!(part2_example, "18-test", "6,1");
|
||||||
|
println!("Part 2: {}", part2(INPUT, 70));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1_example(input: &str) -> usize {
|
||||||
|
part1(input, 6, 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str, size: i32, steps: usize) -> usize {
|
||||||
|
let blocks = parse(input);
|
||||||
|
simulate(size, steps, &blocks)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2_example(input: &str) -> String {
|
||||||
|
part2(input, 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str, size: i32) -> String {
|
||||||
|
let blocks = parse(input);
|
||||||
|
let mut steps = 1;
|
||||||
|
let mut div = blocks.len() / 2;
|
||||||
|
|
||||||
|
// Binary search for the number of steps
|
||||||
|
loop {
|
||||||
|
let a_works = simulate(size, steps, &blocks) < usize::MAX;
|
||||||
|
let b_works = simulate(size, steps + 1, &blocks) < usize::MAX;
|
||||||
|
match (a_works, b_works) {
|
||||||
|
(true, false) => break,
|
||||||
|
(true, true) => {
|
||||||
|
steps += div;
|
||||||
|
div = 1.max(div / 2);
|
||||||
|
}
|
||||||
|
(false, false) => {
|
||||||
|
steps -= div;
|
||||||
|
div = 1.max(div / 2);
|
||||||
|
}
|
||||||
|
(false, true) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let blocker = blocks[steps];
|
||||||
|
format!("{},{}", blocker.x, blocker.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simulate(size: i32, steps: usize, blocks: &[IVec2]) -> usize {
|
||||||
|
let walls: HashSet<IVec2> = blocks.iter().take(steps).copied().collect();
|
||||||
|
let mut grid: HashMap<IVec2, Tile> = (0..=size)
|
||||||
|
.cartesian_product(0..=size)
|
||||||
|
.map(|(i, j)| IVec2::new(i, j))
|
||||||
|
.filter_map(|pos| {
|
||||||
|
if walls.contains(&pos) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((
|
||||||
|
pos,
|
||||||
|
Tile {
|
||||||
|
pos,
|
||||||
|
visited: false,
|
||||||
|
distance: usize::MAX,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
grid.insert(
|
||||||
|
IVec2::ZERO,
|
||||||
|
Tile {
|
||||||
|
pos: IVec2::ZERO,
|
||||||
|
visited: false,
|
||||||
|
distance: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let next = grid
|
||||||
|
.values()
|
||||||
|
.filter(|t| !t.visited)
|
||||||
|
.min_by_key(|t| t.distance)
|
||||||
|
.cloned();
|
||||||
|
let Some(next) = next else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
grid.insert(
|
||||||
|
next.pos,
|
||||||
|
Tile {
|
||||||
|
visited: true,
|
||||||
|
..next
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
for dir in DIRECTIONS4 {
|
||||||
|
let neighbor = next.pos + dir;
|
||||||
|
let Some(neighbor) = grid.get_mut(&neighbor) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if neighbor.visited {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(new_distance) = next.distance.checked_add(1) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if new_distance < neighbor.distance {
|
||||||
|
neighbor.distance = new_distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.get(&IVec2::splat(size)).unwrap().distance
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Tile {
|
||||||
|
pos: IVec2,
|
||||||
|
visited: bool,
|
||||||
|
distance: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &str) -> Vec<IVec2> {
|
||||||
|
input.lines().map(parse_line).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_line(line: &str) -> IVec2 {
|
||||||
|
let (x, y) = line.split_once(',').unwrap();
|
||||||
|
let x = x.parse().unwrap();
|
||||||
|
let y = y.parse().unwrap();
|
||||||
|
IVec2::new(x, y)
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue