summaryrefslogtreecommitdiffstats
path: root/src/day_01.rs
blob: 9c0310e183ecc25a2ae1571993760ee508274c45 (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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use anyhow::Context;

use crate::{Problem, Solution};

pub struct Day01;

impl Problem for Day01 {
    const DAY: u8 = 1;

    const INPUT: &'static str = include_str!("../input/day_01.txt");
}

impl Solution for Day01 {
    type Answer1 = usize;

    type Answer2 = usize;

    fn part_1(input: &str) -> anyhow::Result<Self::Answer1> {
        input.trim().split('\n').try_fold(0, |acc, line| {
            let first = line
                .chars()
                .find_map(|c| c.to_digit(10).map(|n| n as usize))
                .context("Failed to find first number")?;

            let last = line
                .chars()
                .rev()
                .find_map(|c| c.to_digit(10).map(|n| n as usize))
                .unwrap_or(first);

            Ok(acc + first * 10 + last)
        })
    }

    fn part_2(input: &str) -> anyhow::Result<Self::Answer2> {
        let words = [
            "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
        ];

        input.trim().split('\n').try_fold(0, |acc, line| {
            let mut buf = String::new();
            let first = line
                .chars()
                .find_map(|c| {
                    buf.push(c);
                    words
                        .iter()
                        .enumerate()
                        .find_map(|(n, w)| buf.contains(w).then_some(n))
                        .or_else(|| c.to_digit(10).map(|n| n as usize))
                })
                .context("Failed to find first number")?;

            buf.clear();
            let last = line
                .chars()
                .rev()
                .find_map(|c| {
                    buf.insert(0, c);
                    words
                        .iter()
                        .enumerate()
                        .find_map(|(n, w)| buf.contains(w).then_some(n))
                        .or_else(|| c.to_digit(10).map(|n| n as usize))
                })
                .unwrap_or(first);

            Ok(acc + first * 10 + last)
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_part_1() -> anyhow::Result<()> {
        let input = indoc::indoc! {"
            1abc2
            pqr3stu8vwx
            a1b2c3d4e5f
            treb7uchet
        "};

        Ok(assert_eq!(142, Day01::part_1(input)?))
    }

    #[test]
    fn test_part_2() -> anyhow::Result<()> {
        let input = indoc::indoc! {"
            two1nine
            eightwothree
            abcone2threexyz
            xtwone3four
            4nineeightseven2
            zoneight234
            7pqrstsixteen
        "};

        Ok(assert_eq!(281, Day01::part_2(input)?))
    }
}