fun main() { val input = generateSequence(::readLine).map { it.split(")") }.toList() val parentToChildren = input.groupBy { it[0] }.mapValues { it.value.map { it[1] } } val childToParent = input.associateBy { it[1] }.mapValues { it.value[0] } val rootNode = (parentToChildren.keys - parentToChildren.values.flatten().toSet()).first() println("Part 1: ${countOrbiters(parentToChildren, rootNode, 0)}") val santaParents = getParents(childToParent, "SAN") val myParents = getParents(childToParent, "YOU") val commonParent = firstCommon(santaParents, myParents) println("Part 2: ${santaParents.indexOf(commonParent) + myParents.indexOf(commonParent)}") } fun countOrbiters(graph: Map>, key: T, acc: Int): Int = acc + (graph[key]?.map { countOrbiters(graph, it, acc+1) }?.sum() ?: 0) fun getParents(graph: Map, key: T): List = graph[key]?.let { curr -> listOf(curr) + getParents(graph, curr) } ?: emptyList() fun firstCommon(first: List, second: List): T { val seen = mutableSetOf() for (i in 0..first.size) { if (first[i] in seen) return first[i] seen.add(first[i]) if (second[i] in seen) return second[i] seen.add(second[i]) } error("should be unreachable") }