diff --git a/2018/rust/src/bin/day_07.rs b/2018/rust/src/bin/day_07.rs
index 7b627c1..a604351 100644
--- a/2018/rust/src/bin/day_07.rs
+++ b/2018/rust/src/bin/day_07.rs
@@ -1,3 +1,6 @@
+#![feature(vec_remove_item)]
+
+use std::cmp::{Ord, Ordering};
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::io::{self, Read};
@@ -17,23 +20,115 @@ fn main() -> Result<(), Box<Error>> {
fn solve(input: &str) -> Result<String, Box<Error>> {
let mut assembly: Assembly = input.parse()?;
- let output = part_one(&mut assembly).iter().map(char::to_string).collect();
- Ok(output)
+ let output = part_two(&mut assembly, 5, |x| (x as usize) - ('A' as usize) + 61);
+ Ok(output.to_string())
}
-fn part_two<F: Fn(char) -> usize>(assembly: Assembly, worker_count: usize, step_time: F) {}
+fn part_two<F: Fn(char) -> usize>(
+ assembly: &mut Assembly,
+ worker_count: usize,
+ step_time: F,
+) -> usize {
+ let mut workers = Workers(vec![None; worker_count]);
+
+ let mut output = 0;
+ while !assembly.is_done() || workers.are_working() {
+ for (worker, step_id) in workers.available().iter_mut().zip(assembly.available()) {
+ worker.replace((step_id, step_time(step_id)));
+ assembly.start(&step_id);
+ }
+
+ let done = workers.tick();
+ for step_id in done {
+ assembly.finish(&step_id);
+ }
+
+ output += 1;
+ }
+
+ output
+}
+
+#[test]
+fn test_part_two() {
+ let input = r"
+Step C must be finished before step A can begin.
+Step C must be finished before step F can begin.
+Step A must be finished before step B can begin.
+Step A must be finished before step D can begin.
+Step B must be finished before step E can begin.
+Step D must be finished before step E can begin.
+Step F must be finished before step E can begin.
+ ";
+
+ let mut assembly: Assembly = input.parse().unwrap();
+ let output = part_two(&mut assembly, 2, |x| (x as usize) - ('A' as usize) + 1);
+ assert_eq!(output, 15);
+}
+
+#[derive(Debug)]
+struct Workers(Vec<Option<(char, usize)>>);
+
+impl Workers {
+ fn are_working(&self) -> bool {
+ !self.current_work().is_empty()
+ }
+
+ fn available(&mut self) -> Vec<&mut Option<(char, usize)>> {
+ self.0.iter_mut().filter(|x| x.is_none()).collect()
+ }
+
+ fn current_work(&self) -> Vec<&char> {
+ self.0.iter().flat_map(|x| x).map(|(x, _)| x).collect()
+ }
+
+ fn tick(&mut self) -> Vec<char> {
+ let mut done = Vec::new();
+ for maybe_work in self.0.iter_mut() {
+ if let Some((step, mut time)) = maybe_work.take() {
+ time -= 1;
+ if time > 0 {
+ maybe_work.replace((step, time));
+ } else {
+ done.push(step);
+ }
+ }
+ }
+ done
+ }
+}
+
+#[test]
+fn test_workers() {
+ let mut workers = Workers(vec![None; 5]);
+
+ let steps = workers.tick();
+ assert!(steps.is_empty());
+
+ let worker = &mut workers.available()[0];
+ worker.replace(('a', 5));
+ assert_eq!(workers.0[0], Some(('a', 5)));
+ assert_eq!(workers.current_work(), vec![&'a']);
+
+ let worker = &mut workers.available()[0];
+ worker.replace(('b', 1));
+ assert_eq!(workers.0[1], Some(('b', 1)));
+ assert_eq!(workers.current_work(), vec![&'a', &'b']);
+
+ let steps = workers.tick();
+ assert_eq!(workers.0[0], Some(('a', 4)));
+ assert_eq!(steps, vec!['b']);
+}
#[allow(dead_code)]
fn part_one(assembly: &mut Assembly) -> Vec<char> {
let mut output = Vec::new();
while !assembly.is_done() {
- let mut available = assembly.available_steps();
- available.sort();
- let done = *available[0];
-
- assembly.finish(&done);
+ let done = assembly.available()[0];
output.push(done);
+
+ assembly.finish(&done);
}
output
@@ -56,27 +151,43 @@ Step F must be finished before step E can begin.
assert_eq!(output, vec!['C', 'A', 'B', 'D', 'F', 'E']);
}
-struct Assembly {
- steps: HashMap<char, HashSet<char>>,
-}
+struct Assembly(Vec<Step>);
impl Assembly {
fn is_done(&self) -> bool {
- self.steps.is_empty()
+ self.0.iter().all(|x| x.state == State::Finished)
+ }
+
+ fn available(&self) -> Vec<char> {
+ let finished = self.finished();
+ let mut available: Vec<_> = self
+ .0
+ .iter()
+ .filter(|x| x.state == State::Unstarted)
+ .filter(|x| x.deps.iter().all(|x| finished.contains(x)))
+ .map(|x| x.id)
+ .collect();
+ available.sort();
+ available
}
- fn available_steps(&self) -> Vec<&char> {
- self.steps
+ fn finished(&self) -> Vec<char> {
+ self.0
.iter()
- .filter(|(_, v)| v.is_empty())
- .map(|(k, _)| k)
+ .filter(|x| x.state == State::Finished)
+ .map(|x| x.id)
.collect()
}
- fn finish(&mut self, step: &char) {
- self.steps.remove(step);
- for dependencies in self.steps.values_mut() {
- dependencies.remove(step);
+ fn start(&mut self, step_id: &char) {
+ if let Some(step) = self.0.iter_mut().find(|x| &x.id == step_id) {
+ step.state = State::InProgress;
+ }
+ }
+
+ fn finish(&mut self, step_id: &char) {
+ if let Some(step) = self.0.iter_mut().find(|x| &x.id == step_id) {
+ step.state = State::Finished;
}
}
}
@@ -103,7 +214,40 @@ impl FromStr for Assembly {
let entry = steps.entry(y).or_insert_with(HashSet::new);
entry.insert(x);
});
+ let steps = steps
+ .into_iter()
+ .map(|(id, deps)| {
+ let state = State::Unstarted;
+ Step { id, deps, state }
+ })
+ .collect();
+
+ Ok(Assembly(steps))
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct Step {
+ id: char,
+ deps: HashSet<char>,
+ state: State,
+}
+
+impl PartialOrd for Step {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
- Ok(Assembly { steps })
+impl Ord for Step {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.id.cmp(&other.id)
}
}
+
+#[derive(Eq, PartialEq)]
+enum State {
+ Unstarted,
+ InProgress,
+ Finished,
+}