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