diff --git a/src/Year_2017/P7.py b/src/Year_2017/P7.py index ed9b235..535de35 100644 --- a/src/Year_2017/P7.py +++ b/src/Year_2017/P7.py @@ -88,5 +88,78 @@ def part_1() -> None: print(f"The name of the bottom program is {root_program}") +# --- Part Two --- + +# The programs explain the situation: they can't get down. Rather, they could +# get down, if they weren't expending all of their energy trying to keep the +# tower balanced. Apparently, one program has the wrong weight, and until it's +# fixed, they're stuck here. + +# For any program holding a disc, each program standing on that disc forms a +# sub-tower. Each of those sub-towers are supposed to be the same weight, or +# the disc itself isn't balanced. The weight of a tower is the sum of the +# weights of the programs in that tower. + +# In the example above, this means that for ugml's disc to be balanced, gyxo, +# ebii, and jptl must all have the same weight, and they do: 61. + +# However, for tknk to be balanced, each of the programs standing on its disc +# and all programs above it must each match. This means that the following sums +# must all be the same: + +# ugml + (gyxo + ebii + jptl) = 68 + (61 + 61 + 61) = 251 +# padx + (pbga + havc + qoyq) = 45 + (66 + 66 + 66) = 243 +# fwft + (ktlj + cntj + xhth) = 72 + (57 + 57 + 57) = 243 + +# As you can see, tknk's disc is unbalanced: ugml's stack is heavier than the +# other two. Even though the nodes above ugml are balanced, ugml itself is too +# heavy: it needs to be 8 units lighter for its stack to weigh 243 and keep the +# towers balanced. If this change were made, its weight would be 60. + +# Given that exactly one program is the wrong weight, what would its weight +# need to be to balance the entire tower? + + +def child_values(node, node_map, node_values): + weights, unbalanced = [], [] + children = node_map[node] + for child in children: + if child in node_map.keys(): + child_weight, child_balance = child_values( + child, node_map, node_values + ) + value = sum(child_weight) + node_values[child] + unbalanced.append(child_balance) + else: + value = node_values[child] + weights.append(value) + if len(set(weights)) != 1: + unbalanced.append((node_map[node], weights)) + return weights, unbalanced + + +def part_2() -> None: + node_map, node_values = {}, {} + for line in towers: + if "->" in line: + lhs, rhs = line.split(" -> ") + parent, value = lhs.split() + node_values[parent] = int(value[1:-1]) + _childs = rhs.split(", ") + node_map[parent] = [child for child in _childs] + else: + child, value = line.split() + node_values[child] = int(value[1:-1]) + + _, unbalance = child_values("rqwgj", node_map, node_values) + + heavier_child_idx = unbalance[0][0][5][1].index(max(unbalance[0][0][5][1])) + heavier_child = unbalance[0][0][5][0][heavier_child_idx] + unbalanced_child = node_values[heavier_child] + + print(f"To balance the tower, the weight must be {unbalanced_child - 8}") + + if __name__ == "__main__": part_1() + part_2()