1use utils::bit::BitIterator;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day07 {
7 steps: u32,
8 requirements: [u32; 26],
9 workers: usize,
10 base_duration: u32,
11}
12
13impl Day07 {
14 pub fn new(input: &str, input_type: InputType) -> Result<Self, InputError> {
15 let step = parser::byte_range(b'A'..=b'Z').map(|x| x - b'A');
16
17 let mut steps = 0u32;
18 let mut requirements = [0u32; 26];
19 for item in step
20 .with_prefix("Step ")
21 .with_suffix(" must be finished before step ")
22 .then(step.with_suffix(" can begin."))
23 .with_suffix(parser::eol())
24 .parse_iterator(input)
25 {
26 let (first, second) = item?;
27 steps |= (1 << first) | (1 << second);
28 requirements[second as usize] |= 1 << first;
29 }
30
31 Ok(Self {
32 steps,
33 requirements,
34 workers: match input_type {
35 InputType::Example => 2,
36 InputType::Real => 5,
37 },
38 base_duration: match input_type {
39 InputType::Example => 1,
40 InputType::Real => 61,
41 },
42 })
43 }
44
45 #[must_use]
46 pub fn part1(&self) -> String {
47 let mut sequence = String::with_capacity(26);
48 let mut todo = self.steps;
49 while todo != 0 {
50 let (s, bit) = BitIterator::ones(todo)
51 .find(|&(r, _)| self.requirements[r as usize] & todo == 0)
52 .expect("no valid sequence");
53 todo &= !bit;
54 sequence.push((b'A' + s as u8) as char);
55 }
56 sequence
57 }
58
59 #[must_use]
60 pub fn part2(&self) -> u32 {
61 let mut pending = self.steps;
62 let mut incomplete = self.steps;
63 let mut second = 0;
64 let mut in_progress = Vec::with_capacity(self.workers);
65
66 while incomplete != 0 {
67 for (s, bit) in BitIterator::ones(pending)
68 .filter(|&(s, _)| self.requirements[s as usize] & incomplete == 0)
69 .take(self.workers - in_progress.len())
70 {
71 pending &= !bit;
72 in_progress.push((second + self.base_duration + s, bit));
73 }
74
75 (second, _) = *in_progress.iter().min().expect("no valid sequence");
76 in_progress.retain(|&(completed_at, bit)| {
77 if completed_at == second {
78 incomplete &= !bit;
79 false
80 } else {
81 true
82 }
83 });
84 }
85
86 second
87 }
88}
89
90examples!(Day07 -> (&'static str, u32) [
91 {file: "day07_example0.txt", part1: "CABDFE", part2: 15},
92]);