mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
2025 day 8 in Go
This commit is contained in:
166
2025/day08/solve.go
Normal file
166
2025/day08/solve.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SetEntry struct {
|
||||
parent, size int
|
||||
}
|
||||
|
||||
type DisjointSet struct {
|
||||
set []SetEntry
|
||||
}
|
||||
|
||||
func NewDisjointSet(size int) *DisjointSet {
|
||||
set := make([]SetEntry, size)
|
||||
|
||||
for i := range len(set) {
|
||||
set[i].parent = i
|
||||
set[i].size = 1
|
||||
}
|
||||
|
||||
instance := new(DisjointSet)
|
||||
instance.set = set
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
func (d *DisjointSet) Find(item int) int {
|
||||
for d.set[item].parent != item {
|
||||
d.set[item].parent = d.set[d.set[item].parent].parent
|
||||
item = d.set[item].parent
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func (d *DisjointSet) Union(x, y int) bool {
|
||||
xp := d.Find(x)
|
||||
yp := d.Find(y)
|
||||
|
||||
if xp == yp {
|
||||
return false
|
||||
}
|
||||
|
||||
if yp < xp {
|
||||
xp, yp = yp, xp
|
||||
}
|
||||
|
||||
d.set[xp].size += d.set[yp].size
|
||||
d.set[yp].parent = xp
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *DisjointSet) Size(item int) int {
|
||||
if d.set[item].parent == item {
|
||||
return d.set[item].size
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func read_input(filename string) [][3]int {
|
||||
var points [][3]int
|
||||
var point [3]int
|
||||
|
||||
file, err := os.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for {
|
||||
parsed, err := fmt.Fscanf(file, "%d,%d,%d\n", &point[0], &point[1], &point[2])
|
||||
if err != nil || parsed != 3 {
|
||||
break
|
||||
}
|
||||
points = append(points, point)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
return points
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Printf("Usage: %v INPUT_FILE [connections]\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func compute_group_sizes(groups *DisjointSet, len int) []int {
|
||||
var sizes []int
|
||||
for i := range len {
|
||||
size := groups.Size(i)
|
||||
if size > 0 {
|
||||
sizes = append(sizes, size)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Ints(sizes)
|
||||
|
||||
return sizes
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
|
||||
connections := 1000
|
||||
if len(os.Args) >= 3 {
|
||||
parsed, err := strconv.Atoi(os.Args[2])
|
||||
if err != nil {
|
||||
usage()
|
||||
}
|
||||
connections = parsed
|
||||
}
|
||||
|
||||
points := read_input(os.Args[1])
|
||||
|
||||
var distances [][3]int
|
||||
|
||||
for i, a := range points {
|
||||
for j := i + 1; j < len(points); j += 1 {
|
||||
b := points[j]
|
||||
|
||||
square_dist := (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2])
|
||||
|
||||
distances = append(distances, [3]int{square_dist, i, j})
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(distances, func(i, j int) bool { return distances[i][0] < distances[j][0] })
|
||||
|
||||
groups := NewDisjointSet(len(points))
|
||||
|
||||
for _, d := range distances[:connections] {
|
||||
groups.Union(d[1], d[2])
|
||||
}
|
||||
|
||||
sizes := compute_group_sizes(groups, len(points))
|
||||
|
||||
product := 1
|
||||
for i := len(sizes) - 3; i < len(sizes); i += 1 {
|
||||
product *= sizes[i]
|
||||
}
|
||||
|
||||
fmt.Printf("Part 1: %v\n", product)
|
||||
|
||||
to_merge := len(sizes) - 1
|
||||
for _, d := range distances[connections:] {
|
||||
if groups.Union(d[1], d[2]) {
|
||||
to_merge -= 1
|
||||
if to_merge == 0 {
|
||||
fmt.Printf("Part 2: %v\n", points[d[1]][0]*points[d[2]][0])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println("I should not get here")
|
||||
}
|
||||
Reference in New Issue
Block a user