As the name implies, Day 4 is all about processing passports. You are given the following fields and you’ll have to do some verification steps using them:
byr (Birth Year) iyr (Issue Year) eyr (Expiration Year) hgt (Height) hcl (Hair Color) ecl (Eye Color) pid (Passport ID) cid (Country ID)
!!! SPOILERS AHEAD !!!
You should stop reading if you haven’t solved this puzzle yet!
Part 1
The first part of the challenge is to verify that all the fields are present. You will go through the input file and count all the valid passports.
My rather simplistic solution to this problem is as follows:
def process(lines: str) -> bool: """ Part 1 """ d = lines.split(' ') dd = dict([item.split(':') for item in d if item]) keys = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'] for key in keys: if key not in dd: return False return True def count_passports(data: str) -> int: pport = {} s = '' count = 0 passports = [] for line in data.split('\n'): line = line.strip() if line == '': # process count += bool(process(s)) passports.append(s) s = '' s += ' ' + line print(f"Valid passports: {count}") return count if __name__ == '__main__': with open('input.txt') as f: data = f.read() count_passports(data)
Here I parsed the line out and transformed it into a Python dictionary in my process() function. Then I looped over the keys and verified that all the required ones were present. If any of the keys were not present, then I returned False.
Part 2
This part of the challenge was quite a bit more complex. Now I had to code validation for the following:
byr (Birth Year) - four digits; at least 1920 and at most 2002. iyr (Issue Year) - four digits; at least 2010 and at most 2020. eyr (Expiration Year) - four digits; at least 2020 and at most 2030. hgt (Height) - a number followed by either cm or in: If cm, the number must be at least 150 and at most 193. If in, the number must be at least 59 and at most 76. hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f. ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth. pid (Passport ID) - a nine-digit number, including leading zeroes. cid (Country ID) - ignored, missing or not.
I took the most direct approach with this problem and used a series of conditional statements:
def process2(lines: str) -> bool: """ Part 2 """ d = lines.split(' ') dd = dict([item.split(':') for item in d if item]) keys = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'] for key in keys: if key not in dd: return False if not any([dd[key] != 4 for key in ['byr', 'iyr', 'eyr']]): return False if '1920' > dd['byr'] or dd['byr'] > '2002': return False if dd['iyr'] < "2010" or dd['iyr'] > "2020": return False if dd['eyr'] < "2020" or dd['eyr'] > "2030": return False if not any(['in' in dd['hgt'], 'cm' in dd['hgt']]): return False if 'cm' in dd['hgt']: height = int(dd['hgt'][:-2]) if height < 150 or height > 193: return False if 'in' in dd['hgt']: height = int(dd['hgt'][:-2]) if height < 59 or height > 76: return False if '#' not in dd['hcl']: return False hcl = dd['hcl'].split('#')[-1] if len(hcl) != 6: return False try: int(hcl, 16) except ValueError: return False eye_colors = ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'] if dd['ecl'] not in eye_colors: return False if len(dd['pid']) != 9: return False if dd['pid'] == '182693366': print() return True def count_passports(data: str) -> int: pport = {} s = '' count = 0 passports = [] for line in data.split('\n'): line = line.strip() if line == '': # process count += bool(process2(s)) passports.append(s) s = '' s += ' ' + line print(f"Valid passports: {count}") return count if __name__ == '__main__': with open('input.txt') as f: data = f.read() count_passports(data)
This works, but it is definitely a boring solution. I saw someone else use the voluptuous package to create a schema that they then used to validate everything. You could also create a class that does the verification steps too.
All my code is also on Github if you’d like to check it out.