148 lines
2.4 KiB
Go
148 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.z1glr.de/advent-of-code-2025/pkg/aoc"
|
|
)
|
|
|
|
type Node struct {
|
|
X, Y, Z int
|
|
root *Node
|
|
Size int
|
|
ID int
|
|
}
|
|
|
|
func (p *Node) DistanceTo(p2 *Node) float64 {
|
|
return math.Sqrt(float64((p.X-p2.X)*(p.X-p2.X) + (p.Y-p2.Y)*(p.Y-p2.Y) + (p.Z-p2.Z)*(p.Z-p2.Z)))
|
|
}
|
|
|
|
func (p *Node) GetRoot() *Node {
|
|
if p.root == nil {
|
|
return p
|
|
} else {
|
|
root := p.root.GetRoot()
|
|
p.root = root
|
|
return root
|
|
}
|
|
}
|
|
|
|
func PointFromString(s string) Node {
|
|
parts := strings.Split(s, ",")
|
|
|
|
return Node{
|
|
X: aoc.ParseInt(parts[0]),
|
|
Y: aoc.ParseInt(parts[1]),
|
|
Z: aoc.ParseInt(parts[2]),
|
|
Size: 1,
|
|
}
|
|
}
|
|
|
|
type Connection struct {
|
|
Length float64
|
|
P1, P2 *Node
|
|
}
|
|
|
|
func do(test bool) (int, int) {
|
|
rows := aoc.ReadFileRows(test)
|
|
|
|
points := make([]Node, len(rows))
|
|
|
|
for ii, rr := range rows {
|
|
points[ii] = PointFromString(rr)
|
|
points[ii].ID = ii + 1
|
|
}
|
|
|
|
connections := []Connection{}
|
|
|
|
for ii := range points[:len(points)-1] {
|
|
for jj := ii + 1; jj < len(points); jj++ {
|
|
// for jj := range points[ii+1:] {
|
|
p1 := &points[ii]
|
|
p2 := &points[jj]
|
|
// p2 := &points[ii+1+jj]
|
|
|
|
connections = append(connections, Connection{
|
|
Length: p1.DistanceTo(p2),
|
|
P1: p1,
|
|
P2: p2,
|
|
})
|
|
}
|
|
}
|
|
|
|
// sort distances by length
|
|
sort.Slice(connections, func(i, j int) bool { return connections[i].Length < connections[j].Length })
|
|
|
|
threshold := 1000
|
|
|
|
if test {
|
|
threshold = 10
|
|
}
|
|
|
|
var res1, res2 int
|
|
|
|
for ii := range connections {
|
|
if ii == threshold {
|
|
roots := []*Node{}
|
|
|
|
for ii := range points {
|
|
pp := &points[ii]
|
|
if pp.GetRoot() == pp {
|
|
roots = append(roots, pp)
|
|
}
|
|
}
|
|
|
|
sort.Slice(roots, func(i, j int) bool { return roots[i].Size > roots[j].Size })
|
|
|
|
res1 = roots[0].Size * roots[1].Size * roots[2].Size
|
|
|
|
fmt.Println(res1)
|
|
|
|
} else if ii > threshold {
|
|
cc := connections[ii-1]
|
|
// check wether it is one big circuit
|
|
root := points[0].GetRoot()
|
|
|
|
multipleCircuits := false
|
|
|
|
for jj := range points[1:] {
|
|
pp := &points[jj]
|
|
if pp.GetRoot() != root {
|
|
multipleCircuits = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !multipleCircuits {
|
|
res2 = cc.P1.X * cc.P2.X
|
|
|
|
fmt.Println(res2)
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
cc := &connections[ii]
|
|
|
|
root1 := cc.P1.GetRoot()
|
|
root2 := cc.P2.GetRoot()
|
|
|
|
if root1 != root2 {
|
|
root2.root = root1
|
|
|
|
root1.Size += root2.Size
|
|
}
|
|
}
|
|
|
|
return res1, res2
|
|
}
|
|
|
|
func main() {
|
|
if r1, r2 := do(true); r1 == 40 && r2 == 25272 {
|
|
do(false)
|
|
}
|
|
}
|