-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday11.py
108 lines (75 loc) · 2.16 KB
/
day11.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
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env python3
import sys
from more_itertools import windowed
INVALID_LETTERS = set(ord(c) for c in 'iol')
def has_straight(password):
for a, b, c in windowed(reversed(password), 3):
if b == a + 1 and c == a + 2:
return True
return False
def has_invalid_letters(password):
for c in password:
if c in INVALID_LETTERS:
return True
return False
def has_overlapping_pairs(password):
first_pair = None
first_pair_idx = -1
for i, (a, b) in enumerate(windowed(reversed(password), 2)):
if a != b:
continue
if first_pair is None:
first_pair = a
first_pair_idx = i
continue
if a != first_pair and i > first_pair_idx + 1:
return True
return False
def is_valid(password):
return has_straight(password) \
and not has_invalid_letters(password) \
and has_overlapping_pairs(password)
def parse_password(line):
password = [ord(c) - ord('a') for c in line]
password.reverse()
return password
def next_password(password):
idx = 0
while True:
if idx > len(password) - 1:
password.append(1)
break
password[idx] += 1
carry = password[idx] > 25
if not carry:
break
password[idx] = 0
idx += 1
return password
def password_to_str(password):
res = [chr(c + ord('a')) for c in password]
res.reverse()
return "".join(res)
def part1(lines):
password = parse_password(lines[0].strip())
while True:
password = next_password(password)
if is_valid(password):
break
return password_to_str(password)
def part2(lines):
password = parse_password(lines[0].strip())
count = 0
while True:
password = next_password(password)
if is_valid(password):
count += 1
if count == 2:
break
return password_to_str(password)
def main():
lines = sys.stdin.read().strip().split("\n")
print("Part1: {}".format(part1(lines)))
print("Part2: {}".format(part2(lines)))
if __name__ == "__main__":
main()