
AoC 2025, Day 8 - Playground
Saturday, December 20, 2025
Another lengthy puzzle. Here's Day 8: Playground. Again, spoilers are below for this puzzle. Don't read it if you want to solve this yourself.
The teleporter's fixed, so now you take it out of the no-door room. You end up in an area with a giant playground. On the other side of the playground, some elves are making a crazy light display.
They're going to connect large strings of lights together with junction boxes. They have the X,Y,Z position of each junction box:
162,817,812
57,618,57
906,360,560
592,479,940
352,342,300
466,668,158
542,29,236
431,825,988
739,650,466
52,470,668
216,146,977
819,987,18
117,168,530
805,96,715
346,949,466
970,615,88
941,993,340
862,61,35
984,92,344
425,690,689
Your task is to help them efficiently connect the junction boxes by measuring the distance between each junction box and connecting them from shortest distance to longest.
Part 1 is to multiply together the three largest circuits after connecting the shortest 1000 connections.
Part 2 is to multiply the X coordinates of the last set of junction boxes that creates the final large circuit.
Javascript provides a nice object type called a Set. They will be used extensively throughout our script.
Thankfully, the puzzle input doesn't require string analysis, so it's easy to make it an array of number arrays:
data8 = [
[162, 817, 812],
[57, 618, 57],
[906, 360, 560],
[592, 479, 940],
[352, 342, 300],
[466, 668, 158],
[542, 29, 236],
[431, 825, 988],
[739, 650, 466],
[52, 470, 668],
[216, 146, 977],
[819, 987, 18],
[117, 168, 530],
[805, 96, 715],
[346, 949, 466],
[970, 615, 88],
[941, 993, 340],
[862, 61, 35],
[984, 92, 344],
[425, 690, 689],
];
Because we're measuring distance between points, we need to measure some Euclidean distance, specifically for 3D space:
const JunctionDistance = (p1, p2, p3, q1, q2, q3) =>
Math.sqrt(Math.pow(p1 - q1, 2) + Math.pow(p2 - q2, 2) + Math.pow(p3 - q3, 2));
While the puzzle shows the full X,Y,Z coordinates in its examples to demonstrate which junctions are connecting, in our script we can designate a general id number for each:
const GetJunctionList = (d) => d.map((i, j) => ({ id: j, position: i }));
Now we can get our distances between junctions. Use some for loops to cycle through each junction box and get a distance, then sort the final distance array by shortest to longest:
let list = GetJunctionList(d);
let distances = [];
for (let i = 0; i < d.length; i++)
for (let j = i + 1; j < d.length; j++)
distances.push({
j1: list[i].id,
j2: list[j].id,
distance: JunctionDistance(...list[i].position, ...list[j].position),
});
distances = distances.sort((a, b) => a.distance - b.distance);
Now we can start sifting through our data. We create an empty array called circuits, and in a while loop take the shortest connection to compare:
let current = distances.shift();
let checkj1 = circuits.findIndex((j) => j.has(current.j1)),
checkj2 = circuits.findIndex((j) => j.has(current.j2));
If none of the junction boxes are in a circuit, create a new Set:
if (checkj1 == -1 && checkj1 == checkj2) {
circuits.push(new Set([current.j1, current.j2]));
}
If either one is in a circuit and the other isn't, add the new one to the other's Set:
else if (checkj1 == -1 && checkj2 != -1) {
circuits[checkj2].add(current.j1);
} else if (checkj1 != -1 && checkj2 == -1) {
circuits[checkj1].add(current.j2);
}
If both are already in the same circuit, do nothing:
else if (checkj1 == checkj2) {}
Finally, if they're already in separate circuits, we need to merge them. Take all the numbers in one Set, add them to the other Set, and clear the emptied Set:
else {
[...circuits[checkj2]].forEach((z) => circuits[checkj1].add(z));
circuits[checkj2].clear();
}
Time to solve our puzzles.
Make sure your while loop is limited to the 1000 shortest connections. After connecting your 1000 junctions, use Array.map to create an array of circuit sizes, ordered by largest to smallest:
if (l == c) {
circuitSize = circuits.map((k) => k.size).sort((a, b) => b - a);
}
Your part 1 answer is multiplying circuitSize[0], circuitSize[1], and circuitSize[2] together.
Now we can change the while loop to make connections until we forcefully break from it. After each connection, we check the size of our largest circuit Set:
if (circuits.find((z) => z.size == list.length)) {
let x1 = list.find((z) => z.id == current.j1).position[0],
x2 = list.find((z) => z.id == current.j2).position[0];
finalConnectionX = x1 * x2;
break;
}
If our Set is the size of our original list, that means the circuit includes everything. We take the X position from the junctions of our final connection that caused this to happen, then multiply them together to get our part 2 answer. Boom, puzzle done.
I don't use Sets all that much, so this was a great way to use them.
My final code:
var data8 = require("./day08.json");
const GetJunctionList = (d) => d.map((i, j) => ({ id: j, position: i }));
const JunctionDistance = (p1, p2, p3, q1, q2, q3) =>
Math.sqrt(Math.pow(p1 - q1, 2) + Math.pow(p2 - q2, 2) + Math.pow(p3 - q3, 2));
const Day8A = (d, c) => {
let list = GetJunctionList(d);
let distances = [];
for (let i = 0; i < d.length; i++)
for (let j = i + 1; j < d.length; j++)
distances.push({
j1: list[i].id,
j2: list[j].id,
distance: JunctionDistance(...list[i].position, ...list[j].position),
});
distances = distances.sort((a, b) => a.distance - b.distance);
let circuits = [],
circuitSize = [],
finalConnectionX = 0;
l = 0;
while (true) {
let current = distances.shift();
let checkj1 = circuits.findIndex((j) => j.has(current.j1)),
checkj2 = circuits.findIndex((j) => j.has(current.j2));
if (checkj1 == -1 && checkj1 == checkj2) {
circuits.push(new Set([current.j1, current.j2]));
} else if (checkj1 == -1 && checkj2 != -1) {
circuits[checkj2].add(current.j1);
} else if (checkj1 != -1 && checkj2 == -1) {
circuits[checkj1].add(current.j2);
} else if (checkj1 == checkj2) {
} else {
[...circuits[checkj2]].forEach((z) => circuits[checkj1].add(z));
circuits[checkj2].clear();
}
l++;
if (l == c) {
circuitSize = circuits.map((k) => k.size).sort((a, b) => b - a);
}
if (circuits.find((z) => z.size == list.length)) {
let x1 = list.find((z) => z.id == current.j1).position[0],
x2 = list.find((z) => z.id == current.j2).position[0];
finalConnectionX = x1 * x2;
break;
}
}
return `${circuitSize[0] * circuitSize[1] * circuitSize[2]} - ${finalConnectionX}`;
};
console.log(Day8A(data8, 1000));