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 { for f in 0..self.top_floor + 1 { let mut generators = HashSet::new(); let mut microchips = HashSet::new(); for (i, &(g, m)) in self.components.iter().enumerate() { if g == f { generators.insert(i); } if m == f { 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()); } }