-
Notifications
You must be signed in to change notification settings - Fork 0
/
dec07.py
64 lines (44 loc) · 1.45 KB
/
dec07.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python
import re
import networkx as nx
from ibidem.advent_of_code.util import get_input_name
BAG_PATTERN = re.compile(r"(\d*) ?(\w+ \w+) bags?")
TARGET = "shiny gold"
def load():
with open(get_input_name(7, 2020)) as fobj:
return fobj.read().splitlines(keepends=False)
def parse_color(spec):
m = BAG_PATTERN.match(spec)
if m:
return m.group(1), m.group(2)
raise ValueError(f"Found no color in {spec}")
def parse_network(rules):
g = nx.DiGraph()
for rule in rules:
left, right = rule.split("contain")
_, parent = parse_color(left.strip())
for spec in right.split(","):
count, child = parse_color(spec.strip())
if not count:
continue
g.add_edge(parent, child, weight=int(count))
return g
def part1():
containers = find_containers(load(), TARGET)
print(f"{len(containers)} bags can carry a {TARGET} bag")
def find_containers(rules, target):
g = parse_network(rules)
containers = nx.algorithms.dag.ancestors(g, target)
return containers
def count_children(g, target):
count = 1
for child in g.successors(target):
count += count_children(g, child) * g.out_edges[target, child]["weight"]
return count
def part2():
g = parse_network(load())
count = count_children(g, TARGET) - 1
print(f"One {TARGET} bag must contain {count} other bags")
if __name__ == "__main__":
part1()
part2()