-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathday_09.rs
More file actions
100 lines (87 loc) 路 2.41 KB
/
Copy pathday_09.rs
File metadata and controls
100 lines (87 loc) 路 2.41 KB
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
use std::{cmp::Reverse, iter};
use common::{Answer, solution};
use itertools::Itertools;
use nd_vec::{Vec2, vector};
solution!("Movie Theater", 9);
fn part_a(input: &str) -> Answer {
(parse(input).iter())
.tuple_combinations()
.map(|(a, b)| area(a, b))
.max()
.unwrap()
.into()
}
fn part_b(input: &str) -> Answer {
let red = parse(input);
red.iter()
.tuple_combinations()
.map(|(a, b)| (area(a, b), (a, b)))
.sorted_by_key(|(area, _)| Reverse(*area))
.find(|(_area, (a, b))| {
let bounds = bounds(a, b);
!red.iter()
.chain(iter::once(&red[0]))
.tuple_windows()
.any(|line| intersecting_line(line, bounds))
})
.unwrap()
.0
.into()
}
fn parse(input: &str) -> Vec<Vec2<u64>> {
(input.lines())
.map(|x| {
let (x, y) = x.split_once(',').unwrap();
vector!(x.parse().unwrap(), y.parse().unwrap())
})
.collect::<Vec<_>>()
}
fn area(a: &Vec2<u64>, b: &Vec2<u64>) -> u64 {
(a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1)
}
fn bounds(a: &Vec2<u64>, b: &Vec2<u64>) -> (Vec2<u64>, Vec2<u64>) {
(
vector!(a.x().min(b.x()), a.y().min(b.y())),
vector!(a.x().max(b.x()), a.y().max(b.y())),
)
}
fn intersecting_line(
(la, lb): (&Vec2<u64>, &Vec2<u64>),
(min, max): (Vec2<u64>, Vec2<u64>),
) -> bool {
let (lmin, lmax) = bounds(la, lb);
la.x() == lb.x() // horizontal line
&& (((lmin.y() < min.y() && lmax.y() > min.y())
|| (lmin.y() < max.y() && lmax.y() > max.y())
|| (lmin.y() >= min.y() && lmax.y() <= max.y()))
&& la.x() > min.x()
&& la.x() < max.x())
|| la.y() == lb.y() // vertical line
&& (((lmin.x() < min.x() && lmax.x() > min.x())
|| (lmin.x() < max.x() && lmax.x() > max.x())
|| (lmin.x() >= min.x() && lmax.x() <= max.x()))
&& la.y() > min.y()
&& la.y() < max.y())
}
#[cfg(test)]
mod test {
use indoc::indoc;
const CASE: &str = indoc! {"
7,1
11,1
11,7
9,7
9,5
2,5
2,3
7,3
"};
#[test]
fn part_a() {
assert_eq!(super::part_a(CASE), 50.into());
}
#[test]
fn part_b() {
assert_eq!(super::part_b(CASE), 24.into());
}
}