You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
2.3 KiB
Python

4 years ago
import re
rules = []
my_ticket = None
tickets = []
with open('input', 'r') as f:
line = f.readline() # heading rules
while line != '\n':
rules.append(line)
line = f.readline()
f.readline() # heading my_ticket
my_ticket = f.readline()
f.readline() # newline
f.readline() # heading tickets
tickets = f.readlines()
def parse_ticket(raw):
return list(map(int, raw.split(',')))
def parse_rule(raw):
return list(map(int, re.findall('[0-9]+', raw))) + [raw.split(':')[0]]
def in_range(num, lower, upper):
return num >= lower and num <= upper
my_ticket = parse_ticket(my_ticket)
tickets = list(map(parse_ticket, tickets))
rules = list(map(parse_rule, rules))
mappings_per_num = []
for num_idx in range(len(my_ticket)):
mappings_per_num.append(set(range(len(rules))))
def is_valid(ticket):
for num in ticket:
matches_any_rule = False
for idx, rule in enumerate(rules):
minA, maxA, minB, maxB, _ = rule
if in_range(num, minA, maxA) or in_range(num, minB, maxB):
matches_any_rule = True
if not matches_any_rule:
return False
return True
tickets = list(filter(is_valid, tickets))
# tickets = tickets + [my_ticket]
for ticket in tickets:
for num_idx, num in enumerate(ticket):
for rule_idx, rule in enumerate(rules):
minA, maxA, minB, maxB, _ = rule
if not(in_range(num, minA, maxA) or in_range(num, minB, maxB)):
mappings_per_num[num_idx].remove(rule_idx)
final_mapping = [None] * len(rules)
rules_assigned = set()
for num_idx, mapping in enumerate(mappings_per_num):
print(f'Num #{num_idx:>2}: Possible rules: {mapping}')
while len(rules_assigned) != len(rules):
for num_idx, rule_indices in enumerate(mappings_per_num):
diff = rule_indices.difference(rules_assigned)
if len(diff) == 1:
rule_idx = diff.pop()
final_mapping[rule_idx] = num_idx
rules_assigned.add(rule_idx)
print(f'Mapped rule #{rule_idx:>2} to num #{num_idx:>2}')
solution = 1
for rule_idx, (_, _, _, _, name) in enumerate(rules):
if name.startswith('departure'):
num_idx = final_mapping[rule_idx]
solution *= my_ticket[num_idx]
print('Solution:', solution)