Files
python-aoc-2020/day16/part2.py
Sebastian Seedorf 8ed70a63a9 Day 16
2020-12-16 12:46:38 +01:00

91 lines
2.5 KiB
Python

#!/usr/bin/env python3
import re
def yield_spans(gs: dict):
for g in gs.values():
yield g[:2]
yield g[2:]
def in_spans(x, spans):
for span in spans:
if span[0] <= x <= span[1]:
return True
return False
lines = (x.strip() for x in open("input.txt"))
REGEX_RANGES = re.compile(r"^([a-z ]+): (\d+)-(\d+) or (\d+)-(\d+)$")
groups = {}
your = ()
nearby = []
read_step = 0
group_keys = []
group_cols = []
for line in lines:
if read_step == 0:
if line == "":
read_step = 1
continue
match = REGEX_RANGES.match(line)
groups[match[1]] = list(map(int, match.groups()[1:]))
elif read_step == 1:
if line == "":
read_step = 2
continue
if line.startswith("your"):
continue
your = list(map(int, line.split(',')))
elif read_step == 2:
if line.startswith("nearby"):
continue
nearby.append(list(map(int, line.split(','))))
group_keys = list(groups.keys())
group_cols = [-1]*len(group_keys)
valid_spans = []
for span in yield_spans(groups):
start_idx = next((i for i, v in enumerate(valid_spans) if span[0] <= v[1]), len(valid_spans))
end_idx = next((len(valid_spans)-i for i, v in enumerate(valid_spans[::-1]) if span[1] >= v[0]), 0)
for idx in range(start_idx, end_idx):
popped = valid_spans.pop(start_idx)
span = (min(popped[0], span[0]), max(popped[1], span[1]))
valid_spans.insert(start_idx, tuple(span))
print("Valid Spans:", valid_spans)
valid_tickets = filter(lambda n: not any(True for x in n if not in_spans(x, valid_spans)), nearby)
cnt_grp = len(groups)
classes = [2**cnt_grp - 1] * len(your)
for ticket in valid_tickets:
for ig, key in enumerate(group_keys):
spans = groups[key]
spans = tuple(zip(spans[::2], spans[1::2]))
for it, t in enumerate(ticket):
if not in_spans(t, spans):
classes[it] &= ~(2**ig)
print("Possible Columns:", list(map(lambda x: format(x, '0'+str(cnt_grp)+'b')[::-1], classes)))
fixed = 0
for _ in range(len(your)):
col, power_two = next(((i, v) for i, v in enumerate(classes) if not (v & (v-1)) and v > 0))
pos = power_two.bit_length()-1
fixed |= power_two
classes = list(map(lambda x: x & ~fixed, classes))
group_cols[pos] = col
print("Mapping:", dict(zip(group_keys, group_cols)))
result = 1
for name, col in zip(group_keys, group_cols):
if name.startswith("departure"):
result *= your[col]
print(result)