From 791b94827edd43caaf59993696ba0bb77884b8c4 Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Mon, 7 Dec 2020 10:03:42 +0100 Subject: [PATCH] 7 --- solutions/7/README.md | 15 ++++++++ solutions/7/python/main.py | 70 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 solutions/7/README.md create mode 100644 solutions/7/python/main.py diff --git a/solutions/7/README.md b/solutions/7/README.md new file mode 100644 index 0000000..7e25335 --- /dev/null +++ b/solutions/7/README.md @@ -0,0 +1,15 @@ +# 7 + +This one was maybe the coolest yet! Fixed-point iteration and some recursion. Amazing :) + +For the first part we iterate as long as we don't find any enclosing bags anymore. This can build long chains. + +The second we recurse down the bag chain und sum it up recursively. + +
+ Solutions +
    +
  1. 164
  2. +
  3. 7872
  4. +
+
diff --git a/solutions/7/python/main.py b/solutions/7/python/main.py new file mode 100644 index 0000000..be5dc56 --- /dev/null +++ b/solutions/7/python/main.py @@ -0,0 +1,70 @@ +from os.path import join, dirname +from typing import Dict, List, Set, Tuple +import re + +TRules = Dict[str, Dict[str, int]] + + +def split_trim(input: str, split: str) -> List[str]: + return list(map(lambda s: s.strip(), input.split(split))) + + +def extract_inner(input: str) -> Tuple[int, str]: + parts = input.split(' ') + amount = int(parts[0]) + color = ' '.join(parts[1:-1]) + return amount, color + + +def parse_rules(rules: str) -> TRules: + d: TRules = {} + for rule in rules.strip().split('\n'): + outer, inner = split_trim(rule, 'contain') + outer = re.sub(r'bags?', '', outer).strip() + d[outer] = { + color: amount + for amount, color in [ + extract_inner(i) + for i in split_trim(inner, ',') + if 'no other bag' not in i # Also matches "bags" + ] + } + return d + + +def find_enclosing_bags(rules: TRules, color: str) -> Set[str]: + colors: Set[str] = set() + stack: Set[str] = set([color]) + + while len(stack): + for item in list(stack): + stack.remove(item) + for contains, enclosing in rules.items(): + if item in enclosing: + if contains not in colors: + stack.add(contains) + colors.add(contains) + return colors + + +def count_containing(rules: TRules, color: str) -> int: + children = rules[color] + if not children: + return 0 + + return sum([ + amount + amount * count_containing(rules, clr) + for clr, amount in children.items() + ]) + + +data = join(dirname(__file__), '../data.txt') +with open(data) as f: + rules = parse_rules(f.read()) + + color = 'shiny gold' + first = len(find_enclosing_bags(rules, color)) + print(f'We can pack the {color} into {first} bags') + + second = count_containing(rules, color) + print(f'We need to put {second} bags into {color}')