#!/usr/bin/env python from collections import Counter myinput = [] with open("/home/login/bin/advent/input7.txt", 'r') as f: for line in f: myinput.append(line[:-1]) #no newlines in myinput def stripChar(text): if text[0]=='(' and text[-1]==')': return text[1:-1] elif text[-1]==',': return text[:-1] else: return text mysecondfinalinput = [line.split(" ") for line in myinput] myfinalinput = [[stripChar(item) for item in line if item != '->'] for line in mysecondfinalinput] my_parent = {} for line in myfinalinput: for item in line: if line.index(item) < 2: continue else: my_parent[item] = {'name': line[0], 'weight': int(line[1])} answer1 = "" for line in myfinalinput: if line[0] not in my_parent: answer1 = line[0] break print("Part 1: " + answer1) self_weights = {} def self_weight(text): global self_weights if text in self_weights: return self_weights[text] else: index = [line[0] for line in myfinalinput].index(text) self_weights[text] = int(myfinalinput[index][1]) return int(myfinalinput[index][1]) my_children = {} for line in myfinalinput: my_children[line[0]] = list(map(lambda x: {'name': x, 'weight': self_weight(x)}, line[2:])) answer2 = 0 total_weight_carried = {} def total_weight(node_name): global total_weight_carried my_weight = self_weight(node_name) if node_name not in my_children: return my_weight elif node_name in total_weight_carried: return my_weight + total_weight_carried[node_name] else: children = my_children[node_name] children_total_weight = 0 for child in children: child_self_weight = child['weight'] child_total_weight = total_weight(child['name']) children_total_weight += child_total_weight total_weight_carried[child['name']] = child_total_weight - child_self_weight return my_weight + children_total_weight def sibling_name(node_name): siblings_incl_self = my_children[my_parent[node_name]['name']] for sibling in siblings_incl_self: if sibling['name'] == node_name: continue else: return sibling['name'] # Assumption: only one wrong-weighted node def return_corrected_weight(node_name): if node_name not in my_children: #My parent has leaf-nodes for children. #I have no carried weight, so self-weight must be unequal to sibling self-weights. return (node_name, self_weight(node_name), self_weight(node_name) - abs(self_weight(node_name)-sibling_weight(node_name))) else: children = my_children[node_name] children_props = {'total_weights': [total_weight(child['name']) for child in children], 'names': [child['name'] for child in children]} if len(set(children_props['total_weights']))==1: #I carry balanced children, so my self-weight must be problematic. return (node_name, "Old weight: " + str(self_weight(node_name)), "New weight: " + str(self_weight(node_name) - abs(total_weight(node_name)-total_weight(sibling_name(node_name))))) else: counter = Counter(children_props['total_weights']) unbalanced_node_name = children_props['names'][children_props['total_weights'].index(min(counter, key=counter.get))] return return_corrected_weight(unbalanced_node_name) answer2 = return_corrected_weight(answer1) print("Part 2: " + str(answer2))