aoc/2020/16/16.py

102 lines
3 KiB
Python

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