summaryrefslogtreecommitdiff
path: root/src/bin/day3.rs
blob: 53c77c9d3ad61945b79f63c3c776884aa72794be (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
use std::collections::HashMap;

static DAY: u8 = 3;

fn main() {
    let input = advent::read_lines(DAY);
    println!("{DAY}a: {}", part_sum(&input));
    println!("{DAY}b: {}", 0);
}

#[derive(Eq, PartialEq, Hash)]
struct Position {
    x: isize,
    y: isize,
}

struct Schematics {
    map: HashMap<Position, char>,
}

impl Schematics {
    fn new(input: &[String]) -> Schematics {
        let mut map = HashMap::new();
        for (y, line) in input.iter().enumerate() {
            for (x, c) in line.chars().enumerate() {
                if c != '.' {
                    map.insert(Position { x: x as isize, y: y as isize }, c);
                }
            }
        }
        Schematics { map }
    }

    fn has_neighboring_part(&self, pos: &Position) -> bool {
        for y in -1 ..= 1 {
            for x in -1 ..= 1 {
                if let Some(obj) = self.map.get(&Position { x: pos.x + x, y: pos.y + y }) {
                    if !obj.is_ascii_digit() {
                        return true;
                    }
                }
            }
        }
        false
    }
}

fn part_sum(input: &[String]) -> u32 {
    let schematics = Schematics::new(input);
    let mut part_numbers = Vec::new();

    for (y, line) in input.iter().enumerate() {
        let mut number = 0;
        let mut is_part_number = false;
        for (x, c) in line.chars().enumerate() {
            if let Some(digit) = c.to_digit(10) {
                number *= 10;
                number += digit;
                if schematics.has_neighboring_part(&Position { x: x as isize, y: y as isize }) {
                    is_part_number = true;
                }
            } else if number > 0 {
                /* number ended within a line */
                if is_part_number {
                    part_numbers.push(number);
                }
                number = 0;
                is_part_number = false;
            }
        }
        if number > 0 && is_part_number {
            /* number ended at the end of line */
            part_numbers.push(number);
        }
    }

    part_numbers.iter()
                .sum()
}

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

    #[test]
    fn test() {
        let input = [
            "467..114..",
            "...*......",
            "..35..633.",
            "......#...",
            "617*......",
            ".....+.58.",
            "..592.....",
            "......755.",
            "...$.*....",
            ".664.598..",
        ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
        assert_eq!(part_sum(&input), 4361);
    }
}