Skip to content

Commit 89ed13f

Browse files
committed
βš‘πŸ’‘πŸŽ„
1 parent 5e9b219 commit 89ed13f

File tree

3 files changed

+152
-1
lines changed

3 files changed

+152
-1
lines changed

β€Žaoc2025_wasm/inputsβ€Ž

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
use std::{cell::RefCell, collections::HashSet, str::FromStr};
2+
3+
use anyhow::{Context, Result, ensure};
4+
use itertools::Itertools;
5+
6+
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
7+
struct Coord {
8+
x: i64,
9+
y: i64,
10+
z: i64,
11+
}
12+
13+
impl Coord {
14+
fn dist_squared(&self, other: &Coord) -> i64 {
15+
let xd = self.x - other.x;
16+
let yd = self.y - other.y;
17+
let zd = self.z - other.z;
18+
xd * xd + yd * yd + zd * zd
19+
}
20+
}
21+
22+
impl FromStr for Coord {
23+
type Err = anyhow::Error;
24+
25+
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
26+
let (x, y, z) = s
27+
.split(",")
28+
.collect_tuple()
29+
.context("incorrect number of elements in line")?;
30+
31+
Ok(Coord {
32+
x: x.parse()?,
33+
y: y.parse()?,
34+
z: z.parse()?,
35+
})
36+
}
37+
}
38+
39+
fn calculate_p1(circuits: &[RefCell<HashSet<&Coord>>]) -> usize {
40+
circuits
41+
.iter()
42+
.map(|c| c.borrow().len())
43+
.sorted_unstable()
44+
.rev()
45+
.take(3)
46+
.product()
47+
}
48+
49+
fn calculate<const P1_CONNECTIONS: usize>(inp: &str) -> Result<(usize, i64)> {
50+
let coords = inp
51+
.lines()
52+
.map(|line| line.parse::<Coord>())
53+
.collect::<Result<Vec<_>>>()?;
54+
55+
let mut distances = coords
56+
.iter()
57+
.tuple_combinations()
58+
.map(|(b1, b2)| (b1.dist_squared(b2), b1, b2))
59+
.collect::<Vec<_>>();
60+
61+
distances.sort_unstable_by_key(|&(dist, _, _)| dist);
62+
63+
let mut circuits: Vec<RefCell<HashSet<&Coord>>> = vec![];
64+
let mut connections = 0;
65+
66+
let mut p1 = 0;
67+
let mut p2 = 0;
68+
69+
for (_, b1, b2) in distances {
70+
let mut added = false;
71+
for c in circuits.iter() {
72+
let mut c = c.borrow_mut();
73+
if c.contains(b1) || c.contains(b2) {
74+
c.insert(b1);
75+
c.insert(b2);
76+
for c2 in circuits.iter() {
77+
if let Ok(mut c2) = c2.try_borrow_mut()
78+
&& (c2.contains(b1) || c2.contains(b2))
79+
{
80+
c.extend(c2.iter());
81+
c2.clear();
82+
}
83+
}
84+
added = true;
85+
break;
86+
}
87+
}
88+
89+
if !added {
90+
let new_circuit = HashSet::from([b1, b2]);
91+
circuits.push(RefCell::new(new_circuit));
92+
}
93+
94+
circuits.retain(|c| !c.borrow().is_empty());
95+
96+
connections += 1;
97+
98+
if connections == P1_CONNECTIONS {
99+
p1 = calculate_p1(&circuits);
100+
}
101+
102+
let max_circuit_length = circuits
103+
.iter()
104+
.map(|c| c.borrow().len())
105+
.max()
106+
.context("no circuits")?;
107+
108+
if max_circuit_length == coords.len() {
109+
ensure!(p1 != 0, "solved part 2 before part 1?");
110+
p2 = b1.x * b2.x;
111+
break;
112+
}
113+
}
114+
115+
Ok((p1, p2))
116+
}
117+
118+
pub fn run_2025_08(inp: &str) -> Result<String> {
119+
let (p1, p2) = calculate::<1000>(inp)?;
120+
Ok(format!("{p1}\n{p2}"))
121+
}
122+
123+
#[cfg(test)]
124+
mod tests {
125+
use super::*;
126+
127+
const EXAMPLE_DATA: &str = include_str!("../inputs/examples/2025_08");
128+
const REAL_DATA: &str = include_str!("../inputs/real/2025_08");
129+
130+
#[test]
131+
fn test_example_p1() {
132+
assert_eq!(calculate::<10>(EXAMPLE_DATA).unwrap().0, 40);
133+
}
134+
135+
#[test]
136+
fn test_example_p2() {
137+
assert_eq!(calculate::<10>(EXAMPLE_DATA).unwrap().1, 25272);
138+
}
139+
140+
#[test]
141+
fn test_real_p1() {
142+
assert_eq!(calculate::<1000>(REAL_DATA).unwrap().0, 96672);
143+
}
144+
145+
#[test]
146+
fn test_real_p2() {
147+
assert_eq!(calculate::<1000>(REAL_DATA).unwrap().1, 22517595);
148+
}
149+
}

β€Žaoc2025_wasm/src/lib.rsβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod impl_2025_04;
66
mod impl_2025_05;
77
mod impl_2025_06;
88
mod impl_2025_07;
9+
mod impl_2025_08;
910

1011
pub use wasm_bindgen_rayon::init_thread_pool;
1112

@@ -22,6 +23,7 @@ pub fn run_day(day: u32, input: &str) -> String {
2223
5 => impl_2025_05::run_2025_05(input),
2324
6 => impl_2025_06::run_2025_06(input),
2425
7 => impl_2025_07::run_2025_07(input),
26+
8 => impl_2025_08::run_2025_08(input),
2527
_ => Err(anyhow!("No solution for that day yet")),
2628
};
2729

0 commit comments

Comments
Β (0)