Files
aoc2023/src/day01.rs
T

86 lines
2.6 KiB
Rust

use lazy_static::lazy_static;
use regex::Regex;
use crate::{utils::digit_value, Day};
// Register this day in our runner inventory
inventory::submit! {
Day { number: 1, run }
}
fn first_and_last_digit(s: &str) -> usize {
// Find the first ASCII digit in the string
let first = s.chars().filter_map(|c| c.to_digit(10)).next().unwrap() as usize; // Safe to use unwrap as a digit is always present
// Find the last ASCII digit in the string
let last = s
.chars()
.rev() // Reverse the iteration for the last digit
.filter_map(|c| c.to_digit(10))
.next()
.unwrap() as usize; // Safe to use unwrap here as well
// Combine the first and last digits to form a new number
first * 10 + last
}
lazy_static! {
static ref REGEX: Regex =
Regex::new(r"(?P<digit>zero|one|two|three|four|five|six|seven|eight|nine|\d)").unwrap();
}
fn first_and_last_digit_regex(s: &str) -> usize {
// Find the first digit in the string by testing against each sice from [0..] to [n-1..]
let first_digit = s
.char_indices()
.find_map(|(index, _)| REGEX.find(&s[index..]).map(|mat| mat.as_str().to_string()))
.unwrap(); // Safe to use unwrap because a digit is always expected
// Iterate from the end of the string, checking each slice for the last match
let last_digit = s
.char_indices()
.rev()
.find_map(|(index, _)| {
// Check if the slice from this index to the end of the string matches the regex
REGEX.find(&s[index..]).map(|mat| mat.as_str().to_string())
})
.unwrap(); // Safe to use unwrap as a digit is always expected
// Convert the found digits to numbers and calculate the result
digit_value(&first_digit) * 10 + digit_value(&last_digit)
}
fn day01_part1(input: &str) -> usize {
input.lines().map(first_and_last_digit).sum()
}
fn day01_part2(input: &str) -> usize {
input.lines().map(first_and_last_digit_regex).sum()
}
const INPUT: &str = include_str!("../data/day01.dat");
fn run() {
println!("{}", day01_part1(INPUT));
println!("{}", day01_part2(INPUT));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_day01_part1() {
let input = "1abc2\npqr3stu8vwx\na1b2c3d4e5f\ntreb7uchet";
assert_eq!(day01_part1(input), 142);
assert_eq!(day01_part1(INPUT), 54597);
}
#[test]
fn test_day01_part2() {
let input="two1nine\neightwothree\nabcone2threexyz\nxtwone3four\n4nineeightseven2\nzoneight234\n7pqrstsixteen";
assert_eq!(day01_part2(input), 281);
assert_eq!(day01_part2(INPUT), 54504);
}
}