[2016][rust][11.0] Floor.is_safe
change ptrlxqmvxszzpnwxkntumsyrrqvklrzl
commit 2052373d95ad52e5f17b200d731788cd9e49e2a6
author Alpha Chen <alpha.chen@gmail.com>
date
parent xsuwvykk
diff --git a/2016/rust/src/day_11.rs b/2016/rust/src/day_11.rs
index a1a0511..83fd274 100644
--- a/2016/rust/src/day_11.rs
+++ b/2016/rust/src/day_11.rs
@@ -1,3 +1,8 @@
+use regex;
+use std::convert::TryFrom;
+use std::str;
+use errors::*;
+
 // You come upon a column of four floors that have been entirely sealed off from the rest of the
 // building except for a small dedicated lobby. There are some radiation warnings and a big sign
 // which reads "Radioisotope Testing Facility".
@@ -6,19 +11,65 @@ struct Facility {
     floors: Vec<Floor>,
 }
 
-struct Floor(Vec<Item>);
+struct Floor {
+    items: Vec<Item>,
+}
 
-// According to the project status board, this facility is currently being used to experiment with
-// Radioisotope Thermoelectric Generators (RTGs, or simply "generators") that are designed to be
-// paired with specially-constructed microchips. Basically, an RTG is a highly radioactive rock
-// that generates electricity through heat.
+impl Floor {
+    fn generators(&self) -> Vec<String> {
+        self.items.iter().map(|item| {
+            match *item {
+                Item::Generator(ref s) => Some(s),
+                _ => None,
+            }
+        }).flat_map(|x| x).cloned().collect()
+    }
 
-#[derive(PartialEq)]
+    fn microchips(&self) -> Vec<String> {
+        self.items.iter().map(|item| {
+            match *item {
+                Item::Microchip(ref s) => Some(s),
+                _ => None,
+            }
+        }).flat_map(|x| x).cloned().collect()
+    }
+}
+
+#[test]
+fn test_generators_and_microchips() {
+    let items = vec![
+        Item::Generator("a".into()),
+        Item::Microchip("b".into()),
+    ];
+    let floor = Floor{items};
+    assert_eq!(floor.generators(), vec!["a".to_string()]);
+    assert_eq!(floor.microchips(), vec!["b".to_string()]);
+}
+
+#[derive(Clone, PartialEq)]
 enum Item {
     Generator(String),
     Microchip(String),
 }
 
+impl<'a> TryFrom<regex::Captures<'a>> for Item {
+    type Err = Error;
+    fn try_from(c: regex::Captures) -> Result<Item> {
+        let element = c.name("element").ok_or("missing element name")?;
+        let itemtype = c.name("itemtype").ok_or("missing item type")?;
+        match itemtype {
+            "generator" => { Ok(Item::Generator(element.into())) },
+            "microchip" => { Ok(Item::Microchip(element.into())) },
+            _ => { Err(format!("invalid item type: '{}", itemtype).into()) },
+        }
+    }
+}
+
+// According to the project status board, this facility is currently being used to experiment with
+// Radioisotope Thermoelectric Generators (RTGs, or simply "generators") that are designed to be
+// paired with specially-constructed microchips. Basically, an RTG is a highly radioactive rock
+// that generates electricity through heat.
+//
 // The experimental RTGs have poor radiation containment, so they're dangerously radioactive. The
 // chips are prototypes and don't have normal radiation shielding, but they do have the ability to
 // generate an electromagnetic radiation shield when powered. Unfortunately, they can only be
