aoc2025/day8/main.go
2025-12-08 17:12:22 -05:00

208 lines
4.5 KiB
Go

package main
import (
"fmt"
"os"
"slices"
"strconv"
"strings"
"github.com/dominikbraun/graph"
)
func readLines(filename string) []string {
raw, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
return strings.Split(string(raw), "\n")
}
// input1 80446
func main() {
filename := "input0.txt"
if len(os.Args) > 1 {
filename = os.Args[1]
}
lines := readLines(filename)
p := parsePlayground(lines)
circuits, err := p.wireClosest(1000)
if err != nil {
panic(err)
}
counts := map[uint]uint{}
for _, circuit := range circuits {
counts[circuit]++
}
totals := []uint{}
for _, v := range counts {
totals = append(totals, v)
}
slices.Sort(totals)
slices.Reverse(totals)
fmt.Printf("%v\n", totals[0]*totals[1]*totals[2])
xx, err := p.wireAll()
if err != nil {
panic(err)
}
fmt.Printf("%d\n", xx)
}
func parsePlayground(lines []string) playground {
p := playground{
boxes: []box{},
distances: graph.New(boxHash, graph.Weighted()),
}
for _, line := range lines {
parts := strings.Split(line, ",")
b := box{line: line}
b.x, _ = strconv.Atoi(parts[0])
b.y, _ = strconv.Atoi(parts[1])
b.z, _ = strconv.Atoi(parts[2])
_ = p.distances.AddVertex(b)
for _, c := range p.boxes {
_ = p.distances.AddEdge(b.line, c.line, graph.EdgeWeight(b.distanceTo(c)))
}
p.boxes = append(p.boxes, b)
}
return p
}
func (p *playground) wireClosest(n uint64) (map[string]uint, error) {
edges, err := p.distances.Edges()
if err != nil {
return nil, err
}
slices.SortFunc(edges, func(e1, e2 graph.Edge[string]) int {
return e1.Properties.Weight - e2.Properties.Weight
})
nextCircuit := uint(1)
circuits := map[string]uint{}
for i := range n {
edge := edges[i]
sourceCircuit := circuits[edge.Source]
targetCircuit := circuits[edge.Target]
if sourceCircuit == 0 && targetCircuit == 0 {
circuits[edge.Source] = nextCircuit
circuits[edge.Target] = nextCircuit
nextCircuit++
continue
}
if sourceCircuit == 0 {
circuits[edge.Source] = targetCircuit
continue
}
if targetCircuit == 0 {
circuits[edge.Target] = sourceCircuit
continue
}
if sourceCircuit == targetCircuit {
continue
}
for k, v := range circuits {
if v == targetCircuit {
circuits[k] = sourceCircuit
}
}
}
return circuits, nil
}
func (p *playground) wireAll() (int, error) {
edges, err := p.distances.Edges()
if err != nil {
return 0, err
}
slices.SortFunc(edges, func(e1, e2 graph.Edge[string]) int {
return e1.Properties.Weight - e2.Properties.Weight
})
circuitsInUse := 0
nextCircuit := uint(1)
circuits := map[string]uint{}
for _, edge := range edges {
sourceCircuit := circuits[edge.Source]
targetCircuit := circuits[edge.Target]
if sourceCircuit == 0 && targetCircuit == 0 {
circuits[edge.Source] = nextCircuit
circuits[edge.Target] = nextCircuit
nextCircuit++
circuitsInUse++
continue
}
if sourceCircuit == 0 {
circuits[edge.Source] = targetCircuit
if circuitsInUse == 1 {
count, _ := p.distances.Order()
if count == len(circuits) {
v1, _ := p.distances.Vertex(edge.Source)
v2, _ := p.distances.Vertex(edge.Target)
return v1.x * v2.x, nil
}
}
continue
}
if targetCircuit == 0 {
circuits[edge.Target] = sourceCircuit
if circuitsInUse == 1 {
count, _ := p.distances.Order()
if count == len(circuits) {
v1, _ := p.distances.Vertex(edge.Source)
v2, _ := p.distances.Vertex(edge.Target)
return v1.x * v2.x, nil
}
}
continue
}
if sourceCircuit == targetCircuit {
if circuitsInUse == 1 {
count, _ := p.distances.Order()
if count == len(circuits) {
v1, _ := p.distances.Vertex(edge.Source)
v2, _ := p.distances.Vertex(edge.Target)
return v1.x * v2.x, nil
}
}
continue
}
for k, v := range circuits {
if v == targetCircuit {
circuits[k] = sourceCircuit
}
}
circuitsInUse--
if circuitsInUse == 1 {
count, _ := p.distances.Order()
if count == len(circuits) {
v1, _ := p.distances.Vertex(edge.Source)
v2, _ := p.distances.Vertex(edge.Target)
return v1.x * v2.x, nil
}
}
}
v, _ := p.distances.Order()
return 0, fmt.Errorf("exhausted edges without reaching full connectivity %v", v)
}
type playground struct {
boxes []box
distances graph.Graph[string, box]
}
func boxHash(b box) string {
return b.line
}
type box struct {
line string
x int
y int
z int
}
func (b box) distanceTo(c box) int {
x := c.x - b.x
y := c.y - b.y
z := c.z - b.z
// no need to sqrt since we only care about relative distances
return x*x + y*y + z*z
}