Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions src/year_2025/day_8/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Day 8: Playground

Equipped with a new understanding of teleporter maintenance, you confidently step onto the repaired teleporter pad.

You rematerialize on an unfamiliar teleporter pad and find yourself in a vast underground space which contains a giant playground!

Across the playground, a group of Elves are working on setting up an ambitious Christmas decoration project. Through careful rigging, they have suspended a large number of small electrical junction boxes.

Their plan is to connect the junction boxes with long strings of lights. Most of the junction boxes don't provide electricity; however, when two junction boxes are connected by a string of lights, electricity can pass between those two junction boxes.

The Elves are trying to figure out which junction boxes to connect so that electricity can reach every junction box. They even have a list of all of the junction boxes' positions in 3D space (your puzzle input).

## Example

```
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
```

This list describes the position of 20 junction boxes, one per line. Each position is given as X,Y,Z coordinates. So, the first junction box in the list is at X=162, Y=817, Z=812.

## Solution Approach

To save on string lights, the Elves would like to focus on connecting pairs of junction boxes that are as close together as possible according to straight-line distance. In this example, the two junction boxes which are closest together are `162,817,812` and `425,690,689`.

By connecting these two junction boxes together, because electricity can flow between them, they become part of the same circuit. After connecting them, there is a single circuit which contains two junction boxes, and the remaining 18 junction boxes remain in their own individual circuits.

Now, the two junction boxes which are closest together but aren't already directly connected are `162,817,812` and `431,825,988`. After connecting them, since `162,817,812` is already connected to another junction box, there is now a single circuit which contains three junction boxes and an additional 17 circuits which contain one junction box each.

The next two junction boxes to connect are `906,360,560` and `805,96,715`. After connecting them, there is a circuit containing 3 junction boxes, a circuit containing 2 junction boxes, and 15 circuits which contain one junction box each.

The next two junction boxes are `431,825,988` and `425,690,689`. Because these two junction boxes were already in the same circuit, nothing happens!

This process continues for a while, and the Elves are concerned that they don't have enough extension cables for all these circuits. They would like to know how big the circuits will be.

After making the ten shortest connections, there are 11 circuits: one circuit which contains 5 junction boxes, one circuit which contains 4 junction boxes, two circuits which contain 2 junction boxes each, and seven circuits which each contain a single junction box. Multiplying together the sizes of the three largest circuits (5, 4, and one of the circuits of size 2) produces **40**.

## Part One

Your list contains many junction boxes; connect together the 1000 pairs of junction boxes which are closest together. Afterward, what do you get if you multiply together the sizes of the three largest circuits?

**Answer: 42840**

## Part Two

The Elves were right; they definitely don't have enough extension cables. You'll need to keep connecting junction boxes together until they're all in one large circuit.

Continuing the above example, the first connection which causes all of the junction boxes to form a single circuit is between the junction boxes at `216,146,977` and `117,168,530`. The Elves need to know how far those junction boxes are from the wall so they can pick the right extension cable; multiplying the X coordinates of those two junction boxes (216 and 117) produces **25272**.

Continue connecting the closest unconnected pairs of junction boxes together until they're all in the same circuit. What do you get if you multiply together the X coordinates of the last two junction boxes you need to connect?

**Answer: 170629052**
126 changes: 117 additions & 9 deletions src/year_2025/day_8/code.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,147 @@
"""
Advent of Code 2025 - Day 8
Advent of Code 2025 - Day 8: Playground

Placeholder for Day 8 puzzle.
Connect junction boxes with the shortest connections using Union-Find algorithm.
"""

import os
import math


class UnionFind:
"""Union-Find data structure for tracking connected components."""

def __init__(self, n):
self.parent = list(range(n))
self.size = [1] * n

def find(self, x):
"""Find the root of the set containing x."""
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x]) # Path compression
return self.parent[x]

def union(self, x, y):
"""Union the sets containing x and y. Returns True if they were different sets."""
root_x = self.find(x)
root_y = self.find(y)

if root_x == root_y:
return False # Already in the same set

# Union by size
if self.size[root_x] < self.size[root_y]:
root_x, root_y = root_y, root_x

self.parent[root_y] = root_x
self.size[root_x] += self.size[root_y]
return True

def get_component_sizes(self):
"""Get the sizes of all connected components."""
component_sizes = {}
for i in range(len(self.parent)):
root = self.find(i)
component_sizes[root] = self.size[root]
return list(component_sizes.values())


def parse_input(input_text: str):
"""Parse the input text."""
"""Parse the input text into a list of 3D coordinates."""
lines = input_text.strip().split("\n")
return lines
points = []
for line in lines:
x, y, z = map(int, line.split(","))
points.append((x, y, z))
return points


def distance(p1, p2):
"""Calculate Euclidean distance between two 3D points."""
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 + (p1[2] - p2[2]) ** 2)


def part1(file_name: str) -> int:
"""Solve part 1."""
"""Solve part 1: Connect 1000 closest pairs and multiply 3 largest circuit sizes."""
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, file_name)

with open(file_path, encoding="utf-8") as f:
input_text = f.read()

data = parse_input(input_text)
return 0
points = parse_input(input_text)
n = len(points)

# Create all possible edges with their distances
edges = []
for i in range(n):
for j in range(i + 1, n):
dist = distance(points[i], points[j])
edges.append((dist, i, j))

# Sort edges by distance
edges.sort()

# Use Union-Find to connect closest pairs
uf = UnionFind(n)

# For test case, try 10 connections; for real input, try 1000
# Note: "try" means attempt, even if already connected
max_attempts = 10 if file_name == "test.txt" else 1000

for idx in range(max_attempts):
dist, i, j = edges[idx]
uf.union(i, j) # Attempt to union (may not merge if already connected)

# Get sizes of all circuits
circuit_sizes = uf.get_component_sizes()
circuit_sizes.sort(reverse=True)

# Multiply the three largest circuit sizes
result = circuit_sizes[0] * circuit_sizes[1] * circuit_sizes[2]
return result


def part2(file_name: str) -> int:
"""Solve part 2."""
"""Solve part 2: Connect all junction boxes and return product of X coordinates of last connection."""
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, file_name)

with open(file_path, encoding="utf-8") as f:
input_text = f.read()

data = parse_input(input_text)
points = parse_input(input_text)
n = len(points)

# Create all possible edges with their distances
edges = []
for i in range(n):
for j in range(i + 1, n):
dist = distance(points[i], points[j])
edges.append((dist, i, j))

# Sort edges by distance
edges.sort()

# Use Union-Find to connect closest pairs
uf = UnionFind(n)
last_connection = None

# Keep connecting until all junction boxes are in one circuit
for dist, i, j in edges:
if uf.union(i, j):
# Check if all are now connected (only 1 component)
component_sizes = uf.get_component_sizes()
if len(component_sizes) == 1:
# This was the last connection needed
last_connection = (i, j)
break

# Return the product of X coordinates of the last two junction boxes
if last_connection:
i, j = last_connection
return points[i][0] * points[j][0]

return 0


Expand Down
Loading