| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- #!/usr/bin/env python3
- import sys
- import re
- def parse_rule(rule):
- if ':' not in rule:
- return 0, (1, 4000), rule
- left, op, right, _, destination = re.split('([<>:])', rule)
- rating = 'xmas'.index(left)
- rating_range = (1, int(right) - 1) if op == '<' else (int(right) + 1, 4000)
- return rating, rating_range, destination
- def parse(inp):
- flows = {}
- for line in inp:
- if line == '\n':
- break
- flow, rule_strings = line[:-2].split('{')
- flows[flow] = list(map(parse_rule, rule_strings.split(',')))
- parts = [tuple(map(int, re.findall(r'\d+', line))) for line in inp]
- return flows, parts
- def at(ranges, i, lower, upper):
- return *ranges[:i], (lower, upper), *ranges[i + 1:]
- def naccept(ranges, flows, flow):
- if flow == 'R':
- return 0
- if flow == 'A':
- x, m, a, s = (upper - lower + 1 for lower, upper in ranges)
- return x * m * a * s
- acc = 0
- for i, (imin, imax), dst in flows[flow]:
- rmin, rmax = ranges[i]
- lower = max(rmin, imin)
- upper = min(rmax, imax)
- if upper >= lower:
- acc += naccept(at(ranges, i, lower, upper), flows, dst)
- if rmin < imin:
- acc += naccept(at(ranges, i, rmin, imin - 1), flows, flow)
- if rmax > imax:
- acc += naccept(at(ranges, i, imax + 1, rmax), flows, flow)
- break
- return acc
- flows, parts = parse(sys.stdin)
- print(sum(sum(p) for p in parts if naccept(tuple(zip(p, p)), flows, 'in')))
- print(naccept(((1, 4000),) * 4, flows, 'in'))
|