Skip to content

Commit 12c3b28

Browse files
committed
2025 day08
1 parent 17cf7f3 commit 12c3b28

File tree

6 files changed

+177
-0
lines changed

6 files changed

+177
-0
lines changed

2025/day08/.bench

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Lines":[{"Name":"Part 1","N":1620,"NsPerOp":693302,"AllocedBytesPerOp":0,"AllocsPerOp":0,"MBPerS":0,"Measured":1,"Ord":0},{"Name":"Part 2","N":1646,"NsPerOp":695120,"AllocedBytesPerOp":0,"AllocsPerOp":0,"MBPerS":0,"Measured":1,"Ord":0}],"Measured":1}

2025/day08/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!-- You can add some comments here if you want to :D -->

2025/day08/main.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
_ "embed"
5+
"fmt"
6+
"os"
7+
"strings"
8+
)
9+
10+
//go:embed input.txt
11+
var input string
12+
13+
//go:embed input_test.txt
14+
var inputTest string
15+
16+
var (
17+
junctions []coords
18+
distances []distance
19+
)
20+
21+
func main() {
22+
// Check argv if we use test input or not
23+
isTest := len(os.Args) > 1 && os.Args[1] == "test"
24+
if isTest {
25+
input = inputTest
26+
}
27+
28+
// Parse input once
29+
parseInput(input)
30+
31+
k := 1000
32+
if isTest {
33+
k = 10
34+
}
35+
36+
answer := doPartOne(k)
37+
println(answer)
38+
39+
answer = doPartTwo()
40+
println(answer)
41+
}
42+
43+
func parseInput(input string) {
44+
lines := strings.Split(strings.TrimSpace(input), "\n")
45+
junctions = make([]coords, len(lines))
46+
for i, line := range lines {
47+
fmt.Sscanf(line, "%d,%d,%d", &junctions[i].x, &junctions[i].y, &junctions[i].z)
48+
}
49+
50+
// Calculate all pairwise distances
51+
n := len(junctions)
52+
distances = make([]distance, 0, n*(n-1)/2)
53+
for i := 0; i < n; i++ {
54+
j1 := junctions[i]
55+
for j := i + 1; j < n; j++ {
56+
j2 := junctions[j]
57+
dx := j1.x - j2.x
58+
dy := j1.y - j2.y
59+
dz := j1.z - j2.z
60+
if dx < 0 {
61+
dx = -dx
62+
}
63+
if dy < 0 {
64+
dy = -dy
65+
}
66+
if dz < 0 {
67+
dz = -dz
68+
}
69+
d := dx*dx + dy*dy + dz*dz
70+
distances = append(distances, distance{d: d, a: i, b: j})
71+
}
72+
}
73+
}

2025/day08/main_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import "testing"
4+
5+
func BenchmarkPartOne(b *testing.B) {
6+
parseInput(input)
7+
b.ResetTimer()
8+
for n := 0; n < b.N; n++ {
9+
doPartOne(1000)
10+
}
11+
}
12+
13+
func BenchmarkPartTwo(b *testing.B) {
14+
parseInput(input)
15+
b.ResetTimer()
16+
for n := 0; n < b.N; n++ {
17+
doPartTwo()
18+
}
19+
}

2025/day08/part1.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package main
2+
3+
import (
4+
"aocli/utils/union"
5+
"slices"
6+
)
7+
8+
type coords struct {
9+
x, y, z int
10+
}
11+
12+
type distance struct {
13+
d int
14+
a, b int
15+
}
16+
17+
func doPartOne(k int) int {
18+
// Sort by distance (shortest first)
19+
slices.SortFunc(distances, func(a, b distance) int {
20+
return a.d - b.d
21+
})
22+
23+
// Connect the k shortest pairs
24+
uf := union.NewUnionFind(len(junctions))
25+
for i := 0; i < k && i < len(distances); i++ {
26+
uf.Union(distances[i].a, distances[i].b)
27+
}
28+
29+
// Count component sizes
30+
componentSizes := make(map[int]int)
31+
for j := range junctions {
32+
root := uf.Find(j)
33+
componentSizes[root]++
34+
}
35+
36+
// Get the sizes and sort them (largest first)
37+
sizes := make([]int, 0, len(componentSizes))
38+
for _, size := range componentSizes {
39+
sizes = append(sizes, size)
40+
}
41+
42+
// Sort descending
43+
slices.SortFunc(sizes, func(a, b int) int {
44+
return b - a
45+
})
46+
47+
// Multiply the three largest
48+
if len(sizes) < 3 {
49+
return 0
50+
}
51+
return sizes[0] * sizes[1] * sizes[2]
52+
}

2025/day08/part2.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import (
4+
"aocli/utils/union"
5+
"slices"
6+
)
7+
8+
func doPartTwo() int {
9+
// Sort by distance (shortest first)
10+
slices.SortFunc(distances, func(a, b distance) int {
11+
return a.d - b.d
12+
})
13+
14+
// Connect pairs until we have a spanning tree (n-1 connections)
15+
uf := union.NewUnionFind(len(junctions))
16+
ans := 0
17+
connection := 0
18+
19+
for _, d := range distances {
20+
if uf.Find(d.a) != uf.Find(d.b) {
21+
connection++
22+
if connection == len(junctions)-1 {
23+
ans = junctions[d.a].x * junctions[d.b].x
24+
break
25+
}
26+
uf.Union(d.a, d.b)
27+
}
28+
}
29+
30+
return ans
31+
}

0 commit comments

Comments
 (0)