Skip to main content

year2020/
day10.rs

1use utils::bit::BitIterator;
2use utils::prelude::*;
3
4/// Counting paths through a sorted list of numbers.
5#[derive(Clone, Debug)]
6pub struct Day10 {
7    part1: u64,
8    part2: u64,
9}
10
11const MAX: usize = 255;
12
13impl Day10 {
14    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
15        let (mut count, mut adapters) = (0, [0u64; MAX.div_ceil(64)]);
16        for entry in parser::number_range(1..=MAX)
17            .with_eol()
18            .parse_iterator(input)
19        {
20            let n = entry?;
21            adapters[n / 64] |= 1 << (n % 64);
22            count += 1;
23        }
24
25        if count == 0 {
26            return Err(InputError::new(input, 0, "expected at least one adapter"));
27        }
28        if count != adapters.iter().map(|w| w.count_ones()).sum::<u32>() {
29            return Err(InputError::new(input, 0, "duplicate adapter"));
30        }
31
32        let (mut ones, mut threes) = (0u64, 1u64);
33
34        // ways[n] = arrangements ending n jolts below the previous adapter
35        let (mut previous, mut ways) = (0, [1u64, 0, 0]);
36
37        for (i, word) in adapters.into_iter().enumerate() {
38            for (bit, _) in BitIterator::ones(word) {
39                let jolts = i * 64 + bit as usize;
40
41                match jolts - previous {
42                    1 => {
43                        ones += 1;
44                        ways = [ways[0] + ways[1] + ways[2], ways[0], ways[1]];
45                    }
46                    2 => ways = [ways[0] + ways[1], 0, ways[0]],
47                    3 => {
48                        threes += 1;
49                        ways = [ways[0], 0, 0];
50                    }
51                    _ => return Err(InputError::new(input, 0, "expected a valid adapter chain")),
52                }
53                previous = jolts;
54            }
55        }
56
57        Ok(Self {
58            part1: ones * threes,
59            part2: ways[0],
60        })
61    }
62
63    #[must_use]
64    pub fn part1(&self) -> u64 {
65        self.part1
66    }
67
68    #[must_use]
69    pub fn part2(&self) -> u64 {
70        self.part2
71    }
72}
73
74examples!(Day10 -> (u64, u64) [
75    {file: "day10_example0.txt", part1: 35, part2: 8},
76    {file: "day10_example1.txt", part1: 220, part2: 19208},
77]);