Solve day 8

This commit is contained in:
2025-12-08 21:55:03 +02:00
parent 8b102c2c61
commit 019510f0b6
2 changed files with 207 additions and 0 deletions

20
day8/example.txt Normal file
View File

@@ -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

187
day8/main.go Normal file
View File

@@ -0,0 +1,187 @@
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"maps"
"math"
"os"
"slices"
"strconv"
"strings"
"time"
)
func main() {
connections := flag.Int("connect", -1, "Number of connections to perform (-1 unlimited).")
debug := flag.Bool("debug", false, "Debug.")
flag.Parse()
f := os.Stdin
if flag.NArg() > 0 && flag.Arg(0) != "-" {
var err error
f, err = os.Open(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
defer f.Close()
}
positions, err := readPositions(f)
if err != nil {
log.Fatal(err)
}
circuit := make([]int, len(positions))
for i := range positions {
circuit[i] = i
}
start := time.Now()
distances := computeDistances(positions)
var last connection
fmt.Println("distances computed in", time.Since(start))
start = time.Now()
for i := 0; ; i++ {
if *connections >= 0 && i >= *connections {
break
}
c, ok := distances.FindMin()
if !ok {
break
}
bCircuit := circuit[c.B]
for i := range circuit {
if circuit[i] == bCircuit {
circuit[i] = circuit[c.A]
}
}
if *debug {
fmt.Println("connect", positions[c.A], "and", positions[c.B])
}
if allEqual(circuit) {
last = c
break
}
delete(distances, c)
}
fmt.Println("connections computed in", time.Since(start))
countsMap := make(map[int]int)
for _, c := range circuit {
countsMap[c]++
}
counts := slices.Sorted(maps.Values(countsMap))
// if *debug {
// fmt.Println("counts:", counts)
// }
ans := 1
for _, c := range counts[max(0, len(counts)-3):] {
ans *= c
}
fmt.Println("three largest mult:", ans)
fmt.Println("last connection X mult:", positions[last.A].X*positions[last.B].X)
}
type position struct {
X, Y, Z int
}
func (p position) String() string {
return fmt.Sprintf("%d,%d,%d", p.X, p.Y, p.Z)
}
func (p position) DistanceTo(p1 position) float64 {
compX := float64((p.X - p1.X) * (p.X - p1.X))
compY := float64((p.Y - p1.Y) * (p.Y - p1.Y))
compZ := float64((p.Z - p1.Z) * (p.Z - p1.Z))
return math.Sqrt(compX + compY + compZ)
}
func readPositions(r io.Reader) ([]position, error) {
var positions []position
sc := bufio.NewScanner(r)
for sc.Scan() {
fields := strings.Split(sc.Text(), ",")
if len(fields) != 3 {
return nil, fmt.Errorf("position %q: unexpected number of fields", sc.Text())
}
x, err := strconv.Atoi(fields[0])
if err != nil {
return nil, fmt.Errorf("position %q: x: %w", sc.Text(), err)
}
y, err := strconv.Atoi(fields[1])
if err != nil {
return nil, fmt.Errorf("position %q: y: %w", sc.Text(), err)
}
z, err := strconv.Atoi(fields[2])
if err != nil {
return nil, fmt.Errorf("position %q: z: %w", sc.Text(), err)
}
positions = append(positions, position{
X: x,
Y: y,
Z: z,
})
}
return positions, sc.Err()
}
type connection struct {
A, B int
}
func (c connection) Reverse() connection {
return connection{c.B, c.A}
}
type distances map[connection]float64
func (d distances) Get(aIndex, bIndex int) float64 {
c := connection{aIndex, bIndex}
if dist, ok := d[c]; ok {
return dist
}
return d[c.Reverse()]
}
func (d distances) Set(aIndex, bIndex int, dist float64) {
d[connection{aIndex, bIndex}] = dist
}
func (d distances) FindMin() (c connection, ok bool) {
for pair, dist := range d {
if !ok || dist < d[c] {
c = pair
ok = true
}
}
return c, ok
}
func computeDistances(positions []position) distances {
table := make(distances)
for i, p := range positions {
for j := i + 1; j < len(positions); j++ {
dist := p.DistanceTo(positions[j])
table.Set(i, j, dist)
}
}
return table
}
func allEqual(s []int) bool {
if len(s) < 1 {
return true
}
for _, v := range s[1:] {
if v != s[0] {
return false
}
}
return true
}