1use std::cmp::Reverse;
7
8use crate::util::bitset::*;
9
10type Input = [Step; 26];
11
12#[derive(Clone, Copy, Default)]
13pub struct Step {
14 todo: bool,
15 from: u32,
16 to: u32,
17}
18
19pub fn parse(input: &str) -> Input {
20 let mut steps = [Step::default(); 26];
21
22 for line in input.as_bytes().chunks(49) {
23 let from = to_index(line[5]);
25 let to = to_index(line[36]);
26
27 steps[from].todo = true;
29 steps[from].to |= 1 << to;
30
31 steps[to].todo = true;
32 steps[to].from |= 1 << from;
33 }
34
35 steps
36}
37
38pub fn part1(input: &Input) -> String {
39 let mut steps = *input;
40 let mut done = String::new();
41
42 while let Some(i) = next_ready(&steps) {
44 steps[i].todo = false;
46
47 done.push(from_index(i));
49
50 for j in steps[i].to.biterator() {
52 steps[j].from ^= 1 << i;
53 }
54 }
55
56 done
57}
58
59pub fn part2(input: &Input) -> usize {
60 part2_testable(input, 5, 60)
61}
62
63pub fn part2_testable(input: &Input, max_workers: usize, base_duration: usize) -> usize {
64 let mut steps = *input;
65 let mut time = 0;
66 let mut workers = Vec::new();
67
68 while next_ready(&steps).is_some() || !workers.is_empty() {
70 while let Some(i) = next_ready(&steps)
72 && workers.len() < max_workers
73 {
74 steps[i].todo = false;
76
77 let finish = time + base_duration + i + 1;
79
80 workers.push((finish, i));
83 workers.sort_unstable_by_key(|&(finish, _)| Reverse(finish));
84 }
85
86 let (finish, i) = workers.pop().unwrap();
90 time = finish;
91
92 for j in steps[i].to.biterator() {
94 steps[j].from ^= 1 << i;
95 }
96 }
97
98 time
99}
100
101fn to_index(b: u8) -> usize {
102 usize::from(b - b'A')
103}
104
105fn from_index(i: usize) -> char {
106 char::from(i as u8 + b'A')
107}
108
109fn next_ready(steps: &[Step]) -> Option<usize> {
110 steps.iter().position(|step| step.todo && step.from == 0)
111}