Advent of Code: Day #04 - Passport Processing

4th of December 2020 |

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.

Python Copy
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 last
passport out of the for loop
tmp = 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.

Python Copy
def task_one(passports):
valid = 0
for passport in passports:
try:
passport.pop("cid")
except KeyError:
pass
valid += 1 if len(passport.keys()) == 7 else 0
return 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.

Python Copy
def task_two(passports):
valid = 0
for passport in passports:
try:
passport.pop("cid")
except KeyError:
pass
if len(passport.keys()) != 7:
# Still need all 7 to be valid
continue
else:
validity = True
while 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)
break
valid += validity
return valid

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