Implement 2016 day 22 part 2.

Only 2 years and 2 months later.
This commit is contained in:
2019-02-19 15:28:32 +01:00
parent 9ce03d40ca
commit c4163824cc
2 changed files with 140 additions and 5 deletions

View File

@@ -1,13 +1,18 @@
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::collections::HashSet;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use common::Solution;
use std::io::BufReader;
use itertools::Itertools;
use regex::Regex;
use std::io::BufRead;
use common::Solution;
type Coordinate = (usize, usize);
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Default)]
struct Node {
pos: Coordinate,
capacity: usize,
@@ -20,6 +25,30 @@ impl Node {
}
}
fn get_grid<T>(list: &[T], size: usize, (x, y): Coordinate) -> &T {
&list[x + size * y]
}
fn get_mut_grid<T>(list: &mut [T], size: usize, (x, y): Coordinate) -> &mut T {
&mut list[x + size * y]
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
struct State {
pos: Coordinate,
empty_pos: Coordinate,
grid: Vec<usize>,
}
impl State {
fn estimate(&self) -> usize {
self.pos.0 + self.pos.1
+ self.pos.0.max(self.empty_pos.0) + self.pos.1.max(self.empty_pos.1)
- self.pos.0.min(self.empty_pos.0) - self.pos.1.min(self.empty_pos.1)
- 1
}
}
#[derive(Default)]
pub struct Day22 {
nodes: Vec<Node>,
@@ -49,8 +78,25 @@ impl Day22 {
self.nodes.push(node)
}
self.nodes.sort_unstable();
assert_ne!(0, self.nodes.len())
}
fn build_grid(&self) -> (usize, Vec<usize>, Vec<usize>) {
let size = self.nodes.iter().map(|node| node.pos.0).max().unwrap_or(0) + 1;
let mut used = vec![0usize; self.nodes.len()];
let mut capacity = used.clone();
for node in &self.nodes {
let pos = node.pos;
*get_mut_grid(&mut used, size, pos) = node.used;
*get_mut_grid(&mut capacity, size, pos) = node.capacity;
}
(size, used, capacity)
}
}
impl Solution for Day22 {
@@ -66,4 +112,83 @@ impl Solution for Day22 {
fitting.to_string()
}
fn part2(&mut self, input: &mut Read) -> String {
self.read_input(input);
let (size, used, capacity) = self.build_grid();
let (empty_pos, _) = used.iter()
.find_position(|&&used| used == 0)
.unwrap();
let height = used.len() / size;
let state = State {
pos: (size - 1, 0),
empty_pos: (empty_pos % size, empty_pos / size),
grid: used,
};
let mut visited = HashSet::new();
visited.insert((state.pos, state.empty_pos));
let mut todo = BinaryHeap::new();
todo.push(Reverse((state.estimate(), 0usize, state)));
while let Some(Reverse((_, dist, state))) = todo.pop() {
if state.pos == (0, 0) {
return dist.to_string();
}
let (xe, ye) = state.empty_pos;
let empty_capacity = *get_grid(&capacity, size, state.empty_pos);
let valid_x = [if xe > 0 { Some(xe - 1) } else { None }, Some(xe), Some(xe), if xe < size - 1 { Some(xe + 1) } else { None }];
let valid_y = [Some(ye), if ye > 0 { Some(ye - 1) } else { None }, if ye < height - 1 { Some(ye + 1) } else { None }, Some(ye)];
for (x, y) in valid_x.iter().zip(valid_y.iter()) {
if x.is_none() || y.is_none() {
continue
}
let switch = (x.unwrap(), y.unwrap());
let contents = *get_grid(&state.grid, size, switch);
if contents > empty_capacity {
// Not enough capacity
continue;
}
let mut new_state = State {
grid: state.grid.clone(),
empty_pos: switch,
pos: if switch == state.pos { state.empty_pos } else { state.pos },
};
if !visited.contains(&(new_state.pos, new_state.empty_pos)) {
visited.insert((new_state.pos, new_state.empty_pos));
*get_mut_grid(&mut new_state.grid, size, switch) = 0;
*get_mut_grid(&mut new_state.grid, size, state.empty_pos) = contents;
todo.push(Reverse((dist + 1 + new_state.estimate(), dist + 1, new_state)));
}
}
}
unreachable!("Did not arrive at an end state")
}
}
#[cfg(test)]
mod tests {
use common::Solution;
use day22::Day22;
const SAMPLE_INPUT: &[u8] = include_bytes!("samples/22.txt");
#[test]
fn sample_part2() {
let mut instance = Day22::new();
let result = instance.part2(&mut SAMPLE_INPUT);
assert_eq!("7", result);
}
}

10
2016/src/samples/22.txt Normal file
View File

@@ -0,0 +1,10 @@
Filesystem Size Used Avail Use%
/dev/grid/node-x0-y0 10T 8T 2T 80%
/dev/grid/node-x0-y1 11T 6T 5T 54%
/dev/grid/node-x0-y2 32T 28T 4T 87%
/dev/grid/node-x1-y0 9T 7T 2T 77%
/dev/grid/node-x1-y1 8T 0T 8T 0%
/dev/grid/node-x1-y2 11T 7T 4T 63%
/dev/grid/node-x2-y0 10T 6T 4T 60%
/dev/grid/node-x2-y1 9T 8T 1T 88%
/dev/grid/node-x2-y2 9T 6T 3T 66%