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
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)
|