402 lines
9.5 KiB
Rust
402 lines
9.5 KiB
Rust
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::<Vec<_>>();
|
|
|
|
if !diff.is_empty() {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
pub fn steps(&self) -> Vec<Facility> {
|
|
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::<Vec<_>>();
|
|
|
|
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());
|
|
}
|
|
}
|