Day 8: Playground
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465


Go
God damn it, I thought I would never see the end of part 1. I had a hard time finding a good representation and then I failed at not eliminating valid distances etc. The code is quite messy, but I did it!!!
day08.go
package main import ( "aoc/utils" "cmp" "math" "slices" "strconv" "strings" ) type pos3D struct { x, y, z int } func (p pos3D) Compare(other pos3D) int { dx := cmp.Compare(p.x, other.x) if dx != 0 { return dx } dy := cmp.Compare(p.y, other.y) if dy != 0 { return dy } return cmp.Compare(p.z, other.z) } func (p pos3D) distance(other pos3D) float64 { dx := float64(other.x - p.x) dy := float64(other.y - p.y) dz := float64(other.z - p.z) d2 := math.Pow(dx, 2.0) + math.Pow(dy, 2.0) + math.Pow(dz, 2.0) return math.Sqrt(d2) } func getPosChannel(input chan string) chan pos3D { ch := make(chan pos3D, cap(input)) go func() { for line := range input { parts := strings.Split(line, ",") x, _ := strconv.Atoi(parts[0]) y, _ := strconv.Atoi(parts[1]) z, _ := strconv.Atoi(parts[2]) ch <- pos3D{x, y, z} } close(ch) }() return ch } type circuits struct { circuits map[pos3D]int nextID int } func (cc *circuits) newCircuit() (id int) { id = cc.nextID cc.nextID++ return id } func (cc *circuits) mergeCircuits(id1, id2 int) { for p, id := range cc.circuits { if id == id2 { cc.circuits[p] = id1 } } } func createSingletonCircuits(points []pos3D) (cc circuits) { cc.circuits = make(map[pos3D]int) for _, p := range points { id := cc.newCircuit() cc.circuits[p] = id } return cc } func (cc circuits) reverseMap() (m map[int][]pos3D) { m = make(map[int][]pos3D) for p, id := range cc.circuits { if _, ok := m[id]; !ok { m[id] = []pos3D{} } m[id] = append(m[id], p) } return m } func (cc circuits) sizeMap() map[int]int { circuitSizeMap := make(map[int]int) for _, id := range cc.circuits { circuitSizeMap[id]++ } return circuitSizeMap } type targetedDistance struct { distance float64 p1, p2 pos3D } func (p pos3D) distanceWithAll( points []pos3D, alreadyVisited *map[pos3D]any, ) (tds []targetedDistance) { tds = []targetedDistance{} for _, op := range points { if _, ok := (*alreadyVisited)[op]; ok { continue } var td targetedDistance td.distance = math.MaxFloat64 td.p1 = p d := p.distance(op) if d < td.distance { td.distance = d td.p2 = op } tds = append(tds, td) } return tds } type pointPair [2]pos3D func (pp pointPair) equals(other pointPair) bool { pp1 := pp[0] pp2 := pp[1] o1 := other[0] o2 := other[1] return (pp1 == o1 && pp2 == o2) || (pp1 == o2 && pp2 == o1) } var IterationCount = 1000 func stepOne(input chan string) (int, error) { ch := getPosChannel(input) points := []pos3D{} for p := range ch { points = append(points, p) } slices.SortFunc(points, pos3D.Compare) cc := createSingletonCircuits(points) alreadyVisited := make(map[pos3D]any) tds := []targetedDistance{} for _, p := range points { alreadyVisited[p] = nil dsts := p.distanceWithAll(points, &alreadyVisited) tds = append(tds, dsts...) } slices.SortFunc(tds, func(a, b targetedDistance) int { return cmp.Compare(a.distance, b.distance) }) for idx := range IterationCount { td := tds[idx] cc.mergeCircuits(cc.circuits[td.p1], cc.circuits[td.p2]) } circuitSizeMap := cc.sizeMap() circuitSizes := []int{} for _, v := range circuitSizeMap { circuitSizes = append(circuitSizes, v) } slices.Sort(circuitSizes) largestThree := circuitSizes[len(circuitSizes)-3:] product := 1 for _, v := range largestThree { product *= v } return product, nil } func stepTwo(input chan string) (int, error) { ch := getPosChannel(input) points := []pos3D{} for p := range ch { points = append(points, p) } slices.SortFunc(points, pos3D.Compare) cc := createSingletonCircuits(points) alreadyVisited := make(map[pos3D]any) tds := []targetedDistance{} for _, p := range points { alreadyVisited[p] = nil dsts := p.distanceWithAll(points, &alreadyVisited) tds = append(tds, dsts...) } slices.SortFunc(tds, func(a, b targetedDistance) int { return cmp.Compare(a.distance, b.distance) }) idx := 0 var lastConnection pointPair for { td := tds[idx] idx++ cc.mergeCircuits(cc.circuits[td.p1], cc.circuits[td.p2]) circuitSizeMap := cc.sizeMap() if len(circuitSizeMap) == 1 { lastConnection = pointPair{td.p1, td.p2} break } } return lastConnection[0].x * lastConnection[1].x, nil } func main() { inputFile := utils.FilePath("day08.txt") utils.RunStep(utils.ONE, inputFile, stepOne) utils.RunStep(utils.TWO, inputFile, stepTwo) }