Skip to content

Commit 533a16b

Browse files
committed
2025 Day 8 (dirty)
1 parent c1d3ecd commit 533a16b

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

src/bin/2025_08/main.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use std::collections::HashMap;
2+
3+
use aoc::{
4+
common::{self, HashMapCount},
5+
io,
6+
};
7+
use itertools::Itertools;
8+
9+
struct Box {
10+
pub x: usize,
11+
y: usize,
12+
z: usize,
13+
}
14+
15+
impl Box {
16+
fn new(x: usize, y: usize, z: usize) -> Self {
17+
Self { x, y, z }
18+
}
19+
20+
fn dist(b1: &Box, b2: &Box) -> usize {
21+
let dx = b1.x.abs_diff(b2.x);
22+
let dy = b1.y.abs_diff(b2.y);
23+
let dz = b1.z.abs_diff(b2.z);
24+
dx * dx + dy * dy + dz * dz
25+
}
26+
}
27+
28+
fn find_group(gm: &HashMap<usize, usize>, g: usize) -> usize {
29+
let mut ret = g;
30+
while let Some(i) = gm.get(&ret) {
31+
ret = *i;
32+
}
33+
ret
34+
}
35+
36+
fn all_connected(gm: &HashMap<usize, usize>, groups: usize) -> bool {
37+
(0..groups).all(|g| find_group(gm, g) == 0)
38+
}
39+
40+
fn solve<const PART: usize, const MIN_CONNECTIONS: usize>(input: &str) -> usize {
41+
let mut boxes = Vec::new();
42+
for line in input.lines() {
43+
if line.is_empty() {
44+
continue;
45+
}
46+
let coords: Vec<usize> = io::tokenize_nums(line, ",");
47+
boxes.push(Box::new(coords[0], coords[1], coords[2]));
48+
}
49+
50+
let mut distances = Vec::new();
51+
for i in 0..boxes.len() {
52+
for j in i + 1..boxes.len() {
53+
distances.push((i, j, Box::dist(&boxes[i], &boxes[j])));
54+
}
55+
}
56+
57+
distances.sort_by(|a, b| a.2.cmp(&b.2));
58+
59+
let mut group_mapping: HashMap<usize, usize> = HashMap::new();
60+
61+
for (i, j, _) in distances.iter().take(if PART == 1 {
62+
MIN_CONNECTIONS
63+
} else {
64+
distances.len()
65+
}) {
66+
let g1 = find_group(&group_mapping, *i);
67+
let g2 = find_group(&group_mapping, *j);
68+
69+
//println!("Joining {} and {} | groups {} and {}", i, j, g1, g2);
70+
if g1 == g2 {
71+
continue;
72+
}
73+
74+
let g = g1.min(g2);
75+
76+
if g1 != g {
77+
group_mapping.insert(g1, g);
78+
}
79+
if g2 != g {
80+
group_mapping.insert(g2, g);
81+
}
82+
83+
if all_connected(&group_mapping, boxes.len()) {
84+
return boxes[*i].x * boxes[*j].x;
85+
}
86+
}
87+
88+
let mut group_to_member_count: HashMap<usize, usize> = HashMap::new();
89+
90+
for i in 0..boxes.len() {
91+
let g = find_group(&group_mapping, i);
92+
//println!("Box {} belongs to group {}", i, g);
93+
group_to_member_count.insert_with_count(&g, 1);
94+
}
95+
96+
//dbg!(&group_to_member_count);
97+
98+
group_to_member_count
99+
.values()
100+
.sorted_by(|a, b| b.cmp(a))
101+
.take(3)
102+
.product()
103+
}
104+
105+
fn main() {
106+
if let Some(input) = common::get_input() {
107+
common::timed(&input, solve::<1, 1000>, true);
108+
common::timed(&input, solve::<2, 1000>, false);
109+
}
110+
}
111+
112+
#[cfg(test)]
113+
mod tests {
114+
use super::*;
115+
116+
#[test]
117+
fn test_samples() {
118+
let sample_input = "162,817,812\n57,618,57\n906,360,560\n592,479,940\n352,342,300\n466,668,158\n542,29,236\n431,825,988\n739,650,466\n52,470,668\n216,146,977\n819,987,18\n117,168,530\n805,96,715\n346,949,466\n970,615,88\n941,993,340\n862,61,35\n984,92,344\n425,690,689";
119+
assert_eq!(solve::<1, 10>(sample_input), 40);
120+
assert_eq!(solve::<2, 10>(sample_input), 25272);
121+
}
122+
}

0 commit comments

Comments
 (0)