I'm reasonably happy with this. I started with a bi-directional linked list, but realized that a flat list of all nodes came in handy for one use case while the linked list came in handy for another, so I settled on that.
115 lines
1.9 KiB
Go
115 lines
1.9 KiB
Go
package days
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"parnic.com/aoc2019/utilities"
|
|
)
|
|
|
|
type body struct {
|
|
orbits *body
|
|
obj string
|
|
}
|
|
|
|
type Day06 struct {
|
|
allBodies []*body
|
|
}
|
|
|
|
func (d *Day06) Parse() {
|
|
d.allBodies = make([]*body, 0)
|
|
|
|
getOrAddBody := func(obj string) *body {
|
|
target := d.findBody(obj)
|
|
if target == nil {
|
|
target = &body{
|
|
obj: obj,
|
|
}
|
|
d.allBodies = append(d.allBodies, target)
|
|
}
|
|
|
|
return target
|
|
}
|
|
|
|
lines := utilities.GetStringLines("06p")
|
|
for _, line := range lines {
|
|
bodies := strings.Split(line, ")")
|
|
newBody := getOrAddBody(bodies[1])
|
|
|
|
target := getOrAddBody(bodies[0])
|
|
newBody.orbits = target
|
|
}
|
|
}
|
|
|
|
func (d *Day06) findBody(obj string) *body {
|
|
for _, checkBody := range d.allBodies {
|
|
if checkBody.obj == obj {
|
|
return checkBody
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d Day06) Num() int {
|
|
return 6
|
|
}
|
|
|
|
func (d *Day06) Part1() string {
|
|
orbits := 0
|
|
for _, obj := range d.allBodies {
|
|
next := obj.orbits
|
|
for next != nil {
|
|
next = next.orbits
|
|
orbits++
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("Total orbits: %s%d%s", utilities.TextBold, orbits, utilities.TextReset)
|
|
}
|
|
|
|
func (d *Day06) Part2() string {
|
|
you := d.findBody("YOU")
|
|
san := d.findBody("SAN")
|
|
|
|
youChildren := make([]*body, 0)
|
|
next := you.orbits
|
|
for next != nil {
|
|
youChildren = append(youChildren, next)
|
|
next = next.orbits
|
|
}
|
|
|
|
var linkingNode *body
|
|
next = san.orbits
|
|
for next != nil {
|
|
if utilities.ArrayContains(youChildren, next) {
|
|
linkingNode = next
|
|
break
|
|
}
|
|
next = next.orbits
|
|
}
|
|
|
|
if linkingNode == nil {
|
|
panic("")
|
|
}
|
|
|
|
getDistToLinking := func(start *body) int {
|
|
dist := 0
|
|
next = start.orbits
|
|
for next != nil {
|
|
if next == linkingNode {
|
|
break
|
|
}
|
|
dist++
|
|
next = next.orbits
|
|
}
|
|
|
|
return dist
|
|
}
|
|
|
|
distYouToLinking := getDistToLinking(you)
|
|
distSanToLinking := getDistToLinking(san)
|
|
|
|
return fmt.Sprintf("Transfers to get to Santa: %s%d%s", utilities.TextBold, distYouToLinking+distSanToLinking, utilities.TextReset)
|
|
}
|