Created
December 4, 2020 10:59
-
-
Save seblin/154714ccb95fc654855a4995a9b3e710 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://adventofcode.com/2020/day/4 | |
from operator import methodcaller | |
from pathlib import Path | |
INPUT_FILE = Path(__file__).parent / "input.txt" | |
class Document: | |
PASSPORT_KEYS = { | |
"byr", # (Birth Year) | |
"iyr", # (Issue Year) | |
"eyr", # (Expiration Year) | |
"hgt", # (Height) | |
"hcl", # (Hair Color) | |
"ecl", # (Eye Color) | |
"pid", # (Passport ID) | |
"cid", # (Country ID) | |
} | |
NORTHPOLE_CREDENTIALS = PASSPORT_KEYS - {"cid"} | |
def __init__(self, mapping): | |
self.mapping = mapping | |
def is_valid(self): | |
validators = [ | |
getattr(self, name) for name in dir(self) | |
if name.startswith("has_valid") | |
] | |
return ( | |
self.has_valid_keys() | |
and all(valid() for valid in validators) | |
) | |
def has_valid_keys(self): | |
return ( | |
self.mapping.keys() == self.PASSPORT_KEYS | |
or self.mapping.keys() == self.NORTHPOLE_CREDENTIALS | |
) | |
def has_valid_birth_year(self): | |
return 1920 <= int(self.mapping["byr"]) <= 2002 | |
def has_valid_issue_year(self): | |
return 2010 <= int(self.mapping["iyr"]) <= 2020 | |
def has_valid_expiration_year(self): | |
return 2020 <= int(self.mapping["eyr"]) <= 2030 | |
def has_valid_height(self): | |
height = self.mapping["hgt"][:-2] | |
unit = self.mapping["hgt"][-2:] | |
return ( | |
unit == "cm" and 150 <= int(height) <= 193 | |
or unit == "in" and 59 <= int(height) <= 76 | |
) | |
def has_valid_hair_color(self): | |
prefix, *code = self.mapping["hcl"] | |
allowed = set("0123456789abcdef") | |
return ( | |
prefix == "#" and len(code) == 6 | |
and set(code) <= allowed | |
) | |
def has_valid_eye_color(self): | |
valid_colors = [ | |
"amb", "blu", "brn", "gry", "grn", "hzl", "oth" | |
] | |
return self.mapping["ecl"] in valid_colors | |
def has_valid_passport_id(self): | |
pid = self.mapping["pid"] | |
return pid.isdigit() and len(pid) == 9 | |
@classmethod | |
def from_stream(cls, stream): | |
mapping = {} | |
for line in stream: | |
if not line.strip(): | |
break | |
for part in line.split(): | |
key, value = part.split(":") | |
mapping[key] = value | |
return cls(mapping) | |
def get_documents(stream): | |
while True: | |
document = Document.from_stream(stream) | |
if not document.mapping: | |
break | |
yield document | |
def main(): | |
with INPUT_FILE.open() as stream: | |
documents = list(get_documents(stream)) | |
for validator in ("has_valid_keys", "is_valid"): | |
num_valid = sum(map(methodcaller(validator), documents)) | |
print(validator, num_valid) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment