Day 17 Complete

This commit is contained in:
Brian Buller 2016-12-17 10:00:39 -06:00
parent a6e0380b18
commit 5ccafb37c4
4 changed files with 215 additions and 7 deletions

1
2016/day17/input Normal file
View File

@ -0,0 +1 @@
pvhmgsws

111
2016/day17/main.go Normal file
View File

@ -0,0 +1,111 @@
package main
import (
"crypto/md5"
"fmt"
"os"
"../../"
)
var gridWidth, gridHeight int
func main() {
var passcode string
gridWidth, gridHeight = 4, 4
if len(os.Args) < 2 {
printUsageAndExit()
}
passcode = os.Args[1]
if len(os.Args) >= 4 {
gridWidth = aoc.Atoi(os.Args[2])
gridHeight = aoc.Atoi(os.Args[3])
}
foundPaths := findPaths("", passcode)
if len(foundPaths) == 0 {
fmt.Println("Couldn't find a valid path!")
os.Exit(1)
}
shortestPath := foundPaths[0]
longestPath := foundPaths[0]
for i := range foundPaths {
if len(foundPaths[i]) < len(shortestPath) {
shortestPath = foundPaths[i]
}
if len(foundPaths[i]) > len(longestPath) {
longestPath = foundPaths[i]
}
}
fmt.Println("Shortest Path:", shortestPath)
fmt.Println("Longest Path Length:", len(longestPath))
}
func findPaths(path, passcode string) []string {
var ret []string
cX, cY := currPos(path)
if cY == gridHeight-1 && cX == gridWidth-1 {
return []string{path}
}
if cY > 0 && doorIsOpen(path, passcode, 'U') {
ret = append(ret, findPaths(path+"U", passcode)...)
}
if cY < (gridHeight-1) && doorIsOpen(path, passcode, 'D') {
ret = append(ret, findPaths(path+"D", passcode)...)
}
if cX > 0 && doorIsOpen(path, passcode, 'L') {
ret = append(ret, findPaths(path+"L", passcode)...)
}
if cX < (gridWidth-1) && doorIsOpen(path, passcode, 'R') {
ret = append(ret, findPaths(path+"R", passcode)...)
}
return ret
}
// We cache the last hash calculated
// It should speed things up a little
var lastHashInput string
var lastHash string
func doorIsOpen(path, passcode string, dir rune) bool {
if lastHashInput != passcode+path {
lastHashInput = passcode + path
lastHash = fmt.Sprintf("%x", md5.Sum([]byte(lastHashInput)))
}
switch dir {
case 'U':
return lastHash[0] >= 'b' && lastHash[0] <= 'f'
case 'D':
return lastHash[1] >= 'b' && lastHash[1] <= 'f'
case 'L':
return lastHash[2] >= 'b' && lastHash[2] <= 'f'
case 'R':
return lastHash[3] >= 'b' && lastHash[3] <= 'f'
}
return false
}
func currPos(path string) (int, int) {
var cX, cY int
for i := range path {
switch path[i] {
case 'U':
cY--
case 'D':
cY++
case 'L':
cX--
case 'R':
cX++
}
}
return cX, cY
}
func PrintState(path, passcode string) {
}
func printUsageAndExit() {
fmt.Println("Usage: ./day17 <passcode> <gridWidth> <gridHeight>")
os.Exit(0)
}

94
2016/day17/problem Normal file
View File

@ -0,0 +1,94 @@
Advent of Code
--- 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?
Your puzzle answer was __________________.
--- 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?
Your puzzle answer was _______.
References
Visible links
. http://adventofcode.com/
. http://adventofcode.com/2016/about
. http://adventofcode.com/2016/support
. http://adventofcode.com/2016/events
. http://adventofcode.com/2016/settings
. http://adventofcode.com/2016/auth/logout
. http://adventofcode.com/2016
. http://adventofcode.com/2016
. http://adventofcode.com/2016/leaderboard
. http://adventofcode.com/2016/stats
. http://adventofcode.com/2016/sponsors
. http://adventofcode.com/2016/sponsors
. https://en.wikipedia.org/wiki/MD5
. http://adventofcode.com/2016

View File

@ -3,12 +3,13 @@ package aoc
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"os" "os"
"strconv" "strconv"
) )
func stdinToStringSlice() []string { func StdinToStringSlice() []string {
var input []string var input []string
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() { for scanner.Scan() {
@ -17,7 +18,7 @@ func stdinToStringSlice() []string {
return input return input
} }
func atoi(i string) int { func Atoi(i string) int {
var ret int var ret int
var err error var err error
if ret, err = strconv.Atoi(i); err != nil { if ret, err = strconv.Atoi(i); err != nil {
@ -26,11 +27,11 @@ func atoi(i string) int {
return ret return ret
} }
func itoa(i int) string { func Itoa(i int) string {
return strconv.Itoa(i) return strconv.Itoa(i)
} }
func stdinToString() string { func StdinToString() string {
var input string var input string
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() { for scanner.Scan() {
@ -39,11 +40,12 @@ func stdinToString() string {
return input return input
} }
func fileToString(fn string) string { func FileToString(fn string) string {
var c []byte var c []byte
c, err = ioutil.Readfile(filename) var err error
c, err = ioutil.ReadFile(fn)
if err != nil { if err != nil {
fmt.Println("Unable to read file: " + filename) fmt.Println("Unable to read file: " + fn)
os.Exit(1) os.Exit(1)
} }
return string(c) return string(c)