Solve 2021:12 "Passage Pathing"
I struggled a lot with the direction, but realised way too much later that the mappings are bidirectional. Part 2 was exceptionally hard, but I realised early that the order did not matter and that a simple boolean lock was all that was needed. The challenge was to know when to watch for duplicates. The seen was initially a set, but since new sets must be sent instead of references, a list is used instead to be able to use the seen + [] hack.
This commit is contained in:
parent
b53c50addc
commit
c0d352cdf1
2 changed files with 129 additions and 0 deletions
54
2021-python/solutions/day_12.py
Normal file
54
2021-python/solutions/day_12.py
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
from collections import defaultdict, deque, Counter
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = "12.txt"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Day 12: Passage Pathing"
|
||||||
|
|
||||||
|
def parse_input(self, data):
|
||||||
|
return [l.split("-") for l in data.split()]
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
return self._solve(puzzle_input, lambda seen: True)
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
return self._solve(
|
||||||
|
puzzle_input,
|
||||||
|
lambda seen: any(
|
||||||
|
[
|
||||||
|
k.islower() and k != "start" and v > 1
|
||||||
|
for k, v in Counter(seen).items()
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def _solve(self, puzzle_input, isdup):
|
||||||
|
ft = defaultdict(lambda: [])
|
||||||
|
for f, t in puzzle_input:
|
||||||
|
ft[f].append(t)
|
||||||
|
for f, t in puzzle_input:
|
||||||
|
ft[t].append(f)
|
||||||
|
queue = deque([("start", list(), False)])
|
||||||
|
s2e = 0
|
||||||
|
while queue:
|
||||||
|
pos, seen, dup = queue.pop()
|
||||||
|
seen.append(pos)
|
||||||
|
dup = isdup(seen)
|
||||||
|
for t in ft[pos]:
|
||||||
|
if t == "end":
|
||||||
|
s2e += 1
|
||||||
|
continue
|
||||||
|
elif t == "start":
|
||||||
|
continue
|
||||||
|
elif dup and t.islower() and t in seen:
|
||||||
|
continue
|
||||||
|
queue.append((t, seen + [], dup))
|
||||||
|
return s2e
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
75
2021-python/tests/test_day_12.py
Normal file
75
2021-python/tests/test_day_12.py
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_12 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day12TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
self.puzzle_input = self.solution.parse_input(
|
||||||
|
"""
|
||||||
|
start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_parse_puzzle_input(self):
|
||||||
|
data = """
|
||||||
|
a-b
|
||||||
|
q1w2-e3r4
|
||||||
|
"""
|
||||||
|
assert self.solution.parse_input(data) == [["a", "b"], ["q1w2", "e3r4"]]
|
||||||
|
|
||||||
|
def test_solve_first_part(self):
|
||||||
|
assert self.solution.solve(self.puzzle_input) == 10
|
||||||
|
|
||||||
|
def test_solve_second_part(self):
|
||||||
|
assert self.solution.solve_again(self.puzzle_input) == 36
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
"""
|
||||||
|
start,A,b,A,b,A,c,A,end
|
||||||
|
start,A,b,A,b,A,end
|
||||||
|
start,A,b,A,b,end
|
||||||
|
start,A,b,A,c,A,b,A,end
|
||||||
|
start,A,b,A,c,A,b,end
|
||||||
|
start,A,b,A,c,A,c,A,end
|
||||||
|
start,A,b,A,c,A,end
|
||||||
|
start,A,b,A,end
|
||||||
|
start,A,b,d,b,A,c,A,end
|
||||||
|
start,A,b,d,b,A,end
|
||||||
|
start,A,b,d,b,end
|
||||||
|
start,A,b,end
|
||||||
|
start,A,c,A,b,A,b,A,end
|
||||||
|
start,A,c,A,b,A,b,end
|
||||||
|
start,A,c,A,b,A,c,A,end
|
||||||
|
start,A,c,A,b,A,end
|
||||||
|
start,A,c,A,b,d,b,A,end
|
||||||
|
start,A,c,A,b,d,b,end
|
||||||
|
start,A,c,A,b,end
|
||||||
|
start,A,c,A,c,A,b,A,end
|
||||||
|
start,A,c,A,c,A,b,end
|
||||||
|
start,A,c,A,c,A,end
|
||||||
|
start,A,c,A,end
|
||||||
|
start,A,end
|
||||||
|
start,b,A,b,A,c,A,end
|
||||||
|
start,b,A,b,A,end
|
||||||
|
start,b,A,b,end
|
||||||
|
start,b,A,c,A,b,A,end
|
||||||
|
start,b,A,c,A,b,end
|
||||||
|
start,b,A,c,A,c,A,end
|
||||||
|
start,b,A,c,A,end
|
||||||
|
start,b,A,end
|
||||||
|
start,b,d,b,A,c,A,end
|
||||||
|
start,b,d,b,A,end
|
||||||
|
start,b,d,b,end
|
||||||
|
start,b,end
|
||||||
|
"""
|
||||||
Loading…
Add table
Reference in a new issue