diff --git a/2024/day11/day11.go b/2024/day11/day11.go index 1e10f1f..1f8e71f 100644 --- a/2024/day11/day11.go +++ b/2024/day11/day11.go @@ -8,47 +8,78 @@ import ( "strings" ) -func update(stones map[int]int) map[int]int { - processed := make(map[int]int) - for stone, count := range stones { - if stone == 0 { - processed[1] += count - continue - } - - places := int(math.Log10(float64(stone))) + 1 - if places%2 == 0 { - half := places / 2 - divisor := int(math.Pow10(half)) - - left := stone / divisor - right := stone % divisor - - processed[left] += count - processed[right] += count - continue - } - - processed[stone*2024] += count - } - - return processed +type Key struct { + times, stone int } -func Part1(stones map[int]int, steps int) int { - for i := 0; i < steps; i++ { - stones = update(stones) +var splitCache = make(map[int][]int) +var splitCacheHits, splitCacheMisses int + +var cache = make(map[Key]int) +var cacheHits, cacheMisses int + +func split(stone int) (int, int) { + if val, ok := splitCache[stone]; ok { + splitCacheHits++ + return val[0], val[1] } - sum := 0 - for _, count := range stones { - sum += count - } + splitCacheMisses++ - return sum + half := (int(math.Log10(float64(stone))) + 1) / 2 + divisor := int(math.Pow10(half)) + + left := stone / divisor + right := stone % divisor + + splitCache[stone] = []int{left, right} + + return left, right } -func Part2(stones map[int]int, steps int) int { +func cacheKey(key Key, value int) int { + cache[key] = value + return value +} + +func update(stone int, depth int) int { + key := Key{depth, stone} + + if count, exists := cache[key]; exists { + cacheMisses++ + return count + } + + cacheHits++ + + if depth == 0 { + return cacheKey(key, 1) + } + + if stone == 0 { + return cacheKey(key, update(1, depth-1)) + } + + places := int(math.Log10(float64(stone))) + 1 + if places%2 == 0 { + split1, split2 := split(stone) + result := update(split1, depth-1) + update(split2, depth-1) + return cacheKey(key, result) + } + + return cacheKey(key, update(stone*2024, depth-1)) +} + +func Part1(stones []int, steps int) int { + result := 0 + for _, stone := range stones { + result += update(stone, steps) + } + + return result +} + +func Part2(stones []int, steps int) int { return Part1(stones, steps) } @@ -59,7 +90,7 @@ func Run(filename string) (int, int) { } defer file.Close() - stones := make(map[int]int) + stones := []int{} scanner := bufio.NewScanner(file) for scanner.Scan() { @@ -71,7 +102,7 @@ func Run(filename string) (int, int) { panic(err) } - stones[id] += 1 + stones = append(stones, id) } }