adventofcode/2016/day17/main.go

109 lines
2.3 KiB
Go

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 printUsageAndExit() {
fmt.Println("Usage: ./day17 <passcode> <gridWidth> <gridHeight>")
os.Exit(0)
}