2025 day 8 in Go

This commit is contained in:
2025-12-08 21:21:24 +01:00
parent be6c3d37ea
commit 13592a60ee
5 changed files with 201 additions and 0 deletions

1
2025/day08/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
solve

11
2025/day08/README.md Normal file
View File

@@ -0,0 +1,11 @@
# Day 08: Go
Nice puzzle, got to use an obscure data structure. And implement it, because Go doesn't have it in
its standard library.
```console
$ go build
$ ./solve sample.txt 10
Part 1: 40
Part 2: 25272
```

3
2025/day08/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module bertptrs/solve/v2
go 1.25.5

20
2025/day08/sample.txt Normal file
View File

@@ -0,0 +1,20 @@
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

166
2025/day08/solve.go Normal file
View File

@@ -0,0 +1,166 @@
package main
import (
"fmt"
"os"
"sort"
"strconv"
)
type SetEntry struct {
parent, size int
}
type DisjointSet struct {
set []SetEntry
}
func NewDisjointSet(size int) *DisjointSet {
set := make([]SetEntry, size)
for i := range len(set) {
set[i].parent = i
set[i].size = 1
}
instance := new(DisjointSet)
instance.set = set
return instance
}
func (d *DisjointSet) Find(item int) int {
for d.set[item].parent != item {
d.set[item].parent = d.set[d.set[item].parent].parent
item = d.set[item].parent
}
return item
}
func (d *DisjointSet) Union(x, y int) bool {
xp := d.Find(x)
yp := d.Find(y)
if xp == yp {
return false
}
if yp < xp {
xp, yp = yp, xp
}
d.set[xp].size += d.set[yp].size
d.set[yp].parent = xp
return true
}
func (d *DisjointSet) Size(item int) int {
if d.set[item].parent == item {
return d.set[item].size
} else {
return 0
}
}
func read_input(filename string) [][3]int {
var points [][3]int
var point [3]int
file, err := os.Open(filename)
if err != nil {
panic(err)
}
for {
parsed, err := fmt.Fscanf(file, "%d,%d,%d\n", &point[0], &point[1], &point[2])
if err != nil || parsed != 3 {
break
}
points = append(points, point)
}
file.Close()
return points
}
func usage() {
fmt.Printf("Usage: %v INPUT_FILE [connections]\n", os.Args[0])
os.Exit(1)
}
func compute_group_sizes(groups *DisjointSet, len int) []int {
var sizes []int
for i := range len {
size := groups.Size(i)
if size > 0 {
sizes = append(sizes, size)
}
}
sort.Ints(sizes)
return sizes
}
func main() {
if len(os.Args) < 2 {
usage()
}
connections := 1000
if len(os.Args) >= 3 {
parsed, err := strconv.Atoi(os.Args[2])
if err != nil {
usage()
}
connections = parsed
}
points := read_input(os.Args[1])
var distances [][3]int
for i, a := range points {
for j := i + 1; j < len(points); j += 1 {
b := points[j]
square_dist := (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2])
distances = append(distances, [3]int{square_dist, i, j})
}
}
sort.Slice(distances, func(i, j int) bool { return distances[i][0] < distances[j][0] })
groups := NewDisjointSet(len(points))
for _, d := range distances[:connections] {
groups.Union(d[1], d[2])
}
sizes := compute_group_sizes(groups, len(points))
product := 1
for i := len(sizes) - 3; i < len(sizes); i += 1 {
product *= sizes[i]
}
fmt.Printf("Part 1: %v\n", product)
to_merge := len(sizes) - 1
for _, d := range distances[connections:] {
if groups.Union(d[1], d[2]) {
to_merge -= 1
if to_merge == 0 {
fmt.Printf("Part 2: %v\n", points[d[1]][0]*points[d[2]][0])
return
}
}
}
println("I should not get here")
}