109 lines
2.3 KiB
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)
|
|
}
|