From 22500b70764cb51278fb230c1ca47a6c0c277f64 Mon Sep 17 00:00:00 2001 From: Kharec Date: Mon, 8 Dec 2025 12:26:37 +0100 Subject: [PATCH] feat: solve part one --- internal/2025/DayEight/code.go | 156 +++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 internal/2025/DayEight/code.go diff --git a/internal/2025/DayEight/code.go b/internal/2025/DayEight/code.go new file mode 100644 index 0000000..0bd41e5 --- /dev/null +++ b/internal/2025/DayEight/code.go @@ -0,0 +1,156 @@ +package dayeight + +import ( + "cmp" + "container/heap" + "os" + "slices" + "strconv" + "strings" + + "advent-of-code/internal/registry" +) + +func init() { + registry.Register("2025D8", ParseInput, PartOne, PartTwo) +} + +type JunctionBox struct { + X, Y, Z int +} + +type UnionFind struct { + parent []int + size []int +} + +type Connection struct { + firstJunctionBox, secondJunctionBox int + squaredDistance int +} + +type ConnectionHeap []Connection + +func (h ConnectionHeap) Len() int { return len(h) } +func (h ConnectionHeap) Less(i, j int) bool { return h[i].squaredDistance > h[j].squaredDistance } +func (h ConnectionHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *ConnectionHeap) Push(x any) { *h = append(*h, x.(Connection)) } +func (h *ConnectionHeap) Pop() any { + old := *h + n := len(old) + x := old[n-1] + *h = old[0 : n-1] + return x +} + +func NewUnionFind(count int) *UnionFind { + parent := make([]int, count) + size := make([]int, count) + for idx := range parent { + parent[idx] = idx + size[idx] = 1 + } + return &UnionFind{parent: parent, size: size} +} + +func (uf *UnionFind) Find(junctionBox int) int { + if uf.parent[junctionBox] != junctionBox { + uf.parent[junctionBox] = uf.Find(uf.parent[junctionBox]) + } + return uf.parent[junctionBox] +} + +func (uf *UnionFind) Union(junctionBox1, junctionBox2 int) bool { + root1 := uf.Find(junctionBox1) + root2 := uf.Find(junctionBox2) + if root1 == root2 { + return false + } + if uf.size[root1] < uf.size[root2] { + root1, root2 = root2, root1 + } + uf.parent[root2] = root1 + uf.size[root1] += uf.size[root2] + return true +} + +func ParseInput(filepath string) []string { + content, _ := os.ReadFile(filepath) + return strings.Split(string(content), "\n") +} + +func PartOne(data []string) int { + var junctionBoxes []JunctionBox + for _, line := range data { + parts := strings.Split(line, ",") + x, _ := strconv.Atoi(parts[0]) + y, _ := strconv.Atoi(parts[1]) + z, _ := strconv.Atoi(parts[2]) + junctionBoxes = append(junctionBoxes, JunctionBox{X: x, Y: y, Z: z}) + } + + junctionBoxCount := len(junctionBoxes) + targetPairs := 1000 + if junctionBoxCount <= 20 { + targetPairs = 10 + } + + connectionHeap := make(ConnectionHeap, 0, targetPairs) + heap.Init(&connectionHeap) + + for i := range junctionBoxCount { + for j := i + 1; j < junctionBoxCount; j++ { + dx := junctionBoxes[i].X - junctionBoxes[j].X + dy := junctionBoxes[i].Y - junctionBoxes[j].Y + dz := junctionBoxes[i].Z - junctionBoxes[j].Z + squaredDistance := dx*dx + dy*dy + dz*dz + + connection := Connection{ + firstJunctionBox: i, + secondJunctionBox: j, + squaredDistance: squaredDistance, + } + + if len(connectionHeap) < targetPairs { + heap.Push(&connectionHeap, connection) + } else if connection.squaredDistance < connectionHeap[0].squaredDistance { + heap.Pop(&connectionHeap) + heap.Push(&connectionHeap, connection) + } + } + } + + connections := make([]Connection, 0, len(connectionHeap)) + for connectionHeap.Len() > 0 { + connections = append(connections, heap.Pop(&connectionHeap).(Connection)) + } + + slices.SortFunc(connections, func(a, b Connection) int { + return cmp.Compare(a.squaredDistance, b.squaredDistance) + }) + + uf := NewUnionFind(junctionBoxCount) + for _, connection := range connections { + uf.Union(connection.firstJunctionBox, connection.secondJunctionBox) + } + + circuitSizes := make(map[int]int) + for idx := 0; idx < len(junctionBoxes); idx++ { + root := uf.Find(idx) + circuitSizes[root] = uf.size[root] + } + + sizes := make([]int, 0, len(circuitSizes)) + for _, size := range circuitSizes { + sizes = append(sizes, size) + } + + slices.Sort(sizes) + slices.Reverse(sizes) + + return sizes[0] * sizes[1] * sizes[2] +} + +func PartTwo(data []string) int { + return 0 +}