mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 12:50:32 +01:00
Compare commits
3 Commits
be6c3d37ea
...
768a3ff10b
| Author | SHA1 | Date | |
|---|---|---|---|
| 768a3ff10b | |||
| c3d3116f8a | |||
| 13592a60ee |
1
2025/day08/.gitignore
vendored
Normal file
1
2025/day08/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
solve
|
||||||
11
2025/day08/README.md
Normal file
11
2025/day08/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Day 08: Go
|
||||||
|
|
||||||
|
Nice puzzle, got to use an obscure data structure. And implement it, because Go doesn't have it in
|
||||||
|
its standard library.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ go build
|
||||||
|
$ ./solve sample.txt 10
|
||||||
|
Part 1: 40
|
||||||
|
Part 2: 25272
|
||||||
|
```
|
||||||
3
2025/day08/go.mod
Normal file
3
2025/day08/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module bertptrs/solve/v2
|
||||||
|
|
||||||
|
go 1.25.5
|
||||||
20
2025/day08/sample.txt
Normal file
20
2025/day08/sample.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
|
||||||
192
2025/day08/solve.go
Normal file
192
2025/day08/solve.go
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"container/heap"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DistanceHeap [][3]int
|
||||||
|
|
||||||
|
func (h DistanceHeap) Len() int { return len(h) }
|
||||||
|
func (h DistanceHeap) Less(i, j int) bool { return h[i][0] < h[j][0] }
|
||||||
|
func (h DistanceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||||
|
|
||||||
|
func (h *DistanceHeap) Push(x any) {
|
||||||
|
// Push and Pop use pointer receivers because they modify the slice's length,
|
||||||
|
// not just its contents.
|
||||||
|
*h = append(*h, x.([3]int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DistanceHeap) Pop() any {
|
||||||
|
old := *h
|
||||||
|
n := len(old)
|
||||||
|
x := old[n-1]
|
||||||
|
*h = old[0 : n-1]
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
reader := bufio.NewReader(file)
|
||||||
|
|
||||||
|
for {
|
||||||
|
parsed, err := fmt.Fscanf(reader, "%d,%d,%d\n", &point[0], &point[1], &point[2])
|
||||||
|
if err != nil || parsed != 3 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
points = append(points, point)
|
||||||
|
}
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
distances := make([][3]int, 0, len(points)*(len(points)-1)/2)
|
||||||
|
|
||||||
|
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})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_heap := DistanceHeap(distances)
|
||||||
|
heap.Init(&size_heap)
|
||||||
|
|
||||||
|
groups := NewDisjointSet(len(points))
|
||||||
|
|
||||||
|
for range connections {
|
||||||
|
first := heap.Pop(&size_heap)
|
||||||
|
d := first.([3]int)
|
||||||
|
groups.Union(d[1], d[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
sizes := compute_group_sizes(groups, len(points))
|
||||||
|
|
||||||
|
product := 1
|
||||||
|
for _, size := range sizes[len(sizes)-3:] {
|
||||||
|
product *= size
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Part 1: %v\n", product)
|
||||||
|
|
||||||
|
to_merge := len(sizes) - 1
|
||||||
|
for {
|
||||||
|
first := heap.Pop(&size_heap)
|
||||||
|
d := first.([3]int)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user