# /usr/bin/env python3 import re from collections import defaultdict """ identify invalid nearby tickets by considering only whether tickets contain values that are not valid for any field. """ def main(): rules, my_ticket, tickets = open("input.txt").read().split("\n\n") rules = parse_fields(rules) tickets = tickets.splitlines()[1:] print("Ticket scanning error rate ", part1(tickets, rules)) part2(tickets, rules) def parse_fields(fields): fields_dict = {} for field in fields.splitlines(): k, v = field.split(": ") ranges = re.findall(r"(\d+)-(\d+)", v) fields_dict[k] = [range(int(r[0]), int(r[1]) + 1) for r in ranges] return fields_dict def part1(tickets, rules): scanning_error_rate = 0 for ticket in tickets: scanning_error_rate += sum(validate_ticket(ticket, rules)) return scanning_error_rate def validate_ticket(ticket, rules): invalid_fields = [] for value in ticket.split(","): value = int(value) validations = (any(value in r for r in rule) for rule in rules.values()) if not any(validations): invalid_fields.append(value) return invalid_fields def part2(tickets, rules): # filter only valid tickets valid_tickets = [ticket for ticket in tickets if validate_ticket(ticket, rules) == []] # field => [matching_rules] # eliminate field with only one matching rule all_matching_rules = {} for ticket in valid_tickets: possible_matching_rules = defaultdict(set) for field_index, field_value in enumerate(ticket.split(",")): field_value = int(field_value) for name, rule in rules.items(): match = {r: field_value in r for r in rule} if any(match.values()): possible_matching_rules[name].add(field_index) all_matching_rules[ticket]= possible_matching_rules a = 1 # repeat if __name__ == "__main__": main()