Fixup day18 and add second part
[advent-of-code-2020.git] / day04 / count_valid_passports_2.py
1 #!/usr/bin/python3
2
3 REQUIRED_FIELDS=(('byr', "Birth Year"),('iyr', "Issue Year"),('eyr', "Expiration Year"),('hgt', "Height"),('hcl', "Hair Colour"),('ecl', "Eye Colour"),('pid',"Passport ID"))
4 OPTIONAL_FIELDS=(('cid', "Country ID"))
5 VALID_EYE_COLOURS=('amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth')
6
7 def check_passport(passport_data):
8     print(passport_data)
9     for field in REQUIRED_FIELDS:
10         if field[0] not in passport_data:
11             return False
12         # check the field data
13         if field[0] == 'byr':
14             if not check_year(passport_data[field[0]], 1920, 2002):
15                 return False
16         elif field[0] == 'iyr':
17             if not check_year(passport_data[field[0]], 2010, 2020):
18                 return False
19         elif field[0] == 'eyr':
20             if not check_year(passport_data[field[0]], 2020, 2030):
21                 return False
22         elif field[0] == 'hgt':
23             if not check_height(passport_data[field[0]]):
24                 return False
25         elif field[0] == 'hcl':
26             if not check_hair_colour(passport_data[field[0]]):
27                 return False
28         elif field[0] == 'ecl':
29             if not passport_data[field[0]] in VALID_EYE_COLOURS:
30                 return False
31         elif field[0] == 'pid':
32             if not check_pid(passport_data[field[0]]):
33                 return False
34     return True
35
36 def check_year(data, min_year, max_year):
37     try:
38         year = int(data)
39         if year >= min_year and year <= max_year:
40             return True
41         return False
42     except:
43         return False
44
45 def check_height(data):
46     try:
47         unit = data[-2:]
48         value = int(data[:-2])
49
50         if unit == "cm":
51             if value >= 150 and value <= 193:
52                 return True
53         elif unit == "in":
54             if value >= 59 and value <= 76:
55                 return True
56         return False
57     except:
58         return False
59
60 def check_hair_colour(data):
61     if data[0] != "#":
62         return False
63     if len(data) != 7:
64         return False
65     if data != data.lower():
66         return False
67     try:
68         value = int(data[1:], 16)
69         return True
70     except:
71         return False
72     return False
73
74 def check_pid(data):
75     # first check that the string length is correct
76     if len(data) != 9:
77         return False
78
79     # now check that it's a number
80     try:
81         int(data, 10)
82         return True
83     except:
84         return False
85
86 def main():
87     new_passport=False
88     passport_data=dict()
89     valid_passports=0
90     for line in open("input.txt"):
91         if new_passport:
92             if check_passport(passport_data):
93                 valid_passports += 1
94             passport_data.clear()
95         line=line.rstrip()
96         if line == '':
97             new_passport=True
98             continue
99         new_passport=False
100         parts=line.split(" ")
101         for part in parts:
102             (key, value) = part.split(":")
103             passport_data[key] = value
104     if not new_passport:
105         if check_passport(passport_data):
106             valid_passports += 1
107     print("Found", valid_passports, "valid passports")
108
109 main()