advent_of_code/year2020/
day10.rs1use crate::input::Input;
2
3type JoltageAmount = u64;
4
5pub fn solve(input: &Input) -> Result<JoltageAmount, String> {
6 const MAX_DIFF: JoltageAmount = 3;
9
10 let mut joltages = std::iter::once(Ok(0))
11 .chain(input.text.lines().enumerate().map(|(line_idx, line)| {
12 line.parse::<JoltageAmount>().map_err(|parse_error| {
13 format!("Line {}: Invalid joltage - {}", line_idx + 1, parse_error)
14 })
15 }))
16 .collect::<Result<Vec<_>, _>>()?;
17
18 joltages.sort_unstable();
19
20 joltages.push(joltages[joltages.len() - 1] + MAX_DIFF);
23
24 if input.is_part_one() {
25 joltages
26 .windows(2)
27 .try_fold([0; MAX_DIFF as usize + 1], |mut diff_count, window| {
28 let diff = window[1] - window[0];
29 if diff > MAX_DIFF {
30 Err(format!(
31 "Too big difference between adapters - cannot go from {} to {}",
32 window[0], window[1]
33 ))
34 } else {
35 diff_count[diff as usize] += 1;
36 Ok(diff_count)
37 }
38 })
39 .map(|diff_counts| diff_counts[1] * diff_counts[3])
40 } else {
41 let mut distinct_ways_counts = vec![0; joltages.len()];
42 distinct_ways_counts[0] = 1;
43
44 for (idx, joltage) in joltages.iter().enumerate() {
45 let this_distinct_count = distinct_ways_counts[idx];
46
47 joltages[(idx + 1)..]
48 .iter()
49 .take_while(|&higher_joltage| higher_joltage - joltage <= MAX_DIFF)
50 .enumerate()
51 .for_each(|(offset, _)| {
52 distinct_ways_counts[idx + offset + 1] += this_distinct_count;
53 });
54 }
55
56 Ok(distinct_ways_counts[distinct_ways_counts.len() - 1])
57 }
58}
59
60#[test]
61pub fn tests() {
62 use crate::input::{test_part_one, test_part_one_error, test_part_two};
63
64 let example = "16\n10\n15\n5\n1\n11\n7\n19\n6\n12\n4";
65 test_part_one!(example => 35);
66 test_part_two!(example => 8);
67
68 test_part_one_error!(" " => "Line 1: Invalid joltage - invalid digit found in string");
69 test_part_one_error!("100" => "Too big difference between adapters - cannot go from 0 to 100");
70 test_part_one!("1" => 1);
71 test_part_two!("1" => 1);
72
73 let real_input = include_str!("day10_input.txt");
74 test_part_one!(real_input => 2376);
75 test_part_two!(real_input => 129_586_085_429_248);
76}