Skip to main content

aoc/year2024/
day03.rs

1//! # Mull It Over
2//!
3//! Solves both parts simultaneously using a custom parser instead of
4//! [regex](https://en.wikipedia.org/wiki/Regular_expression).
5use crate::util::parse::*;
6
7type Input = (u32, u32);
8
9pub fn parse(input: &str) -> Input {
10    let memory = input.as_bytes();
11    let mut index = 0;
12    let mut enabled = true;
13    let mut part_one = 0;
14    let mut part_two = 0;
15
16    while index < memory.len() {
17        // Skip junk characters.
18        if !matches!(memory[index], b'm' | b'd') {
19            index += 1;
20            continue;
21        }
22
23        // Check possible prefixes.
24        if memory[index..].starts_with(b"mul(") {
25            index += 4;
26        } else if memory[index..].starts_with(b"do()") {
27            index += 4;
28            enabled = true;
29            continue;
30        } else if memory[index..].starts_with(b"don't()") {
31            index += 7;
32            enabled = false;
33            continue;
34        } else {
35            index += 1;
36            continue;
37        }
38
39        // Parse first number.
40        let Some(first) = parse_number(memory, &mut index, b',') else { continue };
41        index += 1;
42
43        // Parse second number.
44        let Some(second) = parse_number(memory, &mut index, b')') else { continue };
45        index += 1;
46
47        // Multiply.
48        let product = first * second;
49        part_one += product;
50        part_two += product * u32::from(enabled);
51    }
52
53    (part_one, part_two)
54}
55
56pub fn part1(input: &Input) -> u32 {
57    input.0
58}
59
60pub fn part2(input: &Input) -> u32 {
61    input.1
62}
63
64fn parse_number(memory: &[u8], index: &mut usize, delimiter: u8) -> Option<u32> {
65    let mut number = 0;
66
67    while memory[*index].is_ascii_digit() {
68        number = 10 * number + memory[*index].to_decimal::<u32>();
69        *index += 1;
70    }
71
72    (memory[*index] == delimiter).then_some(number)
73}