package main import ( "crypto/md5" "fmt" "log" "os" "strconv" "strings" ) var hashStore []string var salt string func main() { if len(os.Args) < 3 { fmt.Println("Usage: ./day14 ") fmt.Println(" My input: ./day14 cuanljph 64") os.Exit(1) } salt = os.Args[1] keyNum := atoi(os.Args[2]) var foundKeys []string tryIdx := 0 for len(foundKeys) < keyNum { tst := getHash(tryIdx) for i := range tst { if len(tst) > i+3 { if tst[i:i+3] == strings.Repeat(string(tst[i]), 3) { // Found a triple, search the next 1000 for a quintuple if searchForQuint(salt, tryIdx+1, string(tst[i])) { foundKeys = append(foundKeys, tst) } // Once we test the first triplet, we're done with this one break } } } tryIdx++ } fmt.Println("Key:", getHash(tryIdx-1), "Idx:", tryIdx) } func getHash(idx int) string { for len(hashStore)-1 < idx { hashStore = append( hashStore, getStretchedHash(fmt.Sprintf("%x", md5.Sum([]byte(salt+itoa(len(hashStore)+1))))), ) } return hashStore[idx] } func getStretchedHash(s string) string { for i := 0; i < 2016; i++ { s = fmt.Sprintf("%x", md5.Sum([]byte(s))) } return s } func searchForQuint(salt string, startIdx int, srch string) bool { for i := startIdx; i <= startIdx+1000; i++ { tst := getHash(i) if strings.Contains(tst, strings.Repeat(srch, 5)) { return true } } return false } func atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi") } return ret } func itoa(i int) string { return strconv.Itoa(i) }