aoc/year2023/
day01.rs

1//! # Trebuchet?!
2//!
3//! The input can contain overlapping digits such as "twone", so we only remove a letter at a time
4//! until the starting or ending digits are found.
5use crate::util::parse::*;
6
7/// Use the index of each digit as its implicit value.
8const DIGITS: [&[u8]; 9] =
9    [b"one", b"two", b"three", b"four", b"five", b"six", b"seven", b"eight", b"nine"];
10
11pub fn parse(input: &str) -> Vec<&[u8]> {
12    input.lines().map(str::as_bytes).collect()
13}
14
15pub fn part1(input: &[&[u8]]) -> u32 {
16    input
17        .iter()
18        .map(|line| {
19            let first = line.iter().find(|b| b.is_ascii_digit()).unwrap().to_decimal();
20            let last = line.iter().rfind(|b| b.is_ascii_digit()).unwrap().to_decimal();
21            (10 * first + last) as u32
22        })
23        .sum()
24}
25
26pub fn part2(input: &[&[u8]]) -> usize {
27    input
28        .iter()
29        .map(|line| {
30            let digit = |i: usize| -> Option<usize> {
31                if line[i].is_ascii_digit() {
32                    return Some(line[i].to_decimal() as usize);
33                }
34
35                for (value, digit) in DIGITS.iter().enumerate() {
36                    if line[i..].starts_with(digit) {
37                        return Some(value + 1);
38                    }
39                }
40
41                None
42            };
43
44            let first = (0..line.len()).find_map(digit).unwrap();
45            let last = (0..line.len()).rev().find_map(digit).unwrap();
46            10 * first + last
47        })
48        .sum()
49}