Solve 2015:11 "Corporate Policy"
I brainfarted and had a hard time trying to understand the instructions. > Incrementing is just like counting with numbers: xx, xy, xz, ya, yb, and so on. Increase the rightmost letter one step; if it was z, it wraps around to a, and repeat with the next letter to the left until one doesn't wrap around. I only managed to understand it by looking at solutions on the subreddit, figuring out the correct behavior: az -> ba, azzz -> baaa, azzzzz -> baaaaa etc. I also sped up the test case containing `ghi` as initial password, by looking for the leftmost invalid I, L or O and increase it, replacing all following chars with `a`. ghijklmn -> ghjaaaaa.
This commit is contained in:
parent
4742910afd
commit
838d06100b
2 changed files with 103 additions and 0 deletions
68
2015-python/solutions/day_11.py
Normal file
68
2015-python/solutions/day_11.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import re
|
||||
from solutions import BaseSolution
|
||||
|
||||
|
||||
class Solution(BaseSolution):
|
||||
input_file = "11.txt"
|
||||
|
||||
def __str__(self):
|
||||
return "Day 11: Corporate Policy"
|
||||
|
||||
def is_valid(self, suggestion):
|
||||
if "i" in suggestion or "l" in suggestion or "o" in suggestion:
|
||||
return False
|
||||
if (
|
||||
len(
|
||||
set(
|
||||
map(
|
||||
lambda x: x[0],
|
||||
filter(lambda x: x[0] == x[1], zip(suggestion, suggestion[1:])),
|
||||
)
|
||||
)
|
||||
)
|
||||
< 2
|
||||
):
|
||||
return False
|
||||
|
||||
def seq(abc):
|
||||
a, b, c = abc
|
||||
return ord(b) - ord(a) == 1 and ord(c) - ord(b) == 1
|
||||
|
||||
return any(map(seq, zip(suggestion, suggestion[1:], suggestion[2:])))
|
||||
|
||||
def parse_input(self, data):
|
||||
return data
|
||||
|
||||
def solve(self, password):
|
||||
def tick(p):
|
||||
chars = list(p)[::-1]
|
||||
i = 0
|
||||
for c in chars:
|
||||
if c == "z":
|
||||
chars[i] = "a"
|
||||
else:
|
||||
chars[i] = chr(ord(chars[i]) + 1)
|
||||
break
|
||||
i += 1
|
||||
return "".join(chars[::-1])
|
||||
|
||||
unallowed = re.compile(r"i|l|o")
|
||||
fastforward = re.search(unallowed, password)
|
||||
if fastforward:
|
||||
password = (
|
||||
password[: fastforward.start()]
|
||||
+ chr(ord(password[fastforward.start()]) + 1)
|
||||
).ljust(len(password), "a")
|
||||
|
||||
while True:
|
||||
password = tick(password)
|
||||
if self.is_valid(password):
|
||||
return password
|
||||
|
||||
def solve_again(self, puzzle_input):
|
||||
return self.solve(self.solve(puzzle_input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
solution = Solution()
|
||||
solution.show_results()
|
||||
35
2015-python/tests/test_day_11.py
Normal file
35
2015-python/tests/test_day_11.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import unittest
|
||||
|
||||
from solutions.day_11 import Solution
|
||||
|
||||
|
||||
class Day11TestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.solution = Solution()
|
||||
self.puzzle_input = self.solution.parse_input(
|
||||
"""
|
||||
<REPLACE ME>
|
||||
"""
|
||||
)
|
||||
|
||||
def test_parse_puzzle_input(self):
|
||||
data = """
|
||||
<REPLACE ME>
|
||||
""".strip()
|
||||
assert self.solution.parse_input(data) == "<REPLACE ME>"
|
||||
|
||||
def test_validate_passwords(self):
|
||||
assert not self.solution.is_valid("hijklmmn")
|
||||
assert not self.solution.is_valid("abbceffg")
|
||||
assert not self.solution.is_valid("abbcegjk")
|
||||
|
||||
def test_solve_first_part(self):
|
||||
assert self.solution.solve("abcdefgh") == "abcdffaa"
|
||||
assert self.solution.solve("ghijklmn") == "ghjaabcc"
|
||||
|
||||
# def test_solve_second_part(self):
|
||||
# assert self.solution.solve_again(self.puzzle_input) == True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Reference in a new issue