Advent of Code 2020, day 4
It’s day 4… As before, all my solutions are available on https://git.sr.ht/~schnouki/advent-of-code.
Today we’re dealing with passport validation. Spoiler alert: as often with data validation issues, it’s pretty boring…
Okay, let’s parse those passports. Split input when there are 2 newlines, split each block on whitespace, parse key:value
entries. Boring!
class Passport(dict):
@classmethod
def from_kv_str(cls, data: str) -> "Passport":
res = cls()
for field in data.split():
k, v = field.split(":", 1)
res[k] = v
return res
data = [Passport.from_kv_str(block) for block in raw_data.split("\n\n")]
Part 1
In this part we just need to check if all required fields are present in the passport. Nothing about their values, even empty strings are OK. Meh.
class Passport(dict):
@property
def is_valid_p1(self) -> bool:
return all(
field in self for field in ("byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid")
)
print(sum(1 for p in data if p.is_valid_p1))
Done. 0.18 ms. Boring.
Part 2
Now we need to validate data. A few years with min/max, a height in cm or in, a hex color, a value in a set, and a number of a specific length… Meh, I don’t even want to try to make that fun.
import re
RE_HEIGHT = re.compile(r"^(\d+)(cm|in)$")
RE_COLOR = re.compile(r"^#[0-9a-f]{6}$")
class Passport(dict):
@property
def is_valid_p2(self) -> bool:
checks = [
self._check_year("byr", 1920, 2002),
self._check_year("iyr", 2010, 2020),
self._check_year("eyr", 2020, 2030),
self._check_height(),
RE_COLOR.match(self.get("hcl", "")),
self.get("ecl") in ("amb", "blu", "brn", "gry", "grn", "hzl", "oth"),
len(self.get("pid", "")) == 9 and self.get("pid", "").isdigit(),
]
return all(checks)
def _check_year(self, field: str, min: int, max: int) -> bool:
if field not in self:
return False
try:
return min <= int(self[field]) <= max
except ValueError:
return False
def _check_height(self) -> bool:
if "hgt" not in self:
return False
if (m := RE_HEIGHT.match(self["hgt"])) :
min, max = (150, 193) if m.group(2) == "cm" else (59, 76)
return min <= int(m.group(1)) <= max
return False
Validation is pretty minimal, but that’s enough for this case as we’re dealing with well-behaved input anyway. 0.53 ms. Only cool thing: I got to use Python’s new walrus operator. Yay?
Comments
Join the conversation by sending an email. Your comment will be added here and to the public inbox after moderation.