From 13592a60ee30e1505f135e4fc6fc9d5337d9ef70 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 8 Dec 2025 21:21:24 +0100 Subject: [PATCH] 2025 day 8 in Go --- 2025/day08/.gitignore | 1 + 2025/day08/README.md | 11 +++ 2025/day08/go.mod | 3 + 2025/day08/sample.txt | 20 +++++ 2025/day08/solve.go | 166 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 2025/day08/.gitignore create mode 100644 2025/day08/README.md create mode 100644 2025/day08/go.mod create mode 100644 2025/day08/sample.txt create mode 100644 2025/day08/solve.go diff --git a/2025/day08/.gitignore b/2025/day08/.gitignore new file mode 100644 index 0000000..b199abc --- /dev/null +++ b/2025/day08/.gitignore @@ -0,0 +1 @@ +solve diff --git a/2025/day08/README.md b/2025/day08/README.md new file mode 100644 index 0000000..30bceb6 --- /dev/null +++ b/2025/day08/README.md @@ -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 +``` diff --git a/2025/day08/go.mod b/2025/day08/go.mod new file mode 100644 index 0000000..2be72c9 --- /dev/null +++ b/2025/day08/go.mod @@ -0,0 +1,3 @@ +module bertptrs/solve/v2 + +go 1.25.5 diff --git a/2025/day08/sample.txt b/2025/day08/sample.txt new file mode 100644 index 0000000..e98a3b6 --- /dev/null +++ b/2025/day08/sample.txt @@ -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 diff --git a/2025/day08/solve.go b/2025/day08/solve.go new file mode 100644 index 0000000..66b0904 --- /dev/null +++ b/2025/day08/solve.go @@ -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") +}