163 lines
3.1 KiB
Go
163 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
func main() {
|
|
inp := helpers.StdinToStringSlice()
|
|
allObjects = make(map[string]*Object)
|
|
for _, v := range inp {
|
|
pts := strings.Split(v, ")")
|
|
var obj1, obj2 *Object
|
|
var ok bool
|
|
if obj1, ok = allObjects[pts[0]]; !ok {
|
|
obj1 = NewObject(pts[0])
|
|
allObjects[pts[0]] = obj1
|
|
}
|
|
if obj2, ok = allObjects[pts[1]]; !ok {
|
|
obj2 = NewObject(pts[1])
|
|
allObjects[pts[1]] = obj2
|
|
obj1.addMoon(pts[1])
|
|
}
|
|
obj2.setOrbiting(pts[0])
|
|
}
|
|
fmt.Println(len(allObjects), "total objects")
|
|
part1()
|
|
part2()
|
|
}
|
|
|
|
func part1() {
|
|
var ret int
|
|
for _, v := range allObjects {
|
|
ret += v.countOrbits()
|
|
}
|
|
fmt.Println("Part 1:", ret)
|
|
}
|
|
|
|
func part2() {
|
|
if _, ok := allObjects["YOU"]; !ok {
|
|
panic("Invalid input for part 2")
|
|
}
|
|
if _, ok := allObjects["SAN"]; !ok {
|
|
panic("Invalid input for part 2")
|
|
}
|
|
you := allObjects["YOU"]
|
|
youOrbits := you.getOrbitsList()
|
|
san := allObjects["SAN"]
|
|
sanOrbits := san.getOrbitsList()
|
|
min := -1
|
|
var minShared *Object
|
|
for _, yv := range youOrbits {
|
|
for _, sv := range sanOrbits {
|
|
if yv == sv {
|
|
ySteps := you.stepsTo(yv.Name)
|
|
sSteps := san.stepsTo(sv.Name)
|
|
if min == -1 || ySteps+sSteps < min {
|
|
min = ySteps + sSteps
|
|
minShared = yv
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if minShared == nil {
|
|
panic("No shared object found!")
|
|
}
|
|
fmt.Println("Closest Ancestor: ", minShared.Name)
|
|
fmt.Println("Steps: ", min)
|
|
}
|
|
|
|
var allObjects map[string]*Object
|
|
|
|
type Object struct {
|
|
Name string
|
|
Moons []*Object
|
|
Orbits *Object
|
|
}
|
|
|
|
func NewObject(nm string) *Object {
|
|
return &Object{Name: nm}
|
|
}
|
|
|
|
func (o *Object) getOrbitsList() []*Object {
|
|
var ret []*Object
|
|
if o.Orbits == nil {
|
|
return ret
|
|
}
|
|
ret = append(ret, o.Orbits)
|
|
return append(ret, o.Orbits.getOrbitsList()...)
|
|
}
|
|
|
|
func (o *Object) stepsTo(nm string) int {
|
|
// First check if this is it
|
|
if o.Name == nm {
|
|
// If so, remove the last transfer
|
|
return -1
|
|
}
|
|
// Now check if it's a descendant of this
|
|
if ret := o.hasDesc(nm); ret != nil {
|
|
return ret.stepsTo(nm) + 1
|
|
}
|
|
// Ok, we must have to go up another level
|
|
if o.Orbits == nil {
|
|
fmt.Println(o.Name)
|
|
panic("Nothing else to check!")
|
|
}
|
|
return o.Orbits.stepsTo(nm) + 1
|
|
}
|
|
|
|
func (o *Object) OrbitsAround(nm string) bool {
|
|
if o.Orbits == nil {
|
|
return false
|
|
}
|
|
if o.Orbits.Name == nm {
|
|
return true
|
|
}
|
|
return o.Orbits.OrbitsAround(nm)
|
|
}
|
|
|
|
// hasDesc checks all moons to see if one is or has the requested moon
|
|
// and returns the object that does
|
|
func (o *Object) hasDesc(nm string) *Object {
|
|
for _, v := range o.Moons {
|
|
if v.Name == nm {
|
|
return v
|
|
}
|
|
if d := v.hasDesc(nm); d != nil {
|
|
return d
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *Object) countOrbits() int {
|
|
if o.Name == "COM" {
|
|
return 0
|
|
}
|
|
return o.Orbits.countOrbits() + 1
|
|
}
|
|
|
|
func (o *Object) setOrbiting(nm string) {
|
|
if v, ok := allObjects[nm]; !ok {
|
|
panic(fmt.Sprintf("Object not found (%s)", nm))
|
|
} else {
|
|
o.Orbits = v
|
|
}
|
|
}
|
|
|
|
func (o *Object) addMoon(nm string) {
|
|
if v, ok := allObjects[nm]; !ok {
|
|
panic(fmt.Sprintf("Object not found (%s)", nm))
|
|
} else {
|
|
for k := range o.Moons {
|
|
if o.Moons[k].Name == nm {
|
|
return
|
|
}
|
|
}
|
|
o.Moons = append(o.Moons, v)
|
|
}
|
|
}
|