got some shine on day 18

This commit is contained in:
Shoofle 2024-12-18 11:58:01 -05:00
parent 5f0d6f9869
commit 5135d5c78f
2 changed files with 187 additions and 0 deletions

6
day18/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day18"
version = "0.1.0"
edition = "2021"
[dependencies]

181
day18/src/main.rs Normal file
View File

@ -0,0 +1,181 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::BinaryHeap;
use std::env;
use std::fs;
use crate::Dir::{North, South, East, West };
type Coord = (i32, i32);
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
enum Dir { North, South, East, West }
fn step(start: &Coord, d: Dir, steps: i32) -> Coord {
match d {
North => (start.0, start.1 - steps),
South => (start.0, start.1 + steps),
East => (start.0 + steps, start.1),
West => (start.0 - steps, start.1),
}
}
fn main() {
println!("Hello, AoC day 13!");
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
println!("wrong number of arguments!");
std::process::exit(1);
}
let file_path = &args[1];
let file = fs::read_to_string(file_path)
.expect("should be able to read the file");
let positions: Vec<Coord> = file.lines()
.filter(|l| l.len() != 0)
.map(|l| l.split_once(",").unwrap())
.map(|(left, right)| (left.parse().unwrap(), right.parse().unwrap()))
.collect();
println!("read in {} positions", positions.len());
let mut corner = (0,0);
positions.iter().for_each(|pos| {
corner.0 = corner.0.max(pos.0);
corner.1 = corner.1.max(pos.1);
});
let mut map = HashMap::new();
for y in 0..corner.1+1 {
for x in 0..corner.0+1 {
map.insert((x,y), '.');
}
}
let count = 1024;
for &(x, y) in &positions[..count] {
map.insert((x,y), '#');
}
print_map(&map);
let score = solve_maze(&map, (0,0), corner);
println!("the shortest path after {count} steps was {score:?}");
println!("let's do a binary blame search!");
let (mut lower, mut upper): (usize, usize) = (0,positions.len());
while lower < upper - 1 {
println!("checking if it's in [{},{})", lower, upper);
let middle = lower + ((upper - lower) / 2);
let test_map = map_at_time(&positions[..middle], corner);
//print_map(&test_map);
if let Some(_) = solve_maze(&test_map, (0,0), corner) {
// if there was a solution, up the lower bound
lower = middle;
} else {
// if no solution, lower the upper bound
upper = middle;
}
}
println!("it's no longer solved at {}ns when byte {},{} falls", lower, positions[lower].0, positions[lower].1);
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct State {
cost: u32,
heuristic: u32,
position: Coord,
}
impl Ord for State {
fn cmp(&self, other: &Self) -> Ordering {
// flipped ordering on cost, so that it's a min-heap and not a max-heap
(other.cost + other.heuristic).cmp(&(self.cost + self.heuristic))
.then_with(|| self.position.cmp(&other.position))
}
}
// `PartialOrd` needs to be implemented as well.
impl PartialOrd for State {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
fn solve_maze(map: &HashMap<Coord, char>, start: Coord, exit: Coord) -> Option<u32> {
let mut heap = BinaryHeap::new();
let mut minimals: HashMap<Coord, State> = HashMap::new();
heap.push(State { position: start, cost: 0, heuristic: hfunc(start, exit) });
while let Some(state) = heap.pop() {
let State { position, cost, heuristic: _ } = state;
if position == exit { return Some(cost); }
if let Some(old_state) = minimals.get(&position) {
if *old_state >= (State { position, cost, heuristic: 0 }) { continue; }
}
minimals.insert(position, State { position, cost, heuristic: 0 });
for new_dir in [North, South, East, West] {
let new_spot = step(&position, new_dir, 1);
if map.get(&new_spot) == Some(&'.') {
heap.push(State {
position: new_spot,
cost: cost + 1,
heuristic: hfunc(new_spot, exit),
});
}
}
}
return None;
}
fn hfunc(pos: Coord, end: Coord) -> u32 {
return ((pos.0-end.0).abs() + (pos.1-end.1).abs()).try_into().unwrap();
}
fn print_map(map: &HashMap<Coord, char>) {
let mut corner = (0,0);
for (p, _) in map {
corner.0 = corner.0.max(p.0);
corner.1 = corner.1.max(p.1);
}
for y in 0..corner.1+1 {
for x in 0..corner.0+1 {
print!("{}", map.get(&(x,y)).unwrap_or(&' '));
}
print!("\n");
}
print!("\n");
}
fn map_at_time(bytes: &[Coord], corner: Coord) -> HashMap<Coord, char>{
let mut map = HashMap::with_capacity((corner.0*corner.1).try_into().unwrap());
for y in 0..corner.1+1 {
for x in 0..corner.0+1 {
map.insert((x,y), '.');
}
}
for &(x, y) in bytes {
map.insert((x,y), '#');
}
return map;
}