advent-of-code/2023/rust/src/day1.rs

147 lines
4.1 KiB
Rust

use crate::prelude::*;
mod prelude;
fn main() {
Day1::show(day_input(1), day_input(1))
}
struct Day1 {}
impl Day1 {
fn calibration_value(line: &str) -> i128 {
println!("{line}");
let bytes = line.as_bytes();
let mut first_digit: Option<u8> = None;
let mut last_digit: Option<u8> = None;
for i in 0..bytes.len() {
let n = bytes.len() - 1 - i;
println!("{n} {i}");
if first_digit.is_none() && (0x30..=0x39).contains(&bytes[i]) {
first_digit = Some(bytes[i] - 0x30);
println!("found first {first_digit:?}");
}
if last_digit.is_none() && (0x30..=0x39).contains(&bytes[n]) {
last_digit = Some(bytes[n] - 0x30);
println!("found last {last_digit:?}");
}
if first_digit.is_some() && last_digit.is_some() {
break;
}
}
println!("{:?} {:?}", first_digit, last_digit);
Into::<i128>::into(first_digit.or(last_digit).unwrap() * 10)
+ Into::<i128>::into(last_digit.or(first_digit).unwrap())
}
fn num_name(s: &[u8]) -> Option<u8> {
for (i, w) in [
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
]
.map(|s| s.as_bytes())
.iter()
.enumerate()
{
if s.starts_with(w) {
return Some(i as u8);
}
}
return None;
}
fn num_name_end(s: &[u8]) -> Option<u8> {
for (i, w) in [
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
]
.map(|s| s.as_bytes())
.iter()
.enumerate()
{
if s.ends_with(w) {
return Some(i as u8);
}
}
return None;
}
fn calibration_value_words(line: &str) -> i128 {
println!("{line}");
let bytes = line.as_bytes();
let mut first_digit: Option<u8> = None;
let mut last_digit: Option<u8> = None;
for i in 0..bytes.len() {
let n = bytes.len() - 1 - i;
println!("NI: {n} {i}");
if first_digit.is_none() {
if (0x30..=0x39).contains(&bytes[i]) {
first_digit = Some(bytes[i] - 0x30);
println!("found first {first_digit:?}");
} else if let Some(n) = Self::num_name(&bytes[i..]) {
first_digit = Some(n);
println!("found first text {first_digit:?}");
}
}
if last_digit.is_none() {
println!("{:?}", &bytes[..=n]);
if (0x30..=0x39).contains(&bytes[n]) {
last_digit = Some(bytes[n] - 0x30);
println!("found last {last_digit:?}");
} else if let Some(n) = Self::num_name_end(&bytes[..=n]) {
last_digit = Some(n);
println!("found last text {last_digit:?}");
}
}
if first_digit.is_some() && last_digit.is_some() {
break;
}
}
println!("{:?} {:?}", first_digit, last_digit);
Into::<i128>::into(first_digit.or(last_digit).unwrap() * 10)
+ Into::<i128>::into(last_digit.or(first_digit).unwrap())
}
}
impl AoCSolution for Day1 {
type Input = String;
type Solution = i128;
fn part1(input: Self::Input) -> Self::Solution {
input.lines().map(Self::calibration_value).sum()
}
fn part2(input: Self::Input) -> Self::Solution {
input.lines().map(Self::calibration_value_words).sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
assert_eq!(
Day1::part1(
r#"1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet"#
.into()
),
142
);
assert_eq!(
Day1::part2(
r#"two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen"#
.into()
),
281
);
}
}