This commit is contained in:
cupcakearmy 2020-12-07 10:03:42 +01:00
parent ad6001e572
commit 791b94827e
2 changed files with 85 additions and 0 deletions

15
solutions/7/README.md Normal file
View File

@ -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.
<details>
<summary>Solutions</summary>
<ol>
<li>164</li>
<li>7872</li>
</ol>
</details>

View File

@ -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}')