diff --git a/py/2017/07/solve.py b/py/2017/07/solve.py deleted file mode 100644 index 27c702e..0000000 --- a/py/2017/07/solve.py +++ /dev/null @@ -1,116 +0,0 @@ -import re -import sys - -# PART 1 - -def any_key(d): - return list(d)[0] - -class Tower: - PROG_RE = r"(\S+) \((\d+)\)( -> (.*))?\n" - - def __init__(self, weight_of, children_of, parent_of): - self.wo = weight_of - self.co = children_of - self.po = parent_of - - @classmethod - def from_file(cls, filename): - weight_of = {} # name -> weight - children_of = {} # name -> children - parent_of = {} # name -> parent - - with open(filename, "r") as f: - for line in f: - match = re.fullmatch(cls.PROG_RE, line) - - name = match.group(1) - weight = int(match.group(2)) - if match.group(4): - children = match.group(4).split(", ") - else: - children = [] - - weight_of[name] = weight - children_of[name] = children - for child in children: - parent_of[child] = name - - return cls(weight_of, children_of, parent_of) - - def find_root(self): - program = any_key(self.po) - while program in self.po: - program = self.po[program] - return program - -# PART 2 - -# This part is implemented really shitty. It makes a lot of assumptions and -# will probably break the second the input changes or you're just unlucky. -# For my particular input, it worked though. -# -# The basic idea of the algorithm is: -# -# 1. Find the plate where one branch has a different weight from all the others -# 2. Find out which branch weight is wrong and whic weights are correct -# 3. Fix the branch's root program's weight - - def weight(self, name): - return self.wo[name] + sum(self.weight(c) for c in self.co[name]) - - def balanced(self, name): - cs = self.co[name] - ws = [self.weight(c) for c in cs] - return min(ws) == max(ws) - - def unbalanced_child(self, name): - for c in self.co[name]: - if not self.balanced(c): - return c - - def find_imbalance(self, name): - c = self.unbalanced_child(name) - if c is None: - weights = [(c, self.weight(c)) for c in self.co[name]] - return weights - else: - return self.find_imbalance(c) - - def fix_imbalance(self, weights): - # Which weight do we need to correct? - ws = [weight for (c, weight) in weights] - if ws.count(max(ws)) < ws.count(min(ws)): - weight = max(ws) - other = min(ws) - else: - weight = min(ws) - other = max(ws) - - # Wich program has that weight? - prog = None - for (p, w) in weights: - if w == weight: - prog = p - break - - # w_prog_soll - w_prog = w_soll - w_branch - # w_prog_soll = w_soll - w_branch + w_prog - # w_prog_soll = w_soll - (w_branch - w_prog) - w_prog = self.wo[prog] - w_soll = other - w_branch = self.weight(prog) - return w_soll - (w_branch - w_prog) - -def main(filename): - print(f"Solutions for {filename}") - tower = Tower.from_file(filename) - root = tower.find_root() - print(f"Part 1: {root}") - weights = tower.find_imbalance(root) - fixed = tower.fix_imbalance(weights) - print(f"Part 2: {fixed}") - -if __name__ == "__main__": - for filename in sys.argv[1:]: - main(filename) diff --git a/py/2017/07/test_input.txt b/py/2017/07/test_input.txt deleted file mode 100644 index 8a41324..0000000 --- a/py/2017/07/test_input.txt +++ /dev/null @@ -1,13 +0,0 @@ -pbga (66) -xhth (57) -ebii (61) -havc (66) -ktlj (57) -fwft (72) -> ktlj, cntj, xhth -qoyq (66) -padx (45) -> pbga, havc, qoyq -tknk (41) -> ugml, padx, fwft -jptl (61) -ugml (68) -> gyxo, ebii, jptl -gyxo (61) -cntj (57) diff --git a/py/aoc/__init__.py b/py/aoc/__init__.py index 2609ca0..3a6f2c2 100644 --- a/py/aoc/__init__.py +++ b/py/aoc/__init__.py @@ -2,7 +2,7 @@ import sys import argparse from pathlib import Path -from .y2017 import d01, d02, d03, d04, d05, d06 +from .y2017 import d01, d02, d03, d04, d05, d06, d07 from .y2018 import d01, d02, d03, d04, d05, d06, d07, d08, d09, d10, d11 from .y2020 import d10 from .y2021 import d14 @@ -15,6 +15,7 @@ DAYS = { "2017_04": y2017.d04.solve, "2017_05": y2017.d05.solve, "2017_06": y2017.d06.solve, + "2017_07": y2017.d07.solve, "2018_01": y2018.d01.solve, "2018_02": y2018.d02.solve, "2018_03": y2018.d03.solve, diff --git a/py/aoc/y2017/d07.py b/py/aoc/y2017/d07.py new file mode 100644 index 0000000..e952d9e --- /dev/null +++ b/py/aoc/y2017/d07.py @@ -0,0 +1,112 @@ +import re + +# PART 1 + + +def any_key(d): + return list(d)[0] + + +class Tower: + PROG_RE = r"(\S+) \((\d+)\)( -> (.*))?" + + def __init__(self, weight_of, children_of, parent_of): + self.wo = weight_of + self.co = children_of + self.po = parent_of + + @classmethod + def from_str(cls, s): + weight_of = {} # name -> weight + children_of = {} # name -> children + parent_of = {} # name -> parent + + for line in s.splitlines(): + match = re.fullmatch(cls.PROG_RE, line) + + name = match.group(1) + weight = int(match.group(2)) + if match.group(4): + children = match.group(4).split(", ") + else: + children = [] + + weight_of[name] = weight + children_of[name] = children + for child in children: + parent_of[child] = name + + return cls(weight_of, children_of, parent_of) + + def find_root(self): + program = any_key(self.po) + while program in self.po: + program = self.po[program] + return program + + # PART 2 + + # This part is implemented really shitty. It makes a lot of assumptions and + # will probably break the second the input changes or you're just unlucky. + # For my particular input, it worked though. + # + # The basic idea of the algorithm is: + # + # 1. Find the plate where one branch has a different weight from all the others + # 2. Find out which branch weight is wrong and whic weights are correct + # 3. Fix the branch's root program's weight + + def weight(self, name): + return self.wo[name] + sum(self.weight(c) for c in self.co[name]) + + def balanced(self, name): + cs = self.co[name] + ws = [self.weight(c) for c in cs] + return min(ws) == max(ws) + + def unbalanced_child(self, name): + for c in self.co[name]: + if not self.balanced(c): + return c + + def find_imbalance(self, name): + c = self.unbalanced_child(name) + if c is None: + weights = [(c, self.weight(c)) for c in self.co[name]] + return weights + else: + return self.find_imbalance(c) + + def fix_imbalance(self, weights): + # Which weight do we need to correct? + ws = [weight for (c, weight) in weights] + if ws.count(max(ws)) < ws.count(min(ws)): + weight = max(ws) + other = min(ws) + else: + weight = min(ws) + other = max(ws) + + # Wich program has that weight? + prog = None + for (p, w) in weights: + if w == weight: + prog = p + break + + # w_prog_soll - w_prog = w_soll - w_branch + # w_prog_soll = w_soll - w_branch + w_prog + # w_prog_soll = w_soll - (w_branch - w_prog) + w_prog = self.wo[prog] + w_soll = other + w_branch = self.weight(prog) + return w_soll - (w_branch - w_prog) + + +def solve(inputstr): + tower = Tower.from_str(inputstr) + root = tower.find_root() + print(f"Part 1: {root}") + weights = tower.find_imbalance(root) + fixed = tower.fix_imbalance(weights) + print(f"Part 2: {fixed}")