Better passport validation
This commit is contained in:
parent
03afc5a28b
commit
ffc3934487
@ -10,6 +10,8 @@ def main() -> int:
|
||||
|
||||
NoneString = typing.Optional[str]
|
||||
|
||||
VALID_EYE_COLORS = ("amb", "blu", "brn", "gry", "grn", "hzl", "oth")
|
||||
|
||||
|
||||
class Passport:
|
||||
byr: NoneString = None
|
||||
@ -22,13 +24,68 @@ class Passport:
|
||||
pid: NoneString = None
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
return all(
|
||||
[
|
||||
getattr(self, attr) is not None
|
||||
for attr in ("byr", "ecl", "eyr", "hcl", "hgt", "iyr", "pid")
|
||||
]
|
||||
return (
|
||||
self._is_year_in_range(self.byr, range(1920, 2003))
|
||||
and self._is_year_in_range(self.iyr, range(2010, 2021))
|
||||
and self._is_year_in_range(self.eyr, range(2020, 2031))
|
||||
and self._has_valid_height()
|
||||
and self._has_valid_hair_color()
|
||||
and self.ecl in VALID_EYE_COLORS
|
||||
and self._has_valid_passport_id()
|
||||
)
|
||||
|
||||
def _has_valid_height(self) -> bool:
|
||||
if self.hgt is None:
|
||||
return False
|
||||
|
||||
height_value = 0
|
||||
|
||||
height_value_string = self.hgt.replace("cm", "").replace("in", "")
|
||||
if not height_value_string.isdigit():
|
||||
return False
|
||||
|
||||
height = int(height_value_string)
|
||||
|
||||
if self.hgt.endswith("cm") and height in range(150, 194):
|
||||
return True
|
||||
elif self.hgt.endswith("in") and height in range(59, 77):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _has_valid_hair_color(self) -> bool:
|
||||
if self.hcl is None:
|
||||
return False
|
||||
|
||||
if not self.hcl.startswith("#"):
|
||||
return False
|
||||
|
||||
hair_value = self.hcl.replace("#", "")
|
||||
if len(hair_value) != 6:
|
||||
return False
|
||||
|
||||
try:
|
||||
_ = int(hair_value, 16)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def _has_valid_passport_id(self) -> bool:
|
||||
return (
|
||||
self.pid is not None
|
||||
and len(self.pid) == 9
|
||||
and all([s.isdigit() for s in list(self.pid)])
|
||||
)
|
||||
|
||||
def _is_year_in_range(self, value: NoneString, yr_range: range) -> bool:
|
||||
if value is None:
|
||||
return False
|
||||
if len(value) != 4:
|
||||
return False
|
||||
if not value.isdigit():
|
||||
return False
|
||||
return int(value) in yr_range
|
||||
|
||||
|
||||
def _read_passports(
|
||||
instream: typing.BinaryIO,
|
||||
|
Loading…
Reference in New Issue
Block a user