Skip to main content

year2020/
day01.rs

1use utils::prelude::*;
2
3/// Finding pairs and triples that sum to a target value.
4#[derive(Clone, Debug)]
5pub struct Day01 {
6    present: [bool; TARGET as usize + 1],
7    values: Vec<u32>,
8}
9
10const TARGET: u32 = 2020;
11
12impl Day01 {
13    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
14        let mut present = [false; TARGET as usize + 1];
15        let mut values = Vec::with_capacity(1024);
16
17        for entry in parser::number_range(0..=TARGET)
18            .with_consumed()
19            .with_eol()
20            .parse_iterator(input)
21        {
22            let (num, line) = entry?;
23
24            if present[num as usize] {
25                return Err(InputError::new(input, line, "duplicate number"));
26            }
27            present[num as usize] = true;
28
29            if num < TARGET / 2 {
30                values.push(num);
31            }
32        }
33        values.sort_unstable();
34
35        Ok(Self { present, values })
36    }
37
38    #[must_use]
39    pub fn part1(&self) -> u64 {
40        for &a in &self.values {
41            let b = TARGET - a;
42            if self.present[b as usize] {
43                return u64::from(a) * u64::from(b);
44            }
45        }
46        panic!("no solution found")
47    }
48
49    #[must_use]
50    pub fn part2(&self) -> u64 {
51        for (i, &a) in self.values.iter().enumerate() {
52            for &b in &self.values[i + 1..] {
53                let c = TARGET - a - b;
54                if c <= b {
55                    break;
56                }
57                if self.present[c as usize] {
58                    return u64::from(a) * u64::from(b) * u64::from(c);
59                }
60            }
61        }
62        panic!("no solution found")
63    }
64}
65
66examples!(Day01 -> (u64, u64) [
67    {input: "1721\n979\n366\n299\n675\n1456", part1: 514579, part2: 241861950},
68]);