Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/advent-of-code-2021
Path: blob/main/src/day19.rs
97 views
1
use std::collections::{HashMap, HashSet};
2
3
pub fn run() {
4
let scanners: Vec<Vec<Point>> = include_str!("inputs/day19")
5
.split("\n\n")
6
.map(|section| {
7
section
8
.lines()
9
.filter(|l| !l.starts_with("---"))
10
.map(parse_point)
11
.collect()
12
})
13
.collect();
14
15
let mut known_beacons = HashSet::new();
16
let mut scanner_positions = HashMap::new();
17
18
known_beacons.extend(&scanners[0]);
19
scanner_positions.insert(0, (0, 0, 0));
20
21
while scanner_positions.len() < scanners.len() {
22
for scanner_index in 1..scanners.len() {
23
if scanner_positions.contains_key(&scanner_index) {
24
continue;
25
}
26
let scanner = &scanners[scanner_index];
27
let rots: Vec<_> = scanner.iter().map(all_rotations).collect();
28
29
for rot_index in 0..rots[0].len() {
30
let mut dist_counts = HashMap::new();
31
for p in rots.iter().map(|rot| &rot[rot_index]) {
32
for known_point in known_beacons.iter() {
33
let d = sub(p, known_point);
34
*dist_counts.entry(d).or_insert(0) += 1;
35
}
36
}
37
38
if let Some((common_dist, _)) = dist_counts.iter().find(|&(_, count)| *count >= 12) {
39
let scanner_points = rots.iter().map(|rot| &rot[rot_index]);
40
known_beacons.extend(scanner_points.map(|p| sub(p, common_dist)));
41
scanner_positions.insert(scanner_index, *common_dist);
42
break;
43
}
44
}
45
}
46
}
47
println!("{}", known_beacons.len());
48
49
let max_dist = scanner_positions
50
.values()
51
.flat_map(|d1| scanner_positions.values().map(|d2| taxicab_dist(d1, d2)))
52
.max()
53
.unwrap();
54
println!("{}", max_dist);
55
}
56
57
type Point = (i32, i32, i32);
58
59
fn parse_point(s: &str) -> Point {
60
let ns: Vec<_> = s.split(",").map(|n| n.parse().unwrap()).collect();
61
(ns[0], ns[1], ns[2])
62
}
63
64
fn sub((x1, y1, z1): &Point, (x2, y2, z2): &Point) -> Point {
65
(x1 - x2, y1 - y2, z1 - z2)
66
}
67
68
fn all_rotations(&(x, y, z): &Point) -> [Point; 24] {
69
// There surely is an algorithmic way of getting these rotations but, oh well...
70
[
71
// z is "up"
72
(x, y, z),
73
(-y, x, z),
74
(-x, -y, z),
75
(y, -x, z),
76
// z is "down"
77
(x, -y, -z),
78
(y, x, -z),
79
(-x, y, -z),
80
(-y, -x, -z),
81
// y is "up"
82
(x, z, -y),
83
(y, z, x),
84
(-x, z, y),
85
(-y, z, -x),
86
// y is "down"
87
(x, -z, y),
88
(-y, -z, x),
89
(-x, -z, -y),
90
(y, -z, -x),
91
// x is "up"
92
(z, y, -x),
93
(z, x, y),
94
(z, -y, x),
95
(z, -x, -y),
96
// x is "down"
97
(-z, y, x),
98
(-z, -x, y),
99
(-z, -y, -x),
100
(-z, x, -y),
101
]
102
}
103
104
fn taxicab_dist((x1, y1, z1): &Point, (x2, y2, z2): &Point) -> i32 {
105
(x1 - x2).abs() + (y1 - y2).abs() + (z1 - z2).abs()
106
}
107
108