1use std::iter;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day01 {
7 changes: Vec<i32>,
8 total: i32,
9}
10
11impl Day01 {
12 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13 let changes = parser::i32().parse_lines(input)?;
14 Ok(Self {
15 total: changes.iter().sum(),
16 changes,
17 })
18 }
19
20 #[must_use]
21 pub fn part1(&self) -> i32 {
22 self.total
23 }
24
25 #[must_use]
26 pub fn part2(&self) -> i32 {
27 if self.total == 0 {
28 let mut frequencies = iter::once(0)
29 .chain(self.changes.iter().scan(0i32, |sum, &c| {
30 *sum += c;
31 Some(*sum)
32 }))
33 .enumerate()
34 .collect::<Vec<_>>();
35
36 frequencies.sort_unstable_by_key(|&(idx, freq)| (freq, idx));
37
38 frequencies
39 .windows(2)
40 .filter_map(|w| {
41 let (_, freq1) = w[0];
42 let (idx2, freq2) = w[1];
43 if freq1 == freq2 {
44 Some((idx2, freq1))
45 } else {
46 None
47 }
48 })
49 .min()
50 } else {
51 let mut remainders = self
52 .changes
53 .iter()
54 .enumerate()
55 .scan(0i32, |freq, (t, &change)| {
56 let curr = *freq;
57 *freq += change;
58 Some((curr.rem_euclid(self.total), curr, t))
59 })
60 .collect::<Vec<_>>();
61
62 remainders.sort_unstable();
63
64 remainders
65 .chunk_by(|&(r1, _, _), &(r2, _, _)| r1 == r2)
66 .flat_map(|chunk| {
67 chunk.iter().enumerate().flat_map(|(i, &r1)| {
68 chunk.iter().skip(i + 1).filter_map(move |&r2| {
69 let ((_, freq1, t1), (_, freq2, _)) =
70 if self.total > 0 { (r1, r2) } else { (r2, r1) };
71
72 let freq_difference = freq2 - freq1;
73 let iterations = freq_difference / self.total;
74 if freq_difference.rem_euclid(self.total) == 0 && iterations >= 0 {
75 let iterations = iterations as usize;
76 Some((iterations * self.changes.len() + t1, freq2))
77 } else {
78 None
79 }
80 })
81 })
82 })
83 .min()
84 }
85 .map(|(_, freq)| freq)
86 .expect("no solution found")
87 }
88}
89
90examples!(Day01 -> (i32, i32) [
91 {input: "+1\n-2\n+3\n+1", part1: 3, part2: 2},
92 {input: "+1\n+1\n+1", part1: 3},
93 {input: "+1\n+1\n-2", part1: 0},
94 {input: "-1\n-2\n-3", part1: -6},
95 {input: "+1\n-1", part2: 0},
96 {input: "+3\n+3\n+4\n-2\n-4", part2: 10},
97 {input: "-6\n+3\n+8\n+5\n-6", part2: 5},
98 {input: "+7\n+7\n-2\n-7\n-4", part2: 14},
99 {input: "-1\n+2\n-3\n-1", part1: -3, part2: -2},
101 {input: "-1\n+1", part2: 0},
102 {input: "-3\n-3\n-4\n+2\n+4", part2: -10},
103 {input: "+6\n-3\n-8\n-5\n+6", part2: -5},
104 {input: "-7\n-7\n+2\n+7\n+4", part2: -14},
105 {input: "+2\n+3\n-8", part2: 2},
107 {input: "+0", part2: 0},
108 {input: "+1000000\n-999999", part2: 1000000},
109 {input: "+1\n-2\n+2\n-2\n+3", part2: 1},
110 {input: "+1\n-2\n+2\n-2\n-5", part2: 1},
111]);