tangled
alpha
login
or
join now
jonas.tngl.sh
/
advent-of-code
0
fork
atom
Advent of Code solutions in Rust
0
fork
atom
overview
issues
pulls
pipelines
feat: day 8 of AoC 2025
jonas.tngl.sh
3 months ago
9212c73d
76174d2c
1/1
rust.yml
success
3m 17s
+144
-2
2 changed files
expand all
collapse all
unified
split
aoc_2025
src
day08.rs
main.rs
+142
aoc_2025/src/day08.rs
···
1
1
+
use std::num::ParseIntError;
2
2
+
3
3
+
use aoc_companion::prelude::*;
4
4
+
use aoc_utils::linalg::{ParseVectorError, Vector};
5
5
+
use itertools::Itertools as _;
6
6
+
7
7
+
pub(crate) struct Door {
8
8
+
boxes: Vec<Vector<i64, 3>>,
9
9
+
}
10
10
+
11
11
+
impl<'input> Solution<'input> for Door {
12
12
+
fn parse(input: &'input str) -> Result<Self, ParseVectorError<ParseIntError>> {
13
13
+
input
14
14
+
.lines()
15
15
+
.map(str::parse)
16
16
+
.try_collect()
17
17
+
.map(|boxes| Door { boxes })
18
18
+
}
19
19
+
20
20
+
fn part1(&self) -> usize {
21
21
+
networks(&self.boxes, 1000)
22
22
+
.iter()
23
23
+
.counts()
24
24
+
.into_values()
25
25
+
.sorted()
26
26
+
.rev()
27
27
+
.take(3)
28
28
+
.product()
29
29
+
}
30
30
+
31
31
+
fn part2(&self) -> i64 {
32
32
+
let (Vector([x1, _, _]), Vector([x2, _, _])) = final_connection(&self.boxes);
33
33
+
x1 * x2
34
34
+
}
35
35
+
}
36
36
+
37
37
+
fn networks(boxes: &[Vector<i64, 3>], n_connect: usize) -> Vec<usize> {
38
38
+
boxes
39
39
+
.iter()
40
40
+
.enumerate()
41
41
+
.tuple_combinations()
42
42
+
.sorted_unstable_by_key(|((_, pi), (_, pj))| (**pi - **pj).norm_l2_sq())
43
43
+
.take(n_connect)
44
44
+
.fold(
45
45
+
(0..boxes.len()).collect_vec(),
46
46
+
|mut assoc, ((i, _), (j, _))| {
47
47
+
update_network_associations(&mut assoc, i, j);
48
48
+
assoc
49
49
+
},
50
50
+
)
51
51
+
}
52
52
+
53
53
+
fn final_connection(boxes: &[Vector<i64, 3>]) -> (Vector<i64, 3>, Vector<i64, 3>) {
54
54
+
boxes
55
55
+
.iter()
56
56
+
.enumerate()
57
57
+
.tuple_combinations()
58
58
+
.sorted_unstable_by_key(|((_, pi), (_, pj))| (**pi - **pj).norm_l2_sq())
59
59
+
.scan(
60
60
+
((0..boxes.len()).collect_vec(), boxes.len()),
61
61
+
|(assoc, n_grp), ((i, pi), (j, pj))| {
62
62
+
if update_network_associations(assoc, i, j) == UpdateOutcome::NetworksConnected {
63
63
+
*n_grp -= 1;
64
64
+
}
65
65
+
Some(((*pi, *pj), *n_grp))
66
66
+
},
67
67
+
)
68
68
+
.find(|(_, n_grp)| *n_grp == 1)
69
69
+
.expect("at least 2 junction boxes should be present")
70
70
+
.0
71
71
+
}
72
72
+
73
73
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74
74
+
enum UpdateOutcome {
75
75
+
AlreadyConnected,
76
76
+
NetworksConnected,
77
77
+
}
78
78
+
79
79
+
fn update_network_associations(assoc: &mut [usize], i: usize, j: usize) -> UpdateOutcome {
80
80
+
let lhs = assoc[i];
81
81
+
let rhs = assoc[j];
82
82
+
83
83
+
if lhs != rhs {
84
84
+
assoc
85
85
+
.iter_mut()
86
86
+
.filter(|x| **x == rhs)
87
87
+
.for_each(|x| *x = lhs);
88
88
+
89
89
+
UpdateOutcome::NetworksConnected
90
90
+
} else {
91
91
+
UpdateOutcome::AlreadyConnected
92
92
+
}
93
93
+
}
94
94
+
95
95
+
#[cfg(test)]
96
96
+
mod tests {
97
97
+
use super::*;
98
98
+
99
99
+
const EXAMPLE_BOXES: &[Vector<i64, 3>] = &[
100
100
+
Vector([162, 817, 812]),
101
101
+
Vector([57, 618, 57]),
102
102
+
Vector([906, 360, 560]),
103
103
+
Vector([592, 479, 940]),
104
104
+
Vector([352, 342, 300]),
105
105
+
Vector([466, 668, 158]),
106
106
+
Vector([542, 29, 236]),
107
107
+
Vector([431, 825, 988]),
108
108
+
Vector([739, 650, 466]),
109
109
+
Vector([52, 470, 668]),
110
110
+
Vector([216, 146, 977]),
111
111
+
Vector([819, 987, 18]),
112
112
+
Vector([117, 168, 530]),
113
113
+
Vector([805, 96, 715]),
114
114
+
Vector([346, 949, 466]),
115
115
+
Vector([970, 615, 88]),
116
116
+
Vector([941, 993, 340]),
117
117
+
Vector([862, 61, 35]),
118
118
+
Vector([984, 92, 344]),
119
119
+
Vector([425, 690, 689]),
120
120
+
];
121
121
+
122
122
+
#[test]
123
123
+
fn example_network_counts() {
124
124
+
itertools::assert_equal(
125
125
+
networks(EXAMPLE_BOXES, 10)
126
126
+
.iter()
127
127
+
.counts()
128
128
+
.into_values()
129
129
+
.sorted()
130
130
+
.rev(),
131
131
+
[5, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1],
132
132
+
);
133
133
+
}
134
134
+
135
135
+
#[test]
136
136
+
fn example_final_connection() {
137
137
+
assert_eq!(
138
138
+
final_connection(EXAMPLE_BOXES),
139
139
+
(Vector([216, 146, 977]), Vector([117, 168, 530]))
140
140
+
)
141
141
+
}
142
142
+
}
+2
-2
aoc_2025/src/main.rs
···
7
7
mod day05;
8
8
mod day06;
9
9
mod day07;
10
10
-
// mod day08;
10
10
+
mod day08;
11
11
// mod day09;
12
12
// mod day10;
13
13
// mod day11;
···
25
25
door!(2025-12-05 ~> day05),
26
26
door!(2025-12-06 ~> day06),
27
27
door!(2025-12-07 ~> day07),
28
28
-
// door!(2025-12-08 ~> day08),
28
28
+
door!(2025-12-08 ~> day08),
29
29
// door!(2025-12-09 ~> day09),
30
30
// door!(2025-12-10 ~> day10),
31
31
// door!(2025-12-11 ~> day11),