got some shine on day 18
This commit is contained in:
parent
5f0d6f9869
commit
5135d5c78f
6
day18/Cargo.toml
Normal file
6
day18/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "day18"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
181
day18/src/main.rs
Normal file
181
day18/src/main.rs
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user