diff --git a/2016/11/Cargo.lock b/2016/11/Cargo.lock new file mode 100644 index 0000000..5f55a37 --- /dev/null +++ b/2016/11/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "11" +version = "0.1.0" + diff --git a/2016/11/Cargo.toml b/2016/11/Cargo.toml new file mode 100644 index 0000000..fb5facf --- /dev/null +++ b/2016/11/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "11" +version = "0.1.0" +authors = ["logaritmisk "] + +[dependencies] diff --git a/2016/11/example.txt b/2016/11/example.txt new file mode 100644 index 0000000..0a01c5e --- /dev/null +++ b/2016/11/example.txt @@ -0,0 +1,4 @@ +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. diff --git a/2016/11/input.txt b/2016/11/input.txt new file mode 100644 index 0000000..2c3c555 --- /dev/null +++ b/2016/11/input.txt @@ -0,0 +1,4 @@ +The first floor contains a thulium generator, a thulium-compatible microchip, a plutonium generator, and a strontium generator. +The second floor contains a plutonium-compatible microchip and a strontium-compatible microchip. +The third floor contains a promethium generator, a promethium-compatible microchip, a ruthenium generator, and a ruthenium-compatible microchip. +The fourth floor contains nothing relevant. diff --git a/2016/11/src/main.rs b/2016/11/src/main.rs new file mode 100644 index 0000000..289de56 --- /dev/null +++ b/2016/11/src/main.rs @@ -0,0 +1,399 @@ +use std::collections::HashSet; + + +type Floor = usize; + + +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct Facility { + elevator: Floor, + components: Vec<(Floor, Floor)>, + top_floor: Floor +} + +impl Facility { + pub fn new(elevator: Floor, top_floor: Floor) -> Self { + Facility { + elevator: elevator, + components: Vec::new(), + top_floor: top_floor - 1 + } + } + + pub fn is_done(&self) -> bool { + if self.elevator != self.top_floor { + return false; + } + + for &(g, m) in self.components.iter() { + if g != self.top_floor { + return false; + } + + if m != self.top_floor { + return false; + } + } + + true + } + + pub fn validate(&self) -> bool { + let mut generators = HashSet::new(); + let mut microchips = HashSet::new(); + + for (i, &(g, m)) in self.components.iter().enumerate() { + if g == self.elevator { + generators.insert(i); + } + if m == self.elevator { + microchips.insert(i); + } + } + + if !generators.is_empty() { + let diff = microchips.difference(&generators).collect::>(); + + if !diff.is_empty() { + return false; + } + } + + true + } + + pub fn steps(&self) -> Vec { + let mut variants = Vec::new(); + + for (i, &(g, m)) in self.components.iter().enumerate() { + if self.elevator < self.top_floor { + if g == self.elevator { + let mut variant = self.clone(); + + variant.elevator += 1; + + variant.components[i].0 += 1; + + if variant.validate() { + variants.push(variant); + } + } + + if m == self.elevator { + let mut variant = self.clone(); + + variant.elevator += 1; + + variant.components[i].1 += 1; + + if variant.validate() { + variants.push(variant); + } + } + } + + if self.elevator > 0 { + if g == self.elevator { + let mut variant = self.clone(); + + variant.elevator -= 1; + + variant.components[i].0 -= 1; + + if variant.validate() { + variants.push(variant); + } + } + + if m == self.elevator { + let mut variant = self.clone(); + + variant.elevator -= 1; + + variant.components[i].1 -= 1; + + if variant.validate() { + variants.push(variant); + } + } + } + } + + let mut components = self.components.iter().enumerate() + .flat_map(|(i, &(g, m))| vec![(i, 0, g), (i, 1, m)].into_iter()) + .filter(|&(_, _, f)| f == self.elevator) + .map(|(i, c, _)| (i, c)) + .collect::>(); + + while !components.is_empty() { + let a = components.remove(0); + + for b in components.iter() { + if self.elevator < self.top_floor { + let mut variant = self.clone(); + + variant.elevator += 1; + + match a.1 { + 0 => variant.components[a.0].0 += 1, + 1 => variant.components[a.0].1 += 1, + _ => unreachable!() + } + + match b.1 { + 0 => variant.components[b.0].0 += 1, + 1 => variant.components[b.0].1 += 1, + _ => unreachable!() + } + + if variant.validate() { + variants.push(variant); + } + } + + if self.elevator > 0 { + let mut variant = self.clone(); + + variant.elevator -= 1; + + match a.1 { + 0 => variant.components[a.0].0 -= 1, + 1 => variant.components[a.0].1 -= 1, + _ => unreachable!() + } + + match b.1 { + 0 => variant.components[b.0].0 -= 1, + 1 => variant.components[b.0].1 -= 1, + _ => unreachable!() + } + + if variant.validate() { + variants.push(variant); + } + } + } + } + + variants + } +} + + +fn main() { + let mut facilities = Vec::new(); + + let mut facility = Facility::new(0, 4); + + // Thulium + facility.components.push((0, 0)); + + // Plutonium + facility.components.push((0, 1)); + + // Strontium + facility.components.push((0, 1)); + + // Promethium + facility.components.push((2, 2)); + + // Ruthenium + facility.components.push((2, 2)); + + // Elerium + facility.components.push((0, 0)); + + // Dilithium + facility.components.push((0, 0)); + + facility.steps(); + + facilities.push(facility); + + let mut checked = HashSet::new(); + + for i in 0..100 { + let mut step_variants = Vec::new(); + + for facility in facilities.clone() { + if checked.contains(&facility) { + continue; + } + + let mut variants = facility.steps(); + + checked.insert(facility); + + step_variants.append(&mut variants); + } + + println!("step={}, variants={}", i + 1, step_variants.len()); + + + let done = step_variants.iter().filter(|x| x.is_done()).count(); + + if done > 0 { + println!("DONE!"); + break; + } + + facilities = step_variants; + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_step_01() { + let mut facility = Facility::new(0, 4); + + // Hydrogen + facility.components.push((1, 0)); + + // Lithium + facility.components.push((2, 0)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_02() { + let mut facility = Facility::new(1, 4); + + // Hydrogen + facility.components.push((1, 1)); + + // Lithium + facility.components.push((2, 0)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_03() { + let mut facility = Facility::new(2, 4); + + // Hydrogen + facility.components.push((2, 2)); + + // Lithium + facility.components.push((2, 0)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_04() { + let mut facility = Facility::new(1, 4); + + facility.components.push((2, 1)); + facility.components.push((2, 0)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_05() { + let mut facility = Facility::new(0, 4); + + facility.components.push((2, 0)); + facility.components.push((2, 0)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_06() { + let mut facility = Facility::new(0, 4); + + facility.components.push((2, 1)); + facility.components.push((2, 1)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_07() { + let mut facility = Facility::new(0, 4); + + facility.components.push((2, 2)); + facility.components.push((2, 2)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_08() { + let mut facility = Facility::new(0, 4); + + facility.components.push((2, 3)); + facility.components.push((2, 3)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_09() { + let mut facility = Facility::new(0, 4); + + facility.components.push((2, 2)); + facility.components.push((2, 3)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_10() { + let mut facility = Facility::new(0, 4); + + facility.components.push((3, 2)); + facility.components.push((3, 3)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_11() { + let mut facility = Facility::new(0, 4); + + facility.components.push((3, 2)); + facility.components.push((3, 2)); + + assert_eq!(true, facility.validate()); + assert_eq!(false, facility.is_done()); + } + + #[test] + fn test_step_12() { + let mut facility = Facility::new(3, 4); + + facility.components.push((3, 3)); + facility.components.push((3, 3)); + + assert_eq!(true, facility.validate()); + assert_eq!(true, facility.is_done()); + } + + #[test] + fn test_validate_01() { + let mut facility = Facility::new(0, 4); + + facility.components.push((1, 0)); + facility.components.push((0, 1)); + + assert_eq!(false, facility.validate()); + } +}