summaryrefslogtreecommitdiff
path: root/src/bin/day5.rs
blob: b396a6b6c743544d3a2450b2ce2fbd1d1c1d953b (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
115
116
use std::collections::HashMap;

fn main() {
    let input = advent::read_lines(5);
    println!("5a: {}", count_overlaps(&input, false));
    println!("5b: {}", count_overlaps(&input, true));
}

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

struct Line {
    start: Point,
    end: Point,
}

impl Point {
    fn new(coord: &str) -> Point {
        let (x_str, y_str) = coord.split_once(',').unwrap();
        let x = x_str.parse::<isize>().unwrap();
        let y = y_str.parse::<isize>().unwrap();
        Point { x, y }
    }
}

impl Line {
    fn new(points: &str) -> Line {
        let (start_str, end_str) = points.split_once(" -> ").unwrap();
        let (start, end) = (Point::new(start_str), Point::new(end_str));
        Line { start, end }
    }

    fn is_horizontal(&self) -> bool {
        self.start.y == self.end.y
    }

    fn is_vertical(&self) -> bool {
        self.start.x == self.end.x
    }

    fn points_on_line(&self) -> Vec<Point> {
        let mut points = Vec::new();

        let x_diff = self.end.x - self.start.x;
        let y_diff = self.end.y - self.start.y;

        if x_diff == 0 {
            /* vertical line */
            for y in 0 ..= y_diff.abs() {
                points.push(Point { x: self.start.x, y: self.start.y + y_diff.signum() * y });
            }
        } else if y_diff == 0 {
            /* horizontal line */
            for x in 0 ..= x_diff.abs() {
                points.push(Point { x: self.start.x + x_diff.signum() * x, y: self.start.y });
            }
        } else if x_diff.abs() == y_diff.abs() && x_diff.abs() > 0 {
            /* diagonal line */
            for i in 0 ..= x_diff.abs() {
                let x = self.start.x + x_diff.signum() * i;
                let y = self.start.y + y_diff.signum() * i;
                points.push(Point { x, y });
            }
        } else {
            panic!("No line!");
        }

        points
    }
}

fn count_overlaps<T: AsRef<str>>(input: &[T], with_diagonal: bool) -> usize {
    let lines : Vec<Line> = input.iter()
                                 .map(|line| Line::new(line.as_ref()))
                                 .collect();

    let mut map = HashMap::new();
    for line in lines {
        if !with_diagonal && !line.is_horizontal() && !line.is_vertical() {
            continue;
        }
        for point in line.points_on_line() {
            let count = map.entry(point).or_insert(0);
            *count += 1;
        }
    }
    map.values()
       .filter(|&count| *count > 1)
       .count()
}

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

    #[test]
    fn test() {
        let input = [
            "0,9 -> 5,9",
            "8,0 -> 0,8",
            "9,4 -> 3,4",
            "2,2 -> 2,1",
            "7,0 -> 7,4",
            "6,4 -> 2,0",
            "0,9 -> 2,9",
            "3,4 -> 1,4",
            "0,0 -> 8,8",
            "5,5 -> 8,2",
        ];
        assert_eq!(count_overlaps(&input, false), 5);
        assert_eq!(count_overlaps(&input, true), 12);
    }
}