Skip to content

Commit f6b1b0c

Browse files
committed
AoC 2025 Day 8 - rust
1 parent fc64a95 commit f6b1b0c

File tree

5 files changed

+202
-1
lines changed

5 files changed

+202
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
| python3 | [](src/main/python/AoC2025_01.py) | [](src/main/python/AoC2025_02.py) | [](src/main/python/AoC2025_03.py) | [](src/main/python/AoC2025_04.py) | [](src/main/python/AoC2025_05.py) | [](src/main/python/AoC2025_06.py) | [](src/main/python/AoC2025_07.py) | [](src/main/python/AoC2025_08.py) | [](src/main/python/AoC2025_09.py) | [](src/main/python/AoC2025_10.py) | [](src/main/python/AoC2025_11.py) | [](src/main/python/AoC2025_12.py) |
1414
| java | [](src/main/java/AoC2025_01.java) | [](src/main/java/AoC2025_02.java) | [](src/main/java/AoC2025_03.java) | [](src/main/java/AoC2025_04.java) | [](src/main/java/AoC2025_05.java) | [](src/main/java/AoC2025_06.java) | [](src/main/java/AoC2025_07.java) | [](src/main/java/AoC2025_08.java) | [](src/main/java/AoC2025_09.java) | [](src/main/java/AoC2025_10.java) | [](src/main/java/AoC2025_11.java) | [](src/main/java/AoC2025_12.java) |
1515
| bash | [](src/main/bash/AoC2025_01.sh) | [](src/main/bash/AoC2025_02.sh) | [](src/main/bash/AoC2025_03.sh) | [](src/main/bash/AoC2025_04.sh) | [](src/main/bash/AoC2025_05.sh) | [](src/main/bash/AoC2025_06.sh) | [](src/main/bash/AoC2025_07.sh) | | | | [](src/main/bash/AoC2025_11.sh) | [](src/main/bash/AoC2025_12.sh) |
16-
| rust | [](src/main/rust/AoC2025_01/src/main.rs) | [](src/main/rust/AoC2025_02/src/main.rs) | [](src/main/rust/AoC2025_03/src/main.rs) | [](src/main/rust/AoC2025_04/src/main.rs) | [](src/main/rust/AoC2025_05/src/main.rs) | [](src/main/rust/AoC2025_06/src/main.rs) | [](src/main/rust/AoC2025_07/src/main.rs) | | | | | |
16+
| rust | [](src/main/rust/AoC2025_01/src/main.rs) | [](src/main/rust/AoC2025_02/src/main.rs) | [](src/main/rust/AoC2025_03/src/main.rs) | [](src/main/rust/AoC2025_04/src/main.rs) | [](src/main/rust/AoC2025_05/src/main.rs) | [](src/main/rust/AoC2025_06/src/main.rs) | [](src/main/rust/AoC2025_07/src/main.rs) | [](src/main/rust/AoC2025_08/src/main.rs) | | | | |
1717
<!-- @END:ImplementationsTable:2025@ -->
1818

