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.
4use std::array::from_fn;
5
6use crate::util::parse::*;
7
8type Input = (usize, usize);
9
10struct Item<'a> {
11    label: &'a [u8],
12    lens: usize,
13}
14
15pub fn parse(input: &str) -> Input {
16    let mut part_one = 0;
17    let mut part_two = 0;
18    let mut boxes: [Vec<Item<'_>>; 256] = from_fn(|_| Vec::new());
19
20    for step in input.trim().as_bytes().split(|&b| b == b',') {
21        part_one += hash(step);
22        let (&last, rest) = step.split_last().unwrap();
23
24        if last == b'-' {
25            // If the label exists then remove it.
26            boxes[hash(rest)].retain(|item| item.label != rest);
27        } else {
28            let label = &rest[..rest.len() - 1];
29            let slot = &mut boxes[hash(label)];
30            let lens = last.to_decimal();
31
32            // Replace or append new lens.
33            if let Some(i) = slot.iter().position(|item| item.label == label) {
34                slot[i].lens = lens;
35            } else {
36                slot.push(Item { label, lens });
37            }
38        }
39    }
40
41    for (i, next) in boxes.iter().enumerate() {
42        for (j, item) in next.iter().enumerate() {
43            part_two += (i + 1) * (j + 1) * item.lens;
44        }
45    }
46
47    (part_one, part_two)
48}
49
50pub fn part1(input: &Input) -> usize {
51    input.0
52}
53
54pub fn part2(input: &Input) -> usize {
55    input.1
56}
57
58/// Custom hash function.
59#[inline]
60fn hash(slice: &[u8]) -> usize {
61    slice.iter().fold(0, |acc, &b| ((acc + b as usize) * 17) & 0xff)
62}