Skip to main content

aoc/year2023/
day15.rs

1//! # Lens Library
2//!
3//! Calculates part one and two at the same time as a speed optimization. Assumes labels are always
4//! 8 characters or fewer.
5use std::array::from_fn;
6
7use crate::util::parse::*;
8
9type Input = (usize, usize);
10
11struct Item {
12    label: usize,
13    lens: usize,
14}
15
16pub fn parse(input: &str) -> Input {
17    let input = input.trim().as_bytes();
18
19    let mut part_one = 0;
20    let mut part_two = 0;
21    let mut hash = 0;
22    let mut label = 0;
23    let mut boxes: [Vec<Item>; 256] = from_fn(|_| Vec::new());
24
25    for (i, &b) in input.iter().enumerate() {
26        match b {
27            b',' => {
28                part_one += hash;
29                hash = 0;
30                label = 0;
31                continue;
32            }
33            b'-' => boxes[hash].retain(|item| item.label != label),
34            b'=' => {
35                let lens = input[i + 1].to_decimal();
36                let slot = &mut boxes[hash];
37
38                match slot.iter_mut().find(|item| item.label == label) {
39                    Some(item) => item.lens = lens,
40                    None => slot.push(Item { label, lens }),
41                }
42            }
43            _ => (),
44        }
45
46        let u = usize::from(b);
47        hash = ((hash + u) * 17) & 0xff;
48        label = (label << 8) | u;
49    }
50
51    for (i, next) in boxes.iter().enumerate() {
52        for (j, item) in next.iter().enumerate() {
53            part_two += (i + 1) * (j + 1) * item.lens;
54        }
55    }
56
57    // The final step has no trailing comma.
58    (part_one + hash, part_two)
59}
60
61pub fn part1(input: &Input) -> usize {
62    input.0
63}
64
65pub fn part2(input: &Input) -> usize {
66    input.1
67}