Day21
This commit is contained in:
125
2024/gareth/day21/day21.go
Normal file
125
2024/gareth/day21/day21.go
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
25
2024/gareth/day21/day21_test.go
Normal file
25
2024/gareth/day21/day21_test.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package day21
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
r := Part1(`029A
|
||||||
|
980A
|
||||||
|
179A
|
||||||
|
456A
|
||||||
|
379A`)
|
||||||
|
assert.Equal(t, 126384, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart2(t *testing.T) {
|
||||||
|
r := Part2(`029A
|
||||||
|
980A
|
||||||
|
179A
|
||||||
|
456A
|
||||||
|
379A`)
|
||||||
|
assert.Equal(t, 126384, r)
|
||||||
|
}
|
||||||
5
2024/gareth/day21/input.txt
Normal file
5
2024/gareth/day21/input.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
985A
|
||||||
|
540A
|
||||||
|
463A
|
||||||
|
671A
|
||||||
|
382A
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"aoc2024/day20"
|
"aoc2024/day21"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
data, _ := os.ReadFile("day20/input.txt")
|
data, _ := os.ReadFile("day21/input.txt")
|
||||||
fmt.Printf("part 1: %d\n", day20.Part1(string(data)))
|
fmt.Printf("part 1: %d\n", day21.Part1(string(data)))
|
||||||
fmt.Printf("part 2: %d\n", day20.Part2(string(data)))
|
fmt.Printf("part 2: %d\n", day21.Part2(string(data)))
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
fmt.Printf("Execution time: %s\n", elapsed)
|
fmt.Printf("Execution time: %s\n", elapsed)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user