summaryrefslogtreecommitdiffstats
path: root/src/bin/2021/day5.rs
blob: 68bca56985437ccbb7d7086ac69280634b5d1072 (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
use advent_of_code::prelude::*;

#[derive(Default, Clone)]
struct Map {
    grid: Grid<i64>,
}

impl Map {
    fn mark_horizontal(
        &mut self,
        x1: usize,
        y1: usize,
        x2: usize,
        y2: usize,
    ) -> bool {
        self.grid
            .grow(Row((y1 + 1).max(y2 + 1)), Col((x1 + 1).max(x2 + 1)));
        if x1 == x2 {
            for y in y1.min(y2)..=y1.max(y2) {
                self.grid[Row(y)][Col(x1)] += 1;
            }
            true
        } else {
            false
        }
    }

    fn mark_vertical(
        &mut self,
        x1: usize,
        y1: usize,
        x2: usize,
        y2: usize,
    ) -> bool {
        self.grid
            .grow(Row((y1 + 1).max(y2 + 1)), Col((x1 + 1).max(x2 + 1)));
        if y1 == y2 {
            for x in x1.min(x2)..=x1.max(x2) {
                self.grid[Row(y1)][Col(x)] += 1;
            }
            true
        } else {
            false
        }
    }

    fn mark_diagonal(
        &mut self,
        x1: usize,
        y1: usize,
        x2: usize,
        y2: usize,
    ) -> bool {
        if x1.max(x2) - x1.min(x2) == y1.max(y2) - y1.min(y2) {
            for i in 0..=(x1.max(x2) - x1.min(x2)) {
                if x1 > x2 && y1 > y2 || x1 < x2 && y1 < y2 {
                    self.grid[Row(y1.min(y2) + i)][Col(x1.min(x2) + i)] += 1;
                } else if x1 > x2 {
                    self.grid[Row(y2 - i)][Col(x2 + i)] += 1;
                } else {
                    self.grid[Row(y1 - i)][Col(x1 + i)] += 1;
                }
            }
            true
        } else {
            false
        }
    }

    fn count_overlapping(&self) -> usize {
        self.grid.cells().filter(|x| **x >= 2).count()
    }
}

pub fn parse(fh: File) -> Result<impl Iterator<Item = Vec<usize>>> {
    Ok(parse::raw_lines(fh).map(move |line| {
        regex_captures!(r"^(\d+),(\d+) -> (\d+),(\d+)$", &line)
            .unwrap()
            .iter()
            .skip(1)
            .map(|s| s.unwrap().as_str().parse())
            .collect::<Result<_, _>>()
            .unwrap()
    }))
}

pub fn part1(coords: impl Iterator<Item = Vec<usize>>) -> Result<usize> {
    let mut map = Map::default();
    for nums in coords {
        let _ = map.mark_horizontal(nums[0], nums[1], nums[2], nums[3])
            || map.mark_vertical(nums[0], nums[1], nums[2], nums[3]);
    }
    Ok(map.count_overlapping())
}

pub fn part2(coords: impl Iterator<Item = Vec<usize>>) -> Result<usize> {
    let mut map = Map::default();
    for nums in coords {
        if map.mark_horizontal(nums[0], nums[1], nums[2], nums[3]) {
            continue;
        }
        if map.mark_vertical(nums[0], nums[1], nums[2], nums[3]) {
            continue;
        }
        if map.mark_diagonal(nums[0], nums[1], nums[2], nums[3]) {
            continue;
        }
        unreachable!();
    }
    Ok(map.count_overlapping())
}

#[test]
fn test() {
    assert_eq!(
        part1(parse(parse::data(2021, 5).unwrap()).unwrap()).unwrap(),
        6311
    );
    assert_eq!(
        part2(parse(parse::data(2021, 5).unwrap()).unwrap()).unwrap(),
        19929
    );
}