tAoC2023/src/problems/day01/mod.rs
2023-12-03 08:40:13 +11:00

81 lines
2.1 KiB
Rust

use nom::{
branch::alt,
bytes::complete::tag,
character::{
complete::{anychar, line_ending, satisfy},
is_alphabetic,
},
combinator::{map, map_opt},
multi::{many1, separated_list1},
IResult,
};
pub mod inputs;
mod test;
type Int = u32;
type Line = (Vec<Int>, Vec<Int>);
fn parse_single_digit(input: &str) -> IResult<&str, Int> {
map_opt(anychar, |i: char| i.to_digit(10))(input)
}
fn parse_single_digit_or_word(input: &str) -> IResult<&str, Int> {
let (_, x) = alt((
map(tag("one"), |_| 1),
map(tag("two"), |_| 2),
map(tag("three"), |_| 3),
map(tag("four"), |_| 4),
map(tag("five"), |_| 5),
map(tag("six"), |_| 6),
map(tag("seven"), |_| 7),
map(tag("eight"), |_| 8),
map(tag("nine"), |_| 9),
parse_single_digit,
))(input)?;
let n = input.get(1..).unwrap_or("");
Ok((n, x))
}
fn parse_line_sub(
f: impl FnMut(&str) -> IResult<&str, Int>,
input: &str,
) -> IResult<&str, Vec<Option<Int>>> {
many1(alt((
map(f, Some),
map(satisfy(|c| is_alphabetic(c as u8)), |_| None),
)))(input)
}
fn parse_line(input: &str) -> IResult<&str, Line> {
let (_, i) = parse_line_sub(parse_single_digit, input)?;
let i: Vec<Int> = i.into_iter().flatten().collect();
let (out, j) = parse_line_sub(parse_single_digit_or_word, input)?;
let j: Vec<Int> = j.into_iter().flatten().collect();
Ok((out, (i, j)))
}
fn parse_input(input: &str) -> IResult<&str, Vec<Line>> {
let (res, out) = separated_list1(line_ending, parse_line)(input)?;
Ok((res, out))
}
pub fn solution(input: &str) -> Result<(Int, Int), String> {
let (_, input) = parse_input(input).map_err(|e| e.to_string())?;
let (a, b): (Int, Int) = input
.into_iter()
.map(|(ads, bds)| {
let f = |ds: Vec<Int>| {
if ds.is_empty() {
0
} else {
let n = ds.len() - 1;
(ds[0] * 10) + ds[n]
}
};
(f(ads), f(bds))
})
.fold((0, 0), |(a, b), (c, d)| (a + c, b + d));
Ok((a, b))
}