Skip to content

Commit d32dd68

Browse files
committed
Faster multithreaded approach that buckets the edges by distance
1 parent 78f448d commit d32dd68

File tree

2 files changed

+51
-21
lines changed

2 files changed

+51
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
8484
| 5 | [Cafeteria](https://adventofcode.com/2025/day/5) | [Source](src/year2025/day05.rs) | 20 |
8585
| 6 | [Trash Compactor](https://adventofcode.com/2025/day/6) | [Source](src/year2025/day06.rs) | 20 |
8686
| 7 | [Laboratories](https://adventofcode.com/2025/day/7) | [Source](src/year2025/day07.rs) | 5 |
87-
| 8 | [Playground](https://adventofcode.com/2025/day/8) | [Source](src/year2025/day08.rs) | 12000 |
87+
| 8 | [Playground](https://adventofcode.com/2025/day/8) | [Source](src/year2025/day08.rs) | 527 |
8888

8989
## 2024
9090

src/year2025/day08.rs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,57 @@
11
//! # Playground
22
use crate::util::iter::*;
33
use crate::util::parse::*;
4+
use crate::util::thread::*;
45

5-
type Box = [u64; 3];
6-
type Pair = (usize, usize, u64);
7-
type Input = (Vec<Box>, Vec<Pair>);
6+
type Box = [usize; 3];
7+
type Pair = (u16, u16, usize);
8+
type Input = (Vec<Box>, Vec<Vec<Vec<Pair>>>);
89

910
struct Node {
1011
parent: usize,
1112
size: usize,
1213
}
1314

15+
const BUCKETS: usize = 5;
16+
const SIZE: usize = 10_000 * 10_000;
17+
1418
pub fn parse(input: &str) -> Input {
15-
let boxes: Vec<_> = input.iter_unsigned::<u64>().chunk::<3>().collect();
16-
let mut pairs = Vec::with_capacity(boxes.len() * (boxes.len() - 1));
19+
let boxes: Vec<_> = input.iter_unsigned::<usize>().chunk::<3>().collect();
20+
let items: Vec<_> = (0..boxes.len()).collect();
21+
let mut buckets = vec![vec![]; BUCKETS];
1722

18-
for (i, &v1) in boxes.iter().enumerate() {
19-
for (j, &v2) in boxes.iter().enumerate().skip(i + 1) {
20-
let dx = v1[0].abs_diff(v2[0]);
21-
let dy = v1[1].abs_diff(v2[1]);
22-
let dz = v1[2].abs_diff(v2[2]);
23-
let distance = dx * dx + dy * dy + dz * dz;
24-
pairs.push((i, j, distance));
23+
for result in spawn_parallel_iterator(&items, |iter| worker(&boxes, iter)) {
24+
for (bucket, pairs) in buckets.iter_mut().zip(result) {
25+
bucket.push(pairs);
2526
}
2627
}
2728

28-
pairs.sort_unstable_by_key(|&(.., distance)| distance);
29-
(boxes, pairs)
29+
(boxes, buckets)
3030
}
3131

3232
pub fn part1(input: &Input) -> usize {
3333
part1_testable(input, 1000)
3434
}
3535

3636
pub fn part1_testable(input: &Input, limit: usize) -> usize {
37-
let (boxes, pairs) = input;
37+
let (boxes, buckets) = input;
3838
let mut nodes: Vec<_> = (0..boxes.len()).map(|i| Node { parent: i, size: 1 }).collect();
3939

40-
for &(i, j, ..) in pairs.iter().take(limit) {
41-
union(&mut nodes, i, j);
40+
for (i, j, ..) in flatten(buckets).take(limit) {
41+
union(&mut nodes, i as usize, j as usize);
4242
}
4343

4444
nodes.sort_unstable_by_key(|node| node.size);
4545
nodes.iter().rev().take(3).map(|node| node.size).product()
4646
}
4747

48-
pub fn part2(input: &Input) -> u64 {
49-
let (boxes, pairs) = input;
48+
pub fn part2(input: &Input) -> usize {
49+
let (boxes, buckets) = input;
5050
let mut nodes: Vec<_> = (0..boxes.len()).map(|i| Node { parent: i, size: 1 }).collect();
5151

52-
for &(i, j, ..) in pairs {
52+
for (i, j, ..) in flatten(buckets) {
53+
let (i, j) = (i as usize, j as usize);
54+
5355
if union(&mut nodes, i, j) == boxes.len() {
5456
return boxes[i][0] * boxes[j][0];
5557
}
@@ -58,6 +60,34 @@ pub fn part2(input: &Input) -> u64 {
5860
unreachable!()
5961
}
6062

63+
fn worker(boxes: &[Box], iter: ParIter<'_, usize>) -> Vec<Vec<Pair>> {
64+
let mut buckets = vec![vec![]; BUCKETS];
65+
66+
for &i in iter {
67+
let v1 = boxes[i];
68+
69+
for (j, &v2) in boxes.iter().enumerate().skip(i + 1) {
70+
let dx = v1[0].abs_diff(v2[0]);
71+
let dy = v1[1].abs_diff(v2[1]);
72+
let dz = v1[2].abs_diff(v2[2]);
73+
let distance = dx * dx + dy * dy + dz * dz;
74+
75+
let index = (distance / SIZE).min(BUCKETS - 1);
76+
buckets[index].push((i as u16, j as u16, distance));
77+
}
78+
}
79+
80+
buckets
81+
}
82+
83+
fn flatten(buckets: &[Vec<Vec<Pair>>]) -> impl Iterator<Item = Pair> {
84+
buckets.iter().flat_map(|pairs| {
85+
let mut merged = pairs.concat();
86+
merged.sort_unstable_by_key(|&(.., distance)| distance);
87+
merged
88+
})
89+
}
90+
6191
fn find(set: &mut [Node], mut x: usize) -> usize {
6292
while set[x].parent != x {
6393
let parent = set[x].parent;

0 commit comments

Comments
 (0)