1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day07 {
6 part1: u64,
7 part2: u64,
8}
9
10impl Day07 {
11 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
12 let parser = parser::u64()
13 .with_suffix(": ")
14 .then(parser::number_range(0u64..=999).repeat_arrayvec::<12, _>(b' ', 2))
15 .with_suffix(parser::eol());
16
17 let (mut part1, mut part2) = (0, 0);
18 for item in parser.parse_iterator(input) {
19 let (target, numbers) = item?;
20 if Self::possible(target, &numbers, false) {
21 part1 += target;
22 part2 += target;
23 } else if Self::possible(target, &numbers, true) {
24 part2 += target;
25 }
26 }
27
28 Ok(Self { part1, part2 })
29 }
30
31 #[must_use]
32 pub fn part1(&self) -> u64 {
33 self.part1
34 }
35
36 #[must_use]
37 pub fn part2(&self) -> u64 {
38 self.part2
39 }
40
41 #[inline]
42 fn possible(target: u64, numbers: &[u64], concat: bool) -> bool {
43 let (&next, numbers) = numbers.split_last().unwrap();
44 if numbers.is_empty() {
45 return target == next;
46 }
47
48 (target % next == 0 && Self::possible(target / next, numbers, concat))
49 || (concat && {
50 let pow = if next < 10 {
53 10
54 } else if next < 100 {
55 100
56 } else {
57 1000
58 };
59 target % pow == next && Self::possible(target / pow, numbers, concat)
60 })
61 || (target >= next && Self::possible(target - next, numbers, concat))
62 }
63}
64
65examples!(Day07 -> (u64, u64) [
66 {file: "day07_example0.txt", part1: 3749, part2: 11387},
67]);