Solution to problem 16 in Python (failed mypy :()
This commit is contained in:
114
src/P16.py
Normal file
114
src/P16.py
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# --- Day 16: Ticket Translation ---
|
||||||
|
|
||||||
|
# As you're walking to yet another connecting flight, you realize that one of
|
||||||
|
# the legs of your re-routed trip coming up is on a high-speed train. However,
|
||||||
|
# the train ticket you were given is in a language you don't understand. You
|
||||||
|
# should probably figure out what it says before you get to the train station
|
||||||
|
# after the next flight.
|
||||||
|
|
||||||
|
# Unfortunately, you can't actually read the words on the ticket. You can,
|
||||||
|
# however, read the numbers, and so you figure out the fields these tickets
|
||||||
|
# must have and the valid ranges for values in those fields.
|
||||||
|
|
||||||
|
# You collect the rules for ticket fields, the numbers on your ticket, and the
|
||||||
|
# numbers on other nearby tickets for the same train service (via the airport
|
||||||
|
# security cameras) together into a single document you can reference (your
|
||||||
|
# puzzle input).
|
||||||
|
|
||||||
|
# The rules for ticket fields specify a list of fields that exist somewhere on
|
||||||
|
# the ticket and the valid ranges of values for each field. For example, a rule
|
||||||
|
# like class: 1-3 or 5-7 means that one of the fields in every ticket is named
|
||||||
|
# class and can be any value in the ranges 1-3 or 5-7 (inclusive, such that 3
|
||||||
|
# and 5 are both valid in this field, but 4 is not).
|
||||||
|
|
||||||
|
# Each ticket is represented by a single line of comma-separated values. The
|
||||||
|
# values are the numbers on the ticket in the order they appear; every ticket
|
||||||
|
# has the same format. For example, consider this ticket:
|
||||||
|
|
||||||
|
# .--------------------------------------------------------.
|
||||||
|
# | ????: 101 ?????: 102 ??????????: 103 ???: 104 |
|
||||||
|
# | |
|
||||||
|
# | ??: 301 ??: 302 ???????: 303 ??????? |
|
||||||
|
# | ??: 401 ??: 402 ???? ????: 403 ????????? |
|
||||||
|
# '--------------------------------------------------------'
|
||||||
|
|
||||||
|
# Here, ? represents text in a language you don't understand. This ticket might
|
||||||
|
# be represented as 101,102,103,104,301,302,303,401,402,403; of course, the
|
||||||
|
# actual train tickets you're looking at are much more complicated. In any
|
||||||
|
# case, you've extracted just the numbers in such a way that the first number
|
||||||
|
# is always the same specific field, the second number is always a different
|
||||||
|
# specific field, and so on - you just don't know what each position actually
|
||||||
|
# means!
|
||||||
|
|
||||||
|
# Start by determining which tickets are completely invalid; these are tickets
|
||||||
|
# that contain values which aren't valid for any field. Ignore your ticket for
|
||||||
|
# now.
|
||||||
|
|
||||||
|
# For example, suppose you have the following notes:
|
||||||
|
|
||||||
|
# class: 1-3 or 5-7
|
||||||
|
# row: 6-11 or 33-44
|
||||||
|
# seat: 13-40 or 45-46
|
||||||
|
|
||||||
|
# your ticket:
|
||||||
|
# 7,1,14
|
||||||
|
|
||||||
|
# nearby tickets:
|
||||||
|
# 7,3,47
|
||||||
|
# 40,4,50
|
||||||
|
# 55,2,20
|
||||||
|
# 38,6,12
|
||||||
|
|
||||||
|
# It doesn't matter which position corresponds to which field; you can identify
|
||||||
|
# invalid nearby tickets by considering only whether tickets contain values
|
||||||
|
# that are not valid for any field. In this example, the values on the first
|
||||||
|
# nearby ticket are all valid for at least one field. This is not true of the
|
||||||
|
# other three nearby tickets: the values 4, 55, and 12 are are not valid for
|
||||||
|
# any field. Adding together all of the invalid values produces your ticket
|
||||||
|
# scanning error rate: 4 + 55 + 12 = 71.
|
||||||
|
|
||||||
|
# Consider the validity of the nearby tickets you scanned. What is your ticket
|
||||||
|
# scanning error rate?
|
||||||
|
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
|
with open("files/P16.txt", "r") as f:
|
||||||
|
rules_raw, my_ticket, nearby_tickets = [
|
||||||
|
f.split("\n") for f in f.read().strip().split("\n\n")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def part_1() -> None:
|
||||||
|
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])
|
||||||
|
|
||||||
|
# Create a single set with all rules
|
||||||
|
all_rules: Set[int] = set()
|
||||||
|
for rule in rules:
|
||||||
|
all_rules |= rule[1]
|
||||||
|
|
||||||
|
all_tickets = [list(map(int, o.split(","))) for o in nearby_tickets[1:]]
|
||||||
|
|
||||||
|
ticket_scanning_error_rate = sum(
|
||||||
|
[
|
||||||
|
ticket
|
||||||
|
for ticket_numbers in all_tickets
|
||||||
|
for ticket in ticket_numbers
|
||||||
|
if ticket not in all_rules
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"The ticket scanning error rate is {ticket_scanning_error_rate}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
part_1()
|
||||||
Reference in New Issue
Block a user