func part2(input string) int {
	graph := parseInput(input)
	currentNode := part1(input)
	weightCalculator := memoCalcWeight(graph)
	var siblings []string
	for indexToExit := 0; indexToExit < len(graph); indexToExit++ {
		weightToDependents := map[int][]string{}
		for _, dependentName := range graph[currentNode].edges {
			weight := weightCalculator(dependentName)
			weightToDependents[weight] = append(weightToDependents[weight], dependentName)
		}
		if len(weightToDependents) > 1 {
			siblings = graph[currentNode].edges
			for _, names := range weightToDependents {
				if len(names) == 1 {
					currentNode = names[0]
				}
			}
		} else if len(weightToDependents) == 1 {
			currentWeight := weightCalculator(currentNode)
			for _, sib := range siblings {
				if sib != currentNode {
					desiredWeight := weightCalculator(sib)
					return graph[currentNode].weight - (currentWeight - desiredWeight)
				}
			}
		} else {
			panic("unhandled case, weightToDependents == 0")
		}
	}
	panic("something's wrong in the loop...")
}
NOTE this is not a fully generalized solution, there are graphs where this
could fail. Although I suspect AoC inputs are tailored to make this solution
sufficient
package main
import (
	"flag"
	"fmt"
	"strings"
	"github.com/alexchao26/advent-of-code-go/cast"
	"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
	var part int
	flag.IntVar(&part, "part", 1, "part 1 or 2")
	flag.Parse()
	fmt.Println("Running part", part)
	if part == 1 {
		ans := part1(util.ReadFile("./input.txt"))
		fmt.Println("Output:", ans)
	} else {
		ans := part2(util.ReadFile("./input.txt"))
		fmt.Println("Output:", ans)
	}
}
func part1(input string) string {
	graph := parseInput(input)
	allNames := map[string]bool{}
	for k := range graph {
		allNames[k] = true
	}
	for _, node := range graph {
		for _, name := range node.edges {
			delete(allNames, name)
		}
	}
	if len(allNames) != 1 {
		panic("Expected one name left, got" + cast.ToString(len(allNames)))
	}
	var nameAtBottom string
	for name := range allNames {
		nameAtBottom = name
	}
	return nameAtBottom
}