feat: solve part one
This commit is contained in:
156
internal/2025/DayEight/code.go
Normal file
156
internal/2025/DayEight/code.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user