98 lines
2.3 KiB
Python
98 lines
2.3 KiB
Python
|
|
import re
|
||
|
|
from solutions import BaseSolution
|
||
|
|
|
||
|
|
|
||
|
|
class Solution(BaseSolution):
|
||
|
|
input_file = "04.txt"
|
||
|
|
|
||
|
|
def __str__(self):
|
||
|
|
return "Day 4: Passport Processing"
|
||
|
|
|
||
|
|
def parse_input(self, data):
|
||
|
|
return [f"{' '.join(sorted(pp.split()))} " for pp in data.split("\n\n")]
|
||
|
|
|
||
|
|
def solve(self, puzzle_input):
|
||
|
|
return sum(map(has_required_fields, puzzle_input))
|
||
|
|
|
||
|
|
def solve_again(self, puzzle_input):
|
||
|
|
return sum(
|
||
|
|
map(
|
||
|
|
lambda pp: has_required_fields(pp) and has_valid_values(pp),
|
||
|
|
puzzle_input,
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def has_required_fields(data):
|
||
|
|
return all(
|
||
|
|
f"{k}:" in data for k in ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def has_valid_values(data):
|
||
|
|
valid_hgt = lambda d: valid_height(d)
|
||
|
|
valid_byr = lambda d: valid_range(d, "byr", 1920, 2002)
|
||
|
|
valid_iyr = lambda d: valid_range(d, "iyr", 2010, 2020)
|
||
|
|
valid_eyr = lambda d: valid_range(d, "eyr", 2020, 2030)
|
||
|
|
valid_hcl = lambda d: valid_hex_color(data)
|
||
|
|
valid_ecl = lambda d: exactly_1_valid_eye_color(data)
|
||
|
|
valid_pid = lambda d: valid_password_id(d)
|
||
|
|
|
||
|
|
return all(
|
||
|
|
validator(data)
|
||
|
|
for validator in [
|
||
|
|
valid_byr,
|
||
|
|
valid_iyr,
|
||
|
|
valid_eyr,
|
||
|
|
valid_hgt,
|
||
|
|
valid_hcl,
|
||
|
|
valid_ecl,
|
||
|
|
valid_pid,
|
||
|
|
]
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def valid_height(data):
|
||
|
|
values = re.findall(r"hgt:([\d+?]{2,3})(in|cm) ", data)
|
||
|
|
if len(values) != 1:
|
||
|
|
return False
|
||
|
|
value, unit = values[0]
|
||
|
|
if unit == "in":
|
||
|
|
return int(value) in range(59, 77)
|
||
|
|
elif unit == "cm":
|
||
|
|
return int(value) in range(150, 194)
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def valid_range(data, k, a, b):
|
||
|
|
value = re.search(k + r":([\d]{4}) ", data)
|
||
|
|
if not value:
|
||
|
|
return False
|
||
|
|
return int(value[1]) in range(a, b + 1)
|
||
|
|
|
||
|
|
|
||
|
|
def valid_hex_color(data):
|
||
|
|
return re.search(r"hcl:#([0-9abcdef]{6}) ", data) != None
|
||
|
|
|
||
|
|
|
||
|
|
def exactly_1_valid_eye_color(data):
|
||
|
|
return (
|
||
|
|
sum(
|
||
|
|
f"ecl:{cl} " in data
|
||
|
|
for cl in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
|
||
|
|
)
|
||
|
|
== 1
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def valid_password_id(data):
|
||
|
|
value = re.search(r"pid:([\d+?]{9}) ", data)
|
||
|
|
if not value:
|
||
|
|
return False
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
solution = Solution()
|
||
|
|
solution.show_results()
|