From c41099d9d583d78910565d9038bbd4c350095658 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Fri, 30 Nov 2018 16:39:42 +0100 Subject: [PATCH] Implement day 11. Whelp, this was really annoying. --- 2016/inputs/11.txt | 4 + 2016/src/day11.rs | 191 +++++++++++++++++++++++++++++++++++++++++++++ 2016/src/main.rs | 2 + 3 files changed, 197 insertions(+) create mode 100644 2016/inputs/11.txt create mode 100644 2016/src/day11.rs diff --git a/2016/inputs/11.txt b/2016/inputs/11.txt new file mode 100644 index 0000000..e82fca5 --- /dev/null +++ b/2016/inputs/11.txt @@ -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. diff --git a/2016/src/day11.rs b/2016/src/day11.rs new file mode 100644 index 0000000..9630ae2 --- /dev/null +++ b/2016/src/day11.rs @@ -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, 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)); + } +} diff --git a/2016/src/main.rs b/2016/src/main.rs index 17ce9f1..c4a2460 100644 --- a/2016/src/main.rs +++ b/2016/src/main.rs @@ -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 { 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()) }