[2018][rust][07] refactor
change noquyyupqvottprpynqrymytzqxozpzr
commit d28ea1cded97ca62c8129d6dd4667f457e9d9564
author Alpha Chen <alpha.chen@gmail.com>
date
parent tmonxwmp
diff --git a/2018/rust/src/bin/day_07.rs b/2018/rust/src/bin/day_07.rs
index 895b60b..6cbc0d8 100644
--- a/2018/rust/src/bin/day_07.rs
+++ b/2018/rust/src/bin/day_07.rs
@@ -1,6 +1,7 @@
 use std::collections::{HashMap, HashSet};
 use std::error::Error;
 use std::io::{self, Read};
+use std::str::FromStr;
 
 use regex::Regex;
 
@@ -15,27 +16,16 @@ fn main() -> Result<(), Box<Error>> {
 }
 
 fn solve(input: &str) -> Result<String, Box<Error>> {
-    let re = Regex::new(r"^Step (\w).*step (\w)").unwrap();
-
-    let mut steps = HashMap::new();
-    input
-        .trim()
-        .lines()
-        .flat_map(|x| re.captures(x))
-        .map(|x| {
-            x.iter()
-                .flat_map(|x| x)
-                .map(|x| x.as_str())
-                .collect::<Vec<_>>()
-        })
-        .map(|x| (x[1], x[2]))
-        .for_each(|(x, y)| {
-            steps.entry(x).or_insert_with(HashSet::new);
-            let entry = steps.entry(y).or_insert_with(HashSet::new);
-            entry.insert(x);
-        });
+    let instructions: Instructions = input.parse()?;
+    let output = part_one(instructions).iter().map(char::to_string).collect();
+    Ok(output)
+}
+
+#[allow(dead_code)]
+fn part_one(instructions: Instructions) -> Vec<char> {
+    let mut steps = instructions.steps;
 
-    let mut output = String::new();
+    let mut output = Vec::new();
     while !steps.is_empty() {
         let mut ready: Vec<_> = steps
             .iter()
@@ -43,21 +33,21 @@ fn solve(input: &str) -> Result<String, Box<Error>> {
             .map(|(k, _)| k)
             .collect();
         ready.sort();
-        let done = ready[0].clone();
+        let done = *ready[0];
 
-        steps.remove(done);
+        steps.remove(&done);
         for dependencies in steps.values_mut() {
-            dependencies.remove(done);
+            dependencies.remove(&done);
         }
 
-        output.push_str(done);
+        output.push(done);
     }
 
-    Ok(output)
+    output
 }
 
 #[test]
-fn test_solve() {
+fn test_part_one() {
     let input = r"
 Step C must be finished before step A can begin.
 Step C must be finished before step F can begin.
@@ -68,6 +58,39 @@ Step D must be finished before step E can begin.
 Step F must be finished before step E can begin.
     ";
 
-    let output = solve(input).unwrap();
-    assert_eq!(output, "CABDFE".to_string());
+    let instructions: Instructions = input.parse().unwrap();
+    let output = part_one(instructions);
+    assert_eq!(output, vec!['C', 'A', 'B', 'D', 'F', 'E']);
+}
+
+struct Instructions {
+    steps: HashMap<char, HashSet<char>>,
+}
+
+impl FromStr for Instructions {
+    type Err = Box<Error>;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let re = Regex::new(r"^Step (\w).*step (\w)").unwrap();
+
+        let mut steps = HashMap::new();
+        s
+            .trim()
+            .lines()
+            .flat_map(|x| re.captures(x))
+            .map(|x| {
+                x.iter()
+                    .flat_map(|x| x)
+                    .map(|x| x.as_str().chars().next().unwrap())
+                    .collect::<Vec<_>>()
+            })
+        .map(|x| (x[1], x[2]))
+            .for_each(|(x, y)| {
+                steps.entry(x).or_insert_with(HashSet::new);
+                let entry = steps.entry(y).or_insert_with(HashSet::new);
+                entry.insert(x);
+            });
+
+        Ok(Instructions{steps})
+    }
 }