summaryrefslogtreecommitdiffstats
path: root/day2/src/main.rs
blob: 15d0224bc01729373c89a3a72598b5680e03de59 (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
104
105
106
107
108
109
110
111
112
113
114
use std::io::{BufReader, Read};
use aoc::Day;

struct Day2{}

impl Day2 {
    fn part_n(&self, input: BufReader<Box<dyn Read>>) -> Vec<Vec<i32>> {
        self.read_lines(input)
            .iter()
            .map(|l| {
                l.split_whitespace().map(|c| {
                    c.parse::<i32>().unwrap()
                })
                .collect()
            })
            .collect()
    }

    fn is_safe(&self, line: &Vec<i32>) -> Result<bool, usize> {
        let mut last: Option<&i32> = None;
        let mut ascending: Option<bool> = None;

        for (index, i) in line.iter().enumerate() {
            if let Some(l) = last {
                let abs_diff = l.abs_diff(*i);


                if abs_diff < 1 || abs_diff > 3 {
                    return Err(index)
                }

                if let Some(asc) = ascending {
                    let diff = i - l;

                    if (asc && diff < 0) || (!asc && diff > 0) {
                        return Err(index)
                    }

                } else {
                    ascending = Some(i > l);
                }
            }

            last = Some(i);
        }

        Ok(true)
    }
}

impl Day for Day2 {
    fn example_input(&self) -> &'static str {
        r#"
        7 6 4 2 1
        1 2 7 8 9
        9 7 6 2 1
        1 3 2 4 5
        8 6 4 4 1
        1 3 6 7 9
        "#.trim()
    }

    fn example_result_part_1(&self) -> &'static str {
        "2"
    }

    fn example_result_part_2(&self) -> &'static str {
        "4"
    }

    fn part_1(&self, input: BufReader<Box<dyn Read>>) -> String {
        self.part_n(input)
            .iter()
            .filter(|&l| self.is_safe(l).unwrap_or(false))
            .count()
            .to_string()
    }

    fn part_2(&self, input: BufReader<Box<dyn Read>>) -> String {
        self.part_n(input)
            .iter()
            .filter(|&l| {
                match self.is_safe(l) {
                    Ok(val) => val,
                    Err(_index) => {
                        l
                            .iter()
                            .enumerate()
                            .map(|(index, _)| {
                                let mut copy = l.clone();
                                copy.remove(index);
                                self.is_safe(&copy).unwrap_or(false)
                            })
                            .any(|val| val)
                    },
                }
            })
            .count()
            .to_string()
    }
}

fn main() {
    aoc::main(&Day2 {});
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_day2() {
        aoc::test_day(&Day2 {});
    }
}