summaryrefslogtreecommitdiffstats
path: root/11/solution.py
blob: 5c044b3384e857fd971fbda1b739beb4381a4fe8 (plain)
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
"""Advent of code 2015 day 11"""

def next_password(password: str) -> str:
    """Increment the password
    "a" -> "b"
    "az" -> "ba"
    """
    if password[-1] == 'z':
        return next_password(password[:-1]) + 'a'
    else:
        return password[:-1] + chr(ord(password[-1]) + 1)

def has_straight(password: str) -> bool:
    """Check if a password contains a sequence of at least three consecutive characters"""
    for i in range(len(password) - 2):
        if ord(password[i]) + 1 == ord(password[i+1]) and ord(password[i+1]) + 1 == ord(password[i+2]):
            return True
    return False

def has_pair(password: str) -> bool:
    """Check if a password contains at least one pair of letters"""
    for i in range(len(password) - 1):
        if password[i] == password[i+1]:
            return True
    return False

def has_pairs(password: str) -> bool:
    """Check if a password contains at least two different, non-overlapping pairs of letters"""
    for i in range(len(password) - 1):
        if password[i] == password[i+1]:
            return has_pair(password[i+2:])
    return False

def is_valid(password: str) -> bool:
    """Check if password is valid
    Password must:
    - include one increasing straight of at least three letters
    - may not contain i, o or l
    - must contain at least two different, non-overlapping pairs of letters
    "hijklmmn" -> False
    "abbceffg" -> True
    "abbcegjk" -> False
    """
    if not has_straight(password):
        return False
    if not has_pairs(password):
        return False
    if 'i' in password or 'o' in password or 'l' in password:
        return False
    return True

def part1(password: str) -> str:
    """Find the next valid password"""
    password = next_password(password)
    while not is_valid(password):
        password = next_password(password)
    return password

def part2(password: str) -> str:
    """Find the next valid password"""
    password = next_password(part1(password))
    while not is_valid(password):
        password = next_password(password)
    return password

if __name__ == '__main__':
    inp = 'cqjxjnds'
    print(part1(inp))
    print(part2(inp))