Implement day 11.

Whelp, this was really annoying.
This commit is contained in:
2018-11-30 16:39:42 +01:00
parent 48db1dde39
commit c41099d9d5
3 changed files with 197 additions and 0 deletions

4
2016/inputs/11.txt Normal file
View File

@@ -0,0 +1,4 @@
The first floor contains a polonium generator, a thulium generator, a thulium-compatible microchip, a promethium generator, a ruthenium generator, a ruthenium-compatible microchip, a cobalt generator, and a cobalt-compatible microchip.
The second floor contains a polonium-compatible microchip and a promethium-compatible microchip.
The third floor contains nothing relevant.
The fourth floor contains nothing relevant.

191
2016/src/day11.rs Normal file
View File

@@ -0,0 +1,191 @@
use common;
use regex;
use std::io;
use std::io::prelude::*;
use std::collections::{HashSet,HashMap,VecDeque};
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
struct State {
pub elevator: usize,
pub generators: [u8;4],
pub chips: [u8;4],
}
impl State {
pub fn is_valid(&self) -> bool {
for (&generators, &chips) in self.generators.iter().zip(self.chips.iter()) {
let matched = generators & chips;
if (chips & !matched) != 0 && generators != 0 {
return false;
}
}
true
}
pub fn is_done(&self) -> bool {
for i in 0..3usize {
if self.generators[i] != 0 || self.chips[i] != 0 {
return false;
}
}
true
}
}
#[derive(Default)]
pub struct Day11 {
}
impl Day11 {
pub fn new() -> Day11 {
Default::default()
}
fn add_modifications(new_states: &mut Vec<State>, cur: &State,
chip_modifications: u8, generator_modifications: u8) {
if cur.elevator > 0 {
let mut copy = cur.clone();
copy.chips[cur.elevator] &= !chip_modifications;
copy.chips[cur.elevator - 1] |= chip_modifications;
copy.generators[cur.elevator] &= !generator_modifications;
copy.generators[cur.elevator - 1] |= generator_modifications;
copy.elevator -= 1;
if copy.is_valid() {
new_states.push(copy);
}
}
if cur.elevator < 3 {
let mut copy= cur.clone();
copy.chips[cur.elevator] &= !chip_modifications;
copy.chips[cur.elevator + 1] |= chip_modifications;
copy.generators[cur.elevator] &= !generator_modifications;
copy.generators[cur.elevator + 1] |= generator_modifications;
copy.elevator += 1;
if copy.is_valid() {
new_states.push(copy);
}
}
}
fn read_state(input: &mut io::Read) -> State {
let reader = io::BufReader::new(input);
let mut state: State = Default::default();
let mut elements = HashMap::new();
let matcher = regex::Regex::new(r"a (\w+)(-compatible)? (microchip|generator)").unwrap();
for (i, line) in reader.lines().enumerate() {
let contents = line.unwrap();
for result in matcher.captures_iter(&contents) {
let element = result.get(1).unwrap().as_str();
if elements.get(element) == None {
let new_id = elements.len();
elements.insert(element.to_string(), new_id);
}
let id = *elements.get(element).unwrap();
let index = 1 << id;
match result.get(3).unwrap().as_str() {
"microchip" => {state.chips[i] |= index},
"generator" => {state.generators[i] |= index},
_ => panic!("Invalid component type."),
};
}
}
state
}
fn solve(initial: State) -> String {
let mut todo = VecDeque::new();
let mut visited = HashSet::new();
todo.push_back((0, initial));
visited.insert(initial);
assert!(initial.is_valid());
while let Some((dist, state)) = todo.pop_front() {
if state.is_done() {
return format!("{}", dist);
}
let new_dist = dist + 1;
let chips: u8 = state.chips[state.elevator];
let generators: u8 = state.generators[state.elevator];
let mut new_states = Vec::new();
// Move two chips
for i in 0..8u8 {
for j in 0..=i {
if ((1 << i) & chips) == 0 || ((1 << j) & chips) == 0 {
continue;
}
let modification = (1 << i) | (1 << j);
Day11::add_modifications(&mut new_states, &state, modification, 0);
}
}
// Move two generators
for i in 0..8u8 {
for j in 0..=i {
if ((1 << i) & generators) == 0 || ((1 << j) & generators) == 0 {
continue;
}
let modification = (1 << i) | (1 << j);
Day11::add_modifications(&mut new_states, &state, 0, modification);
}
}
// Move one of each
for i in 0..8u8 {
for j in 0..8u8 {
if ((1 << i) & chips) == 0 || ((1 << j) & generators) == 0 {
continue;
}
Day11::add_modifications(&mut new_states, &state, 1 << i, 1 << j);
}
}
for new_state in new_states {
if !visited.contains(&new_state) {
visited.insert(new_state);
todo.push_back((new_dist, new_state));
}
}
}
unreachable!()
}
}
impl common::Solution for Day11 {
fn part1(&mut self, input: &mut io::Read) -> String {
let initial = Day11::read_state(input);
Day11::solve(initial)
}
fn part2(&mut self, input: &mut io::Read) -> String {
let mut initial = Day11::read_state(input);
// Just add the new ones as the most significant bits
let modifier: u8 = 0b11000000;
initial.generators[0] |= modifier;
initial.chips[0] |= modifier;
Day11::solve(initial)
}
}
#[cfg(test)]
mod tests {
use super::*;
use common::Solution;
const SAMPLE: &[u8] = b"The first floor contains a hydrogen-compatible microchip and a lithium-compatible microchip.
The second floor contains a hydrogen generator.
The third floor contains a lithium generator.
The fourth floor contains nothing relevant.";
#[test]
fn sample_part1() {
let mut instance = Day11::new();
assert_eq!("11", instance.part1(&mut SAMPLE));
}
}

View File

@@ -9,6 +9,7 @@ use std::io;
pub mod common;
pub mod day1;
pub mod day2;
pub mod day11;
pub mod day12;
pub mod day15;
pub mod day16;
@@ -21,6 +22,7 @@ fn get_impl(day: &str) -> Box<common::Solution> {
match day.parse() {
Ok(1) => { Box::new(day1::Day1::new()) }
Ok(2) => { Box::new(day2::Day2::new()) }
Ok(11) => Box::new(day11::Day11::new()),
Ok(12) => { Box::new(day12::Day12::new()) }
Ok(15) => { Box::new(day15::Day15::new()) }
Ok(16) => { Box::new(day16::Day16::new()) }