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 ") os.Exit(0) }