Solution to problem 16 part 2 in Python

This commit is contained in:
David Doblas Jiménez 2022-01-01 15:53:15 +01:00
parent 78e735a5f0
commit b97958bf26

View File

@ -92,7 +92,7 @@ def part_1() -> None:
rules.append([name, valid_numbers])
# Create a single set with all rules
all_rules: Set[int] = set()
all_rules = set()
for rule in rules:
all_rules |= rule[1]
@ -110,5 +110,136 @@ def part_1() -> None:
print(f"The ticket scanning error rate is {ticket_scanning_error_rate}")
# --- Part Two ---
# Now that you've identified which tickets contain invalid values, discard
# those tickets entirely. Use the remaining valid tickets to determine which
# field is which.
# Using the valid ranges for each field, determine what order the fields appear
# on the tickets. The order is consistent between all tickets: if seat is the
# third field, it is the third field on every ticket, including your ticket.
# For example, suppose you have the following notes:
# class: 0-1 or 4-19
# row: 0-5 or 8-19
# seat: 0-13 or 16-19
# your ticket:
# 11,12,13
# nearby tickets:
# 3,9,18
# 15,1,5
# 5,14,9
# Based on the nearby tickets in the above example, the first position must be
# row, the second position must be class, and the third position must be seat;
# you can conclude that in your ticket, class is 12, row is 11, and seat is 13.
# Once you work out which field is which, look for the six fields on your
# ticket that start with the word departure. What do you get if you multiply
# those six values together?
def from_part_1():
# from part_1
rules = []
for rule in rules_raw:
name = rule.split(": ")[0]
valid_numbers = set()
for range_numbers in rule.split(": ")[1].split(" or "):
numbers = [int(number) for number in range_numbers.split("-")]
first, last = range(*numbers).start, range(*numbers).stop
list_numbers = list(range(first, last + 1))
for number in list_numbers:
valid_numbers.add(number)
rules.append([name, valid_numbers])
all_rules = set()
for rule in rules:
all_rules |= rule[1]
return rules, all_rules
def remove_invalid(all_rules):
valid_tickets = []
for line in nearby_tickets[1:]:
valid = True
for ticket in [int(t) for t in line.split(",")]:
if ticket not in all_rules:
valid = False
break
if valid:
valid_tickets.append(line)
return valid_tickets
def check_validity(rules, ticket_values):
# check validity of sets
possibles = []
for c in rules:
possibles.append([c[0], []])
for idx, ticket in enumerate(ticket_values):
valid = True
for value in ticket:
if value not in c[1]:
valid = False
break
if valid:
possibles[-1][1].append(idx)
return possibles
def get_ordered_fields(sorted_possibles):
# get each field and its respective order
ordered_fields = []
for idx, (field, values) in enumerate(sorted_possibles):
# first field
if len(values) == 1:
ordered_fields.append([field, values[0]])
else:
value = [
v for v in values if v not in sorted_possibles[idx - 1][1]
][0]
ordered_fields.append([field, value])
return ordered_fields
def part_2() -> None:
rules, all_rules = from_part_1()
valid_tickets = remove_invalid(all_rules)
# collect 20 sets of all respective values
ticket_values = [set() for x in range(len(rules))]
for line in valid_tickets:
index = 0
for element in line.split(","):
ticket_values[index].add(int(element))
index += 1
possibles = check_validity(rules, ticket_values)
# sort possibles by the length of values each set holds
sorted_possibles = sorted(possibles, key=lambda l: (len(l[1]), l))
sorted_fields = get_ordered_fields(sorted_possibles)
# parse "my ticket"
myticket = [
int(v) for elements in my_ticket[1:] for v in elements.split(",")
]
res = 1
for (field, idx) in sorted_fields:
if field.startswith("departure"):
res *= myticket[idx]
print(f"The final result is {res}")
if __name__ == "__main__":
part_1()
part_2()