1use crate::util::hash::*;
6use std::collections::BTreeMap;
7
8type Input = FastMap<u8, Step>;
9
10#[derive(Clone, Default)]
11pub struct Step {
12 remaining: u32,
13 children: Vec<u8>,
14}
15
16pub fn parse(input: &str) -> Input {
17 let mut steps = FastMap::new();
18
19 for line in input.lines().map(str::as_bytes) {
20 let from = line[5];
22 let to = line[36];
23
24 let step = steps.entry(from).or_insert(Step::default());
26 step.children.push(to);
27
28 let step = steps.entry(to).or_insert(Step::default());
31 step.remaining += 1;
32 }
33
34 steps
35}
36
37pub fn part1(input: &Input) -> String {
38 let mut ready = BTreeMap::new();
41 let mut blocked = FastMap::new();
42
43 for (key, step) in input.clone() {
44 if step.remaining == 0 {
45 ready.insert(key, step);
46 } else {
47 blocked.insert(key, step);
48 }
49 }
50
51 let mut done = String::new();
52
53 while let Some((key, step)) = ready.pop_first() {
54 done.push(key as char);
56
57 for key in step.children {
60 let mut step = blocked.remove(&key).unwrap();
61 step.remaining -= 1;
62
63 if step.remaining == 0 {
64 ready.insert(key, step);
65 } else {
66 blocked.insert(key, step);
67 }
68 }
69 }
70
71 done
72}
73
74pub fn part2(input: &Input) -> u32 {
75 part2_testable(input, 5, 60)
76}
77
78pub fn part2_testable(input: &Input, max_workers: usize, base_duration: u32) -> u32 {
79 let mut ready = BTreeMap::new();
81 let mut blocked = FastMap::new();
82
83 for (key, step) in input.clone() {
84 if step.remaining == 0 {
85 ready.insert(key, step);
86 } else {
87 blocked.insert(key, step);
88 }
89 }
90
91 let mut time = 0;
93 let mut workers = Vec::new();
94
95 while !ready.is_empty() || !workers.is_empty() {
96 while !ready.is_empty() && workers.len() < max_workers {
98 let (key, step) = ready.pop_first().unwrap();
99 let finish = time + base_duration + (key - 64) as u32;
100
101 workers.push((finish, step));
104 workers.sort_unstable_by_key(|(time, _)| u32::MAX - time);
105 }
106
107 let (finish, step) = workers.pop().unwrap();
111 time = finish;
112
113 for key in step.children {
115 let mut step = blocked.remove(&key).unwrap();
116 step.remaining -= 1;
117
118 if step.remaining == 0 {
119 ready.insert(key, step);
120 } else {
121 blocked.insert(key, step);
122 }
123 }
124 }
125
126 time
127}