package main import ( "fmt" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { inp := h.StdinToStringSlice() dirPad := make(map[string]h.Coordinate) dirPad["A"] = h.Coordinate{X: 2, Y: 1} dirPad["^"] = h.Coordinate{X: 1, Y: 1} dirPad[">"] = h.Coordinate{X: 2, Y: 0} dirPad["v"] = h.Coordinate{X: 1, Y: 0} dirPad["<"] = h.Coordinate{X: 0, Y: 0} numPad := make(map[string]h.Coordinate) numPad["A"] = h.Coordinate{X: 2, Y: 0} numPad["0"] = h.Coordinate{X: 1, Y: 0} numPad["1"] = h.Coordinate{X: 0, Y: 1} numPad["2"] = h.Coordinate{X: 1, Y: 1} numPad["3"] = h.Coordinate{X: 2, Y: 1} numPad["4"] = h.Coordinate{X: 0, Y: 2} numPad["5"] = h.Coordinate{X: 1, Y: 2} numPad["6"] = h.Coordinate{X: 2, Y: 2} numPad["7"] = h.Coordinate{X: 0, Y: 3} numPad["8"] = h.Coordinate{X: 1, Y: 3} numPad["9"] = h.Coordinate{X: 2, Y: 3} fmt.Println("# Part 1") fmt.Println(findOrders(inp, dirPad, numPad, 2)) fmt.Println("") fmt.Println("# Part 2") fmt.Println(findOrders(inp, dirPad, numPad, 25)) } func parseNum(line string) int { var numLine string for i := range line { if line[i] >= '0' && line[i] <= '9' { numLine = numLine + string(line[i]) } } var num int fmt.Sscanf(numLine, "%d", &num) return num } // findOrders takes: // // inp: The codes that need to be input // dirPad: The direction pad description // numPad: The number pad description // bots: How many robots are operating directional pads between you and the numpad robot. func findOrders(inp []string, dirPad, numPad map[string]h.Coordinate, bots int) int { var count int cache := make(map[string][]int) for _, line := range inp { code := strings.Split(line, "") s := workPad(code, "A", numPad) wrk := workBots(s, bots, 1, cache, dirPad) count += parseNum(line) * wrk } return count } func workPad(code []string, start string, pad map[string]h.Coordinate) []string { curr := pad[start] out := []string{} for _, c := range code { btn := pad[c] dist := btn.Sub(curr) var outV, outH []string for i := 0; i < h.Abs(dist.X); i++ { if dist.X >= 0 { outH = append(outH, ">") } else { outH = append(outH, "<") } } for i := 0; i < h.Abs(dist.Y); i++ { if dist.Y >= 0 { outV = append(outV, "^") } else { outV = append(outV, "v") } } _, isNumPad := pad["0"] if isNumPad { if curr.Y == 0 && btn.X == 0 { out = append(out, outV...) out = append(out, outH...) } else if (curr.X == 0 && btn.Y == 0) || dist.X < 0 { out = append(out, outH...) out = append(out, outV...) } else if dist.X >= 0 { out = append(out, outV...) out = append(out, outH...) } } else { if curr.X == 0 && btn.Y == 1 { out = append(out, outH...) out = append(out, outV...) } else if curr.Y == 1 && btn.X == 0 { out = append(out, outV...) out = append(out, outH...) } else if dist.X < 0 { out = append(out, outH...) out = append(out, outV...) } else if dist.X >= 0 { out = append(out, outV...) out = append(out, outH...) } } curr = btn out = append(out, "A") } return out } func workBots(inst []string, bots int, bot int, cache map[string][]int, dirPad map[string]h.Coordinate) int { cacheKey := strings.Join(inst, "") if v, ok := cache[cacheKey]; ok { if v[bot-1] != 0 { return v[bot-1] } } else { cache[cacheKey] = make([]int, bots) } s := workPad(inst, "A", dirPad) cache[cacheKey][0] = len(s) if bot == bots { return len(s) } sSteps := splitSteps(s) var count int for _, s := range sSteps { c := workBots(s, bots, bot+1, cache, dirPad) subCacheKey := strings.Join(s, "") if _, ok := cache[subCacheKey]; !ok { cache[subCacheKey] = make([]int, bots) } cache[subCacheKey][0] = c count += c } cache[cacheKey][bot-1] = count return count } func splitSteps(s []string) [][]string { var out [][]string var c []string for _, char := range s { c = append(c, char) if char == "A" { out = append(out, c) c = []string{} } } return out }