[2018][rust][07.2]

sorbet
Alpha Chen 6 years ago
parent 6b086acd5b
commit 8aa06e54fd

@ -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: &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);
}
fn part_two<F: Fn(char) -> usize>(assembly: Assembly, worker_count: usize, step_time: F) {}
#[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_steps(&self) -> Vec<&char> {
self.steps
fn available(&self) -> Vec<char> {
let finished = self.finished();
let mut available: Vec<_> = self
.0
.iter()
.filter(|(_, v)| v.is_empty())
.map(|(k, _)| k)
.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 finished(&self) -> Vec<char> {
self.0
.iter()
.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,
}

Loading…
Cancel
Save