package day21 import ( "strconv" "strings" ) type coordinate struct { row, col int } var numberPad = map[string]coordinate{ "7": {0, 0}, "8": {0, 1}, "9": {0, 2}, "4": {1, 0}, "5": {1, 1}, "6": {1, 2}, "1": {2, 0}, "2": {2, 1}, "3": {2, 2}, "0": {3, 1}, "A": {3, 2}, } var robotPad = map[string]coordinate{ "^": {0, 1}, "A": {0, 2}, "<": {1, 0}, "v": {1, 1}, ">": {1, 2}, } type cacheKey struct { sequence string iterations int } var memo = make(map[cacheKey]int) func Part1(input string) int { codes := parseInput(input) numpadGraph := createGraph(numberPad, coordinate{3, 0}) dirpadGraph := createGraph(robotPad, coordinate{0, 0}) total := 0 for _, code := range codes { codeInt, _ := strconv.Atoi(code[:len(code)-1]) total += codeInt * getLength(code, 3, true, numpadGraph, dirpadGraph) } return total } func Part2(input string) int { codes := parseInput(input) numpadGraph := createGraph(numberPad, coordinate{3, 0}) dirpadGraph := createGraph(robotPad, coordinate{0, 0}) total := 0 for _, code := range codes { codeInt, _ := strconv.Atoi(code[:len(code)-1]) total += codeInt * getLength(code, 26, true, numpadGraph, dirpadGraph) } return total } func parseInput(input string) []string { parts := strings.Split(input, "\n") codes := []string{} codes = append(codes, parts...) return codes } func createGraph(keypad map[string]coordinate, invalidCoords coordinate) map[string]string { graph := make(map[string]string) for a, coordA := range keypad { for b, coordB := range keypad { x1, y1 := coordA.row, coordA.col x2, y2 := coordB.row, coordB.col path := strings.Repeat("<", max(0, y1-y2)) + strings.Repeat("v", max(0, x2-x1)) + strings.Repeat("^", max(0, x1-x2)) + strings.Repeat(">", max(0, y2-y1)) if invalidCoords == (coordinate{x1, y2}) || invalidCoords == (coordinate{x2, y1}) { path = reverseString(path) } graph[a+"->"+b] = path + "A" } } return graph } func reverseString(s string) string { runes := []rune(s) for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { runes[i], runes[j] = runes[j], runes[i] } return string(runes) } func getLength(sequence string, iterations int, firstIter bool, numpadGraph map[string]string, dirpadGraph map[string]string) int { if iterations == 0 { return len(sequence) } key := cacheKey{sequence: sequence, iterations: iterations} if cachedResult, exists := memo[key]; exists { return cachedResult } graph := numpadGraph if !firstIter { graph = dirpadGraph } totalLength := 0 prev := "A" for _, char := range sequence { graphKey := prev + "->" + string(char) if subSequence, exists := graph[graphKey]; exists { totalLength += getLength(subSequence, iterations-1, false, numpadGraph, dirpadGraph) } prev = string(char) } memo[key] = totalLength return totalLength }