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)