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) } }