summaryrefslogtreecommitdiff
path: root/2023/src/bin/day_1.rs
blob: fe3ef1ebe254a831bcfd6a94a81df4491235a486 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{alpha1, anychar, line_ending, none_of, one_of},
    combinator::{map, map_opt, map_res, opt, peek, value},
    multi::{many1, separated_list1},
    sequence::pair,
    IResult,
};
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = fs::read_to_string("inputs/day_1.txt")?;
    let parsed = CalibrationInput::parser(&input).unwrap().1;
    dbg!(parsed.calibration_sum());

    Ok(())
}

#[derive(Debug)]
struct CalibrationInput(Vec<CalibrationValue>);

#[derive(Debug)]
struct CalibrationValue(u32);

#[derive(Debug)]
struct CalibrationDigit(u8);

impl CalibrationInput {
    fn calibration_sum(&self) -> u32 {
        self.0.iter().map(|d| d.0).sum()
    }

    fn parser(input: &str) -> IResult<&str, Self> {
        map(
            separated_list1(line_ending, CalibrationValue::parser),
            CalibrationInput,
        )(input)
    }
}

impl CalibrationValue {
    fn parser(input: &str) -> IResult<&str, Self> {
        map(
            many1(pair(
                opt(peek(CalibrationDigit::parser)), // peek is to not consume the 'one' in 'twone'
                none_of("\n"),                       // this is just to advance the input
            )),
            |digits| {
                let digits: Vec<u32> = digits
                    .into_iter()
                    .filter_map(|(d, _)| d.map(|d| d.0 as u32))
                    .collect();
                CalibrationValue(digits[0] * 10 + digits[digits.len() - 1])
            },
        )(input)
    }
}

impl CalibrationDigit {
    fn parser(input: &str) -> IResult<&str, Self> {
        map(
            alt((
                map(one_of("0123456789"), |c| {
                    c.to_string().parse::<u8>().unwrap()
                }),
                value(0, tag("zero")),
                value(1, tag("one")),
                value(2, tag("two")),
                value(3, tag("three")),
                value(4, tag("four")),
                value(5, tag("five")),
                value(6, tag("six")),
                value(7, tag("seven")),
                value(8, tag("eight")),
                value(9, tag("nine")),
            )),
            CalibrationDigit,
        )(input)
    }
}