def read_file(): with open("input.txt","r") as f: groups = f.read().split('\n\n') rules = groups[0].split('\n') your_ticket = groups[1].split('\n')[1:] tickets = groups[2].split('\n')[1:] return rules, your_ticket, tickets def find_valid_set(rule): _, ranges = rule.split(': ') range1, range2 = ranges.split(' or ') a, b = map(int,range1.split('-')) c, d = map(int,range2.split('-')) set1 = set(range(a,b+1)) set2 = set(range(c,d+1)) return set1 | set2 def find_valid_superset(rules): valid_superset = set() for rule in rules: valid_set = find_valid_set(rule) valid_superset = valid_superset | valid_set return valid_superset def part1(rules, tickets): """Add up all values not valid for any range.""" valid_set = find_valid_superset(rules) error_rate = 0 for ticket in tickets: numbers = map(int,ticket.split(',')) for number in numbers: if number not in valid_set: error_rate += number return error_rate def find_valid_tickets(tickets, rules): valid_tickets = [] valid_set = find_valid_superset(rules) for ticket in tickets: numbers = map(int,ticket.split(',')) if all([number in valid_set for number in numbers]): valid_tickets.append(ticket) return valid_tickets def parse_tickets(tickets): parsed_tickets = [] for ticket in tickets: numbers = map(int,ticket.split(',')) parsed_ticket = [int(number) for number in numbers] parsed_tickets.append(parsed_ticket) return parsed_tickets def part2(rules, your_ticket, tickets): """Find product of 6 "departure" fields.""" valid_tickets = find_valid_tickets(tickets, rules) valid_tickets += your_ticket parsed_tickets = parse_tickets(valid_tickets) your_ticket = parse_tickets(your_ticket)[0] ticket_length = len(parsed_tickets[0]) ticket_count = len(parsed_tickets) # convert rules into valid sets valid_sets = [] for i in range(ticket_length): valid_set = find_valid_set(rules[i]) valid_sets.append(valid_set) # correlate rulesets with values possibilities = [] for i in range(ticket_length): ## get all values at position values = set() for ticket in parsed_tickets: values.add(ticket[i]) ## find which rulesets match possibility = [] for j, valid_set in enumerate(valid_sets): if all([value in valid_set for value in values]): possibility.append(1) else: possibility.append(0) possibilities.append(possibility) # process of elimination to correlate ruleset to index mapping = {} for i in range(ticket_length): sums = list(map(sum, possibilities)) i = sums.index(1) ## find row with only one 1 row = possibilities[i] j = row.index(1) ## find 1 in that row mapping[j] = i for i in range(ticket_length): possibilities[i][j] = 0 # this bit only works on actual input bc there's no reason to make it robust prod = 1 for j in range(6): prod *= your_ticket[mapping[j]] return prod def main(): rules, your_ticket, tickets = read_file() print(part1(rules, tickets), part2(rules, your_ticket, tickets)) if __name__ == "__main__": main()