122 lines
3.1 KiB
Python
Executable File
122 lines
3.1 KiB
Python
Executable File
#! /usr/bin/env python3
|
|
|
|
import re
|
|
|
|
|
|
def height_validator(x):
|
|
match = re.match(r"^([0-9]+)(cm|in)$", x.strip())
|
|
if not match:
|
|
return False
|
|
if match.group(2) == "cm":
|
|
return 150 <= int(match.group(1)) <= 193
|
|
elif match.group(2) == "in":
|
|
return 59 <= int(match.group(1)) <= 76
|
|
return False
|
|
|
|
|
|
required_keys = {
|
|
"byr": lambda x: 1920 <= int(x) <= 2002,
|
|
"iyr": lambda x: 2010 <= int(x) <= 2020,
|
|
"eyr": lambda x: 2020 <= int(x) <= 2030,
|
|
"hgt": height_validator,
|
|
"hcl": lambda x: re.match(r"^#[0-9a-f]{6}$", x.strip()),
|
|
"ecl": lambda x: x in ("amb", "blu", "brn", "gry", "grn", "hzl", "oth"),
|
|
"pid": lambda x: re.match(r"^[0-9]{9}$", x.strip()),
|
|
}
|
|
|
|
optional_keys = {
|
|
"cid": lambda x: True,
|
|
}
|
|
|
|
|
|
class Passport(object):
|
|
|
|
def __init__(self, s):
|
|
self.d = {}
|
|
for kvp in s.split():
|
|
parts = kvp.partition(":")
|
|
self.d[parts[0]] = parts[2]
|
|
|
|
def key_set(self):
|
|
return set(self.d.keys())
|
|
|
|
def is_valid(self, deep=False):
|
|
valid = set(required_keys.keys()) <= self.key_set()
|
|
if not valid or not deep:
|
|
# print(f"Valid: {valid}. Missing: {set(required_keys.keys()) - self.key_set()}")
|
|
return valid
|
|
|
|
for key, validator in required_keys.items():
|
|
valid = validator(self.d[key])
|
|
if not valid:
|
|
# print(f"Invalid value for {key}: {self.d[key]}")
|
|
return False
|
|
# print("Valid!", self.d)
|
|
return valid
|
|
|
|
|
|
def parse_passport(buffer):
|
|
s = " ".join(buffer)
|
|
return Passport(s)
|
|
|
|
|
|
def part1():
|
|
num_valid = 0
|
|
total_passports = 0
|
|
with open("input.txt") as f:
|
|
buffer = []
|
|
for line in f:
|
|
line = line.strip()
|
|
if line == "":
|
|
p = parse_passport(buffer)
|
|
total_passports += 1
|
|
if p.is_valid():
|
|
num_valid += 1
|
|
buffer = []
|
|
else:
|
|
buffer.append(line)
|
|
# if total_passports == 4:
|
|
# break
|
|
if buffer:
|
|
p = parse_passport(buffer)
|
|
total_passports += 1
|
|
if p.is_valid():
|
|
num_valid += 1
|
|
|
|
print("Total passports:", total_passports)
|
|
print("Total valid passports:", num_valid)
|
|
|
|
|
|
def part2():
|
|
num_valid = 0
|
|
total_passports = 0
|
|
# with open("valid.txt") as f:
|
|
# with open("invalid.txt") as f:
|
|
with open("input.txt") as f:
|
|
buffer = []
|
|
for line in f:
|
|
line = line.strip()
|
|
if line == "":
|
|
p = parse_passport(buffer)
|
|
total_passports += 1
|
|
if p.is_valid(deep=True):
|
|
num_valid += 1
|
|
buffer = []
|
|
else:
|
|
buffer.append(line)
|
|
# if total_passports == 4:
|
|
# break
|
|
if buffer:
|
|
p = parse_passport(buffer)
|
|
total_passports += 1
|
|
if p.is_valid(deep=True):
|
|
num_valid += 1
|
|
|
|
print("Total passports:", total_passports)
|
|
print("Total valid passports:", num_valid)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
part1()
|
|
part2()
|