adventofcode/2019/day06/main.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)
}
}