1919
## 2024
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "AoC2025_08"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aoc = { path = "../aoc" }
8+
itertools = "0.11"
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#![allow(non_snake_case)]
2+
3+
use aoc::geometry3d::XYZ;
4+
use aoc::Puzzle;
5+
use itertools::Itertools;
6+
7+
#[derive(Clone)]
8+
struct Box {
9+
idx: usize,
10+
position: XYZ,
11+
}
12+
13+
struct Pair {
14+
first: Box,
15+
second: Box,
16+
distance: u64,
17+
}
18+
19+
struct UnionFind {
20+
sz: Vec<usize>,
21+
ids: Vec<usize>,
22+
components: usize,
23+
}
24+
25+
impl UnionFind {
26+
fn new(size: usize) -> Self {
27+
UnionFind {
28+
sz: vec![1; size],
29+
ids: (0..size).collect::<Vec<_>>(),
30+
components: size,
31+
}
32+
}
33+
34+
fn find(&self, p: usize) -> usize {
35+
let mut root = p;
36+
while root != self.ids[root] {
37+
root = self.ids[root];
38+
}
39+
root
40+
}
41+
42+
fn unify(&mut self, p: usize, q: usize) {
43+
let root_p = self.find(p);
44+
let root_q = self.find(q);
45+
if root_p != root_q {
46+
if self.sz[root_p] < self.sz[root_q] {
47+
self.sz[root_q] += self.sz[root_p];
48+
self.ids[root_p] = root_q;
49+
self.sz[root_p] = 0;
50+
} else {
51+
self.sz[root_p] += self.sz[root_q];
52+
self.ids[root_q] = root_p;
53+
self.sz[root_q] = 0;
54+
}
55+
self.components -= 1;
56+
}
57+
}
58+
}
59+
60+
struct AoC2025_08;
61+
62+
impl AoC2025_08 {
63+
fn solve_1(
64+
&self,
65+
num_boxes: usize,
66+
pairs: &[Pair],
67+
size: usize,
68+
) -> <Self as Puzzle>::Output1 {
69+
let mut dsu = UnionFind::new(num_boxes);
70+
pairs
71+
.iter()
72+
.take(size)
73+
.for_each(|pair| dsu.unify(pair.first.idx, pair.second.idx));
74+
dsu.sz.iter().sorted().rev().take(3).product()
75+
}
76+
77+
fn sample_part_1(
78+
&self,
79+
input: &<Self as Puzzle>::Input,
80+
) -> <Self as Puzzle>::Output1 {
81+
self.solve_1(input.0, &input.1, 10)
82+
}
83+
}
84+
85+
impl aoc::Puzzle for AoC2025_08 {
86+
type Input = (usize, Vec<Pair>);
87+
type Output1 = usize;
88+
type Output2 = u64;
89+
90+
aoc::puzzle_year_day!(2025, 8);
91+
92+
fn parse_input(&self, lines: Vec<String>) -> Self::Input {
93+
let boxes = lines
94+
.iter()
95+
.enumerate()
96+
.map(|(idx, line)| Box {
97+
idx,
98+
position: XYZ::from_iter(
99+
line.split(',').map(|sp| sp.parse::<u32>().unwrap()),
100+
),
101+
})
102+
.collect::<Vec<_>>();
103+
let pairs = boxes
104+
.iter()
105+
.enumerate()
106+
.flat_map(|(i, r#box)| {
107+
(i + 1..boxes.len()).map(|j| Pair {
108+
first: r#box.clone(),
109+
second: boxes[j].clone(),
110+
distance: r#box
111+
.position
112+
.squared_distance(&boxes[j].position),
113+
})
114+
})
115+
.sorted_by(|p1, p2| Ord::cmp(&p1.distance, &p2.distance))
116+
.collect::<Vec<_>>();
117+
(boxes.len(), pairs)
118+
}
119+
120+
fn part_1(&self, input: &Self::Input) -> Self::Output1 {
121+
self.solve_1(input.0, &input.1, 1000)
122+
}
123+
124+
fn part_2(&self, input: &Self::Input) -> Self::Output2 {
125+
let mut dsu = UnionFind::new(input.0);
126+
for pair in input.1.iter() {
127+
dsu.unify(pair.first.idx, pair.second.idx);
128+
if dsu.components == 1 && dsu.sz[dsu.find(0)] == input.0 {
129+
return pair.first.position.x() as u64
130+
* pair.second.position.x() as u64;
131+
}
132+
}
133+
unreachable!();
134+
}
135+
136+
fn samples(&self) {
137+
aoc::puzzle_samples! {
138+
self, sample_part_1, TEST, 40,
139+
self, part_2, TEST, 25272
140+
};
141+
}
142+
}
143+
144+
fn main() {
145+
AoC2025_08 {}.run(std::env::args());
146+
}
147+
148+
const TEST: &str = "\
149+
162,817,812
150+
57,618,57
151+
906,360,560
152+
592,479,940
153+
352,342,300
154+
466,668,158
155+
542,29,236
156+
431,825,988
157+
739,650,466
158+
52,470,668
159+
216,146,977
160+
819,987,18
161+
117,168,530
162+
805,96,715
163+
346,949,466
164+
970,615,88
165+
941,993,340
166+
862,61,35
167+
984,92,344
168+
425,690,689
169+
";
170+
171+
#[cfg(test)]
172+
mod tests {
173+
use super::*;
174+
175+
#[test]
176+
pub fn samples() {
177+
AoC2025_08 {}.samples();
178+
}
179+
}

src/main/rust/Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/rust/aoc/src/geometry3d.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ impl XYZ {
3939
.map(|h| XYZ::try_from(h).unwrap())
4040
.map(|xyz| self.translate(&xyz, 1))
4141
}
42+
43+
pub fn squared_distance(&self, other: &XYZ) -> u64 {
44+
((self.x - other.x) as i64 * (self.x - other.x) as i64) as u64
45+
+ ((self.y - other.y) as i64 * (self.y - other.y) as i64) as u64
46+
+ ((self.z - other.z) as i64 * (self.z - other.z) as i64) as u64
47+
}
4248
}
4349

4450
impl FromIterator<u32> for XYZ {

0 commit comments

Comments
 (0)