Solve day 8
This commit is contained in:
20
day8/example.txt
Normal file
20
day8/example.txt
Normal 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
187
day8/main.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user