#! /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()