2015-12-11 - Corporate Policy
(original .ipynb)
Puzzle input is a password. Part one involves finding the next password (i.e. "increment" the letter from the right col) until you get a "valid" password according to the three rules defined in the comments. Part two involves finding the next one after that.
puzzle_input_str = open("./puzzle_input/day11.txt").read()
# Passwords must include one increasing straight of at least three letters, like abc, bcd, cde, and so on, up to xyz. They cannot skip letters; abd doesn't count.
def has_increasing_straight(pwd):
for i in range(len(pwd)-2):
if pwd[i]+1 == pwd[i+1] and pwd[i]+2 == pwd[i+2]:
return True
return False
# Passwords may not contain the letters i, o, or l, as these letters can be mistaken for other characters and are therefore confusing.
def letter(c):
n = ord(c)
assert n >= ord("a") and n <= ord("z")
return n - ord("a")
letter_a = letter("a")
letter_i = letter("i")
letter_o = letter("o")
letter_l = letter("l")
letter_z = letter("z")
def no_confusing_letters(pwd_digits):
letters = [d for d in pwd_digits if d == letter_i or d == letter_o or d == letter_l]
return 0 == len(letters)
# Passwords must contain at least two different, non-overlapping pairs of letters, like aa, bb, or zz.
def two_letter_pairs(pwd):
i = 0
pairs = 0
while i < len(pwd) - 1:
if pwd[i] == pwd[i+1]:
pairs += 1
i += 1
i += 1
return pairs >= 2
def valid_password(pwd_digits):
return has_increasing_straight(pwd_digits) and no_confusing_letters(pwd_digits) and two_letter_pairs(pwd_digits)
def to_digits(pwd):
return [letter(c) for c in pwd]
def to_letters(pwd_digits):
return [chr(ord("a") + c) for c in pwd_digits]
assert not valid_password(to_digits("hijklmmn"))
assert not valid_password(to_digits("abbceffg"))
assert not valid_password(to_digits("abbcegjk"))
assert not valid_password(to_digits("abcdefgh"))
assert valid_password(to_digits("abcdffaa"))
assert not valid_password(to_digits("ghijklmn"))
assert valid_password(to_digits("ghjaabcc"))
def next_password(pwd_digits):
carry = 1
reversed_next_password = []
for digit in reversed(pwd_digits):
if carry > 0:
digit += carry
if digit > letter_z:
digit = letter_a
carry = 1
else:
carry = 0
reversed_next_password.append(digit)
return list(reversed(reversed_next_password))
def part_one(input_str):
password = to_digits(input_str)
while not valid_password(password):
password = next_password(password)
return "".join(to_letters(password))
assert "abcdffaa" == part_one("abcdefgh")
assert "ghjaabcc" == part_one("ghijklmn")
print("part one:", part_one(puzzle_input_str))
part one: hepxxyzz
def part_two(input_str):
part_one_password = part_one(input_str)
next_maybe_password = "".join(to_letters(next_password(to_digits(part_one_password))))
return part_one(next_maybe_password)
print("part two:", part_two(puzzle_input_str))
part two: heqaabcc