Advent of Code: Day #04 - Passport Processing
5-6 minutes
Introduction
Today we need to write a passport validation system that accepts our North Pole credentials.
Task One
Each passport is represent by key:value pairs in the input data. A valid passport must have a birth year, issue year, expiration year, height, hair colour, passport ID and may, or may not, have a country ID.
Reading in the data
A new passports data begins after a new line and ends at the next so we add the line to a variable until we reach a new line. Once we have gathered all of the data we can use a dictionary and list comprehension to convert the input string into a Python dictionary. The input text file does not have a new line at the end, since we are using a new line as a signal that the data has ended this causes us to miss the last passport in the file. To fix this I just manually added the last passport outside of the loop.
def read_data(path):passports = []passport = ""with open(path, "r") as file:for line in file.readlines():if line.rstrip() != "":passport += " " + line.rstrip()else:tmp = passport.strip().split()passports.append({key: value for (key, value)in [x.split(":") for x in tmp]})passport = ""# No new line at end of input so we manually add the lastpassport out of the for looptmp = passport.strip().split()passports.append({key: value for (key, value)in [x.split(":") for x in tmp]})return passports
The Solution
Since we know that a valid passport must contain a birth year, issue year, expiration year, height, hair colour and passport ID but country ID is optional we can pop the country ID value from passports that have it then check how many values the passport has. If it has 7 values then it is valid.
def task_one(passports):valid = 0for passport in passports:try:passport.pop("cid")except KeyError:passvalid += 1 if len(passport.keys()) == 7 else 0return valid
Task Two
The Solution
In task two we had to verify each field of the passport and ensure they met a certain criteria. To do this i first repeated the code from task 1 since passports still need 7 fields, from there I used a while loop to check each field. This way as soon as one is false we break straight away and don't have to bother checking the rest of the fields since all fields must be valid for the passport to be valid.
def task_two(passports):valid = 0for passport in passports:try:passport.pop("cid")except KeyError:passif len(passport.keys()) != 7:# Still need all 7 to be validcontinueelse:validity = Truewhile validity:validity = validity and (1920 <= int(passport["byr"]) <= 2002)validity = validity and (2010 <= int(passport["iyr"]) <= 2020)validity = validity and (2020 <= int(passport["eyr"]) <= 2030)validity = validity and (passport["hgt"][-2:] == "in" or passport["hgt"][-2:] == "cm")validity = validity and (passport["hcl"][0] == "#" and len(passport["hcl"]) == 7)validity = validity and (passport["ecl"] in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"])validity = validity and (len(passport["pid"]) == 9)if passport["hgt"][-2:] == "in":validity = (validity and 59 <= int(passport["hgt"][:-2]) <= 76)elif passport["hgt"][-2:] == "cm":validity = (validity and 150 <= int(passport["hgt"][:-2]) <= 193)breakvalid += validityreturn valid
Links
Leaderboard Code: 353270-1fc6ef28
Github Repository A link to the github repo containing all the days.
main.py A direct download of the main.py script
2.4Kb