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