@@ -29,7 +80,39 @@ enum Item {
 // to its own RTG, the chip will be fried. Therefore, it is assumed that you will follow procedure
 // and keep chips connected to their corresponding RTG when they're in the same room, and away from
 // other RTGs otherwise.
-//
+
+impl Floor {
+    fn is_safe(&self) -> bool {
+        if self.generators().is_empty() {
+            return true;
+        }
+
+        let generators = self.generators();
+        let microchips = self.microchips();
+        let unpaired_chips = microchips.iter().filter(|microchip| {
+            !generators.contains(&microchip)
+        });
+        unpaired_chips.count() == 0
+    }
+}
+
+#[test]
+fn test_is_safe() {
+    assert!(Floor{items: Vec::new()}.is_safe());
+    assert!(Floor{items: vec![Item::Generator("".into())]}.is_safe());
+    assert!(Floor{items: vec![Item::Microchip("a".into())]}.is_safe());
+
+    let items = vec![Item::Generator("a".into()), Item::Microchip("b".into())];
+    assert!(!Floor{items}.is_safe());
+
+    let items = vec![
+        Item::Generator("a".into()),
+        Item::Microchip("a".into()),
+        Item::Generator("b".into()),
+    ];
+    assert!(Floor{items}.is_safe());
+}
+
 // These microchips sound very interesting and useful to your current activities, and you'd like to
 // try to retrieve them. The fourth floor of the facility has an assembling machine which can make
 // a self-contained, shielded computer for you to take with you - that is, if you can bring it all
@@ -59,42 +142,34 @@ enum Item {
 // The fourth floor contains nothing relevant.
 // As a diagram (F# for a Floor number, E for Elevator, H for Hydrogen, L for Lithium, M for Microchip, and G for Generator), the initial state looks like this:
 
-use regex;
-use std::convert::TryFrom;
-use std::str;
-use errors::*;
-
 impl str::FromStr for Floor {
     type Err = Error;
 
     fn from_str(input: &str) -> Result<Self> {
+        // Ok(Floor{items: Vec::new()})
         let re = regex::Regex::new(r"(?P<element>\w+)(-compatible)? (?P<itemtype>generator|microchip)").unwrap();
-        let items = re.captures_iter(input).map(Item::try_from).collect::<Result<_>>();
-        items.map(|items| Floor(items))
-    }
-}
-
-impl<'a> TryFrom<regex::Captures<'a>> for Item {
-    type Err = Error;
-    fn try_from(c: regex::Captures) -> Result<Self> {
-        let element = c.name("element").ok_or("missing element name")?;
-        let itemtype = c.name("itemtype").ok_or("missing item type")?;
-        match itemtype {
-            "generator" => Ok(Item::Generator(element.into())),
-            "microchip" => Ok(Item::Microchip(element.into())),
-            _ => Err(format!("unexpected item type: '{}'", itemtype).into()),
-        }
+        re.captures_iter(input)
+            .map(|captures| Item::try_from(captures))
+            .collect::<Result<Vec<_>>>()
+            .map(|items| Floor{items} )
     }
 }
 
 #[test]
 fn test_floor_from_str() {
-    let input = "The first floor contains a hydrogen-compatible microchip and a lithium-compatible microchip.";
+    let input = "The first floor contains a hydrogen-compatible microchip and \
+                 a lithium-compatible microchip.";
     let floor: Floor = input.parse().unwrap();
+    assert_eq!(floor.items.len(), 2);
+    assert!(floor.items.contains(&Item::Microchip("hydrogen".into())));
+    assert!(floor.items.contains(&Item::Microchip("lithium".into())));
 
-    assert_eq!(floor.0.len(), 2);
-    assert!(floor.0.contains(&Item::Microchip("hydrogen".into())));
-    assert!(floor.0.contains(&Item::Microchip("lithium".into())));
+    let input = "The first floor contains a hydrogen-compatible microchip and \
+                 a lithium generator.";
+    let floor: Floor = input.parse().unwrap();
+    assert_eq!(floor.items.len(), 2);
+    assert!(floor.items.contains(&Item::Microchip("hydrogen".into())));
+    assert!(floor.items.contains(&Item::Generator("lithium".into())));
 }
 
 // F4 .  .  .  .  .