Solution to problem 17 in Python
This commit is contained in:
parent
0ae4fb1375
commit
ba2e0fd5fb
129
src/Year_2016/P17.py
Normal file
129
src/Year_2016/P17.py
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# --- Day 17: Two Steps Forward ---
|
||||||
|
|
||||||
|
# You're trying to access a secure vault protected by a 4x4 grid of small rooms
|
||||||
|
# connected by doors. You start in the top-left room (marked S), and you can
|
||||||
|
# access the vault (marked V) once you reach the bottom-right room:
|
||||||
|
|
||||||
|
# #########
|
||||||
|
# #S| | | #
|
||||||
|
# #-#-#-#-#
|
||||||
|
# # | | | #
|
||||||
|
# #-#-#-#-#
|
||||||
|
# # | | | #
|
||||||
|
# #-#-#-#-#
|
||||||
|
# # | | |
|
||||||
|
# ####### V
|
||||||
|
|
||||||
|
# Fixed walls are marked with #, and doors are marked with - or |.
|
||||||
|
|
||||||
|
# The doors in your current room are either open or closed (and locked) based on
|
||||||
|
# the hexadecimal MD5 hash of a passcode (your puzzle input) followed by a
|
||||||
|
# sequence of uppercase characters representing the path you have taken so far
|
||||||
|
# (U for up, D for down, L for left, and R for right).
|
||||||
|
|
||||||
|
# Only the first four characters of the hash are used; they represent,
|
||||||
|
# respectively, the doors up, down, left, and right from your current position.
|
||||||
|
# Any b, c, d, e, or f means that the corresponding door is open; any other
|
||||||
|
# character (any number or a) means that the corresponding door is closed and
|
||||||
|
# locked.
|
||||||
|
|
||||||
|
# To access the vault, all you need to do is reach the bottom-right room;
|
||||||
|
# reaching this room opens the vault and all doors in the maze.
|
||||||
|
|
||||||
|
# For example, suppose the passcode is hijkl. Initially, you have taken no
|
||||||
|
# steps, and so your path is empty: you simply find the MD5 hash of hijkl alone.
|
||||||
|
# The first four characters of this hash are ced9, which indicate that up is
|
||||||
|
# open (c), down is open (e), left is open (d), and right is closed and locked
|
||||||
|
# (9). Because you start in the top-left corner, there are no "up" or "left"
|
||||||
|
# doors to be open, so your only choice is down.
|
||||||
|
|
||||||
|
# Next, having gone only one step (down, or D), you find the hash of hijklD.
|
||||||
|
# This produces f2bc, which indicates that you can go back up, left (but that's
|
||||||
|
# a wall), or right. Going right means hashing hijklDR to get 5745 - all doors
|
||||||
|
# closed and locked. However, going up instead is worthwhile: even though it
|
||||||
|
# returns you to the room you started in, your path would then be DU, opening a
|
||||||
|
# different set of doors.
|
||||||
|
|
||||||
|
# After going DU (and then hashing hijklDU to get 528e), only the right door is
|
||||||
|
# open; after going DUR, all doors lock. (Fortunately, your actual passcode is
|
||||||
|
# not hijkl).
|
||||||
|
|
||||||
|
# Passcodes actually used by Easter Bunny Vault Security do allow access to the
|
||||||
|
# vault if you know the right path. For example:
|
||||||
|
|
||||||
|
# If your passcode were ihgpwlah, the shortest path would be DDRRRD.
|
||||||
|
# With kglvqrro, the shortest path would be DDUDRLRRUDRD.
|
||||||
|
# With ulqzkmiv, the shortest would be DRURDRUDDLLDLUURRDULRLDUUDDDRR.
|
||||||
|
|
||||||
|
# Given your vault's passcode, what is the shortest path (the actual path, not
|
||||||
|
# just the length) to reach the vault?
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
passcode = "pvhmgsws"
|
||||||
|
directions = {(0, -1): "U", (0, 1): "D", (-1, 0): "L", (1, 0): "R"}
|
||||||
|
|
||||||
|
|
||||||
|
def part_1():
|
||||||
|
visiting = [(passcode, (0, 0), "")]
|
||||||
|
|
||||||
|
while visiting:
|
||||||
|
hash, (x, y), current = visiting.pop(0)
|
||||||
|
md5 = hashlib.md5(hash.encode()).hexdigest()[:4]
|
||||||
|
for char, (dx, dy) in zip(md5, directions):
|
||||||
|
if char not in "bcdef":
|
||||||
|
# door is look
|
||||||
|
continue
|
||||||
|
new_pos = x + dx, y + dy
|
||||||
|
if not -1 < new_pos[0] < 4 or not -1 < new_pos[1] < 4:
|
||||||
|
# out of the grid
|
||||||
|
continue
|
||||||
|
d = directions[(dx, dy)]
|
||||||
|
if new_pos == (3, 3):
|
||||||
|
print(f"The shortest path is {current+d}")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
visiting.append((hash + d, new_pos, current + d))
|
||||||
|
|
||||||
|
|
||||||
|
# --- Part Two ---
|
||||||
|
|
||||||
|
# You're curious how robust this security solution really is, and so you decide
|
||||||
|
# to find longer and longer paths which still provide access to the vault. You
|
||||||
|
# remember that paths always end the first time they reach the bottom-right room
|
||||||
|
# (that is, they can never pass through it, only end in it).
|
||||||
|
|
||||||
|
# For example:
|
||||||
|
|
||||||
|
# If your passcode were ihgpwlah, the longest path would take 370 steps.
|
||||||
|
# With kglvqrro, the longest path would be 492 steps long.
|
||||||
|
# With ulqzkmiv, the longest path would be 830 steps long.
|
||||||
|
|
||||||
|
# What is the length of the longest path that reaches the vault?
|
||||||
|
|
||||||
|
|
||||||
|
def part_2():
|
||||||
|
visiting = [(passcode, (0, 0), "")]
|
||||||
|
|
||||||
|
paths = []
|
||||||
|
while visiting:
|
||||||
|
hash, (x, y), current = visiting.pop(0)
|
||||||
|
md5 = hashlib.md5(hash.encode()).hexdigest()[:4]
|
||||||
|
for c, (dx, dy) in zip(md5, directions):
|
||||||
|
if c not in "bcdef":
|
||||||
|
continue
|
||||||
|
new_pos = x + dx, y + dy
|
||||||
|
if not -1 < new_pos[0] < 4 or not -1 < new_pos[1] < 4:
|
||||||
|
# out of the grid
|
||||||
|
continue
|
||||||
|
d = directions[(dx, dy)]
|
||||||
|
if new_pos == (3, 3):
|
||||||
|
paths.append(current + d)
|
||||||
|
else:
|
||||||
|
visiting.append((hash + d, new_pos, current + d))
|
||||||
|
print(f"The longest path is {len(paths[-1])} units long")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
part_1()
|
||||||
|
part_2()
|
Loading…
x
Reference in New Issue
Block a user