-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathday02.py
More file actions
59 lines (44 loc) · 1.74 KB
/
day02.py
File metadata and controls
59 lines (44 loc) · 1.74 KB
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
from collections import Counter
from typing import Callable, Tuple
from utils import elapsed_time, print_results
def parse_line(line: str) -> Tuple[Tuple[int, int], str, str]:
"""
Parse a line from input and return a tuple containing the range, letter,
and password.
"""
policy, password = line.split(':')
password = password.strip()
times, letter = policy.split(' ')
at_least, at_most = map(int, times.split('-'))
return ((at_least, at_most), letter, password)
def is_valid_times(times: Tuple[int, int],
letter: str,
password: str) -> bool:
"""
Return True if password is valid according to policy: letter appears
correct number of times.
"""
at_least, at_most = times
return Counter(password)[letter] in range(at_least, at_most + 1)
def is_valid_positions(positions: Tuple[int, int],
letter: str,
password: str) -> bool:
"""
Return True if password is valid according to policy: letter appears
at the correct location.
"""
i, j = positions
i -= 1
j -= 1
return ((password[i] == letter and password[j] != letter) or
(password[i] != letter and password[j] == letter))
def count_valid_passwords(filename: str, validation_fn: Callable) -> int:
return sum(validation_fn(*parse_line(line)) for line in open(filename))
def part1(filename: str) -> int:
return count_valid_passwords(filename, is_valid_times)
def part2(filename: str) -> int:
return count_valid_passwords(filename, is_valid_positions)
if __name__ == '__main__':
puzzle_input = 'input_day02.txt'
print_results(elapsed_time(part1, puzzle_input),
elapsed_time(part2, puzzle_input))