-
Notifications
You must be signed in to change notification settings - Fork 1
/
day02_passwords.py
97 lines (71 loc) · 2.71 KB
/
day02_passwords.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from collections import Counter
import re
from typing import List, NamedTuple
PASSWORD_PATTERN = r"(?P<num1>\d+)-(?P<num2>\d+) (?P<letter>[a-z]): (?P<password>[a-z]+)"
class Password(NamedTuple):
num1: int
num2: int
letter: str
password: str
def load_input(lines: List[str]) -> List[Password]:
p = re.compile(PASSWORD_PATTERN)
passwords = []
for line in lines:
cleaned_line = line.strip()
m = p.match(cleaned_line)
password = Password(
num1=int(m.group("num1")),
num2=int(m.group("num2")),
letter=m.group("letter"),
password=m.group("password"),
)
passwords.append(password)
return passwords
def find_valid_password__old_policy(passwords: List[Password]) -> List[Password]:
"""
- num1 is min times letter appears
- num2 is max times letter appears
valid if letter appears between num1 and num2
"""
valid_passwords = []
for password in passwords:
counter = Counter(password.password)
if password.num1 <= counter[password.letter] <= password.num2:
valid_passwords.append(password)
return valid_passwords
def test_valid_passwords__old_policy():
TEST_INPUT="""1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc""".split("\n")
passwords = load_input(TEST_INPUT)
valid_passwords = find_valid_password__old_policy(passwords)
assert len(valid_passwords) == 2
def find_valid_password__new_policy(passwords: List[Password]) -> List[Password]:
"""
- num1 is 1-index position letter appears
- num2 is 1-index position letter apperas
valid if letter is in either num1 or num2 position
"""
valid_passwords = []
for password in passwords:
first_position = password.password[password.num1 - 1]
second_position = password.password[password.num2 - 1]
if first_position == second_position == password.letter:
continue
if first_position == password.letter or second_position == password.letter:
valid_passwords.append(password)
return valid_passwords
def test_find_valid_password__new_policy():
TEST_INPUT="""1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc""".split("\n")
passwords = load_input(TEST_INPUT)
valid_passwords = find_valid_password__new_policy(passwords)
assert len(valid_passwords) == 1
if __name__ == "__main__":
with open("2020/data/day02_input.txt") as f:
passwords = load_input(f.readlines())
valid_passwords = find_valid_password__old_policy(passwords)
print(f"Part 1 answer is {len(valid_passwords)}")
valid_passwords = find_valid_password__new_policy(passwords)
print(f"Part 2 answer is {len(valid_passwords)}")