summaryrefslogtreecommitdiff
path: root/src/day_5.rs
blob: acd2ac1f48122d138838cb61143902554fcc9372 (plain) (blame)
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
117
118
119
120
121
122
123
124
125
use std::cmp;
use std::convert::Infallible;
use std::str::FromStr;

const SIZE: usize = 1000;

#[derive(Debug)]
struct Line
{
    pub a: (u32, u32),
    pub b: (u32, u32),
}

fn part1(input: &[Line])
{
    let mut map = [[0; SIZE]; SIZE];
    for line in input {
        line.cast_vh(&mut map);
    }

    let num_intersections = map.iter().flatten().filter(|&n| *n >= 2).count();
    println!("Solution part 1: {}", num_intersections);
}

fn part2(input: &[Line])
{
    let mut map = [[0; SIZE]; SIZE];
    for line in input {
        line.cast_vh(&mut map);
        line.cast_diag(&mut map);
    }

    let num_intersections = map.iter().flatten().filter(|&n| *n >= 2).count();
    println!("Solution part 2: {}", num_intersections);
}

pub fn run(input: Vec<String>)
{
    let lines: Vec<Line> = input.iter().map(|s| Line::from_str(s).unwrap()).collect();

    part1(&lines);
    part2(&lines);
}

impl Line
{
    pub fn is_horizontal(&self) -> bool { self.a.1 == self.b.1 }

    pub fn is_vertical(&self) -> bool { self.a.0 == self.b.0 }

    pub fn cast_vh(&self, onto: &mut [[u8; SIZE]])
    {
        if self.is_horizontal() {
            let start = cmp::min(self.a.0, self.b.0);
            let end = cmp::max(self.a.0, self.b.0);
            for x in start..=end {
                onto[self.a.1 as usize][x as usize] += 1;
            }
        }
        else if self.is_vertical() {
            let start = cmp::min(self.a.1, self.b.1);
            let end = cmp::max(self.a.1, self.b.1);
            for y in start..=end {
                onto[y as usize][self.a.0 as usize] += 1;
            }
        }
    }

    pub fn cast_diag(&self, onto: &mut [[u8; SIZE]])
    {
        if self.is_horizontal() || self.is_vertical() {
            return;
        }

        // We know all other lines are 45 deg
        let mut dir = (0, 0);
        let len: i32 = if self.a.0 < self.b.0 {
            dir.0 = 1;
            (self.b.0 - self.a.0) as i32
        }
        else if self.a.0 > self.b.0 {
            dir.0 = -1;
            (self.a.0 - self.b.0) as i32
        }
        else {
            panic!("line is unexpectedly vertical!");
        };
        if self.a.1 < self.b.1 {
            dir.1 = 1;
        }
        else if self.a.1 > self.b.1 {
            dir.1 = -1;
        }
        else {
            panic!("line is unexpectedly horizontal!");
        }

        for i in 0..=len {
            onto[(self.a.1 as i32 + (i * dir.1)) as usize]
                [(self.a.0 as i32 + (i * dir.0)) as usize] += 1;
        }
    }
}

impl FromStr for Line
{
    type Err = Infallible;

    fn from_str(s: &str) -> Result<Self, Self::Err>
    {
        let parse_point = |s: &str| {
            let nums: Vec<u32> = s.split(',').map(|s| s.parse().unwrap()).collect();
            assert_eq!(nums.len(), 2);
            (nums[0], nums[1])
        };

        let points: Vec<(u32, u32)> = s.split(" -> ").map(|s| parse_point(s)).collect();
        assert_eq!(points.len(), 2);

        Ok(Line {
            a: points[0],
            b: points[1],
        })
    }
}