11package me.peckb.aoc._2024.calendar.day21
22
3- import javax.inject.Inject
3+ import arrow.core.memoize
44import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory
55import java.util.LinkedList
6+ import javax.inject.Inject
67import kotlin.math.sign
78
89class Day21 @Inject constructor(
@@ -18,76 +19,72 @@ class Day21 @Inject constructor(
1819
1920 private fun solve (input : Sequence <String >, indirections : Int ) : Long {
2021 return input.sumOf { code ->
21- val length = getLength (NUMERIC_PAD , code, indirections)
22+ val length = memoizedGetLength (NUMERIC_PAD , code, indirections)
2223 val size = code.take(3 ).toLong()
2324
2425 length * size
2526 }
2627 }
2728
28- private fun getLength (keyPad : Map <Char , Pair <Int , Int >>, code : String , indirections : Int ): Long {
29- val lengthKey = LengthKey (keyPad.size, code, indirections)
29+ private val memoizedGetLength = ::getLength.memoize()
3030
31- if (LENGTH_CACHE .containsKey(lengthKey)) {
32- return LENGTH_CACHE [lengthKey]!!
33- }
31+ private val memoizedPaths = ::paths.memoize()
3432
33+ private fun getLength (keyPad : Map <Char , Pair <Int , Int >>, code : String , indirections : Int ): Long {
3534 if (indirections == 0 ) {
36- return code.length.toLong(). also { LENGTH_CACHE [lengthKey] = it }
35+ return code.length.toLong()
3736 }
3837
3938 val minLength = " A${code} " .toList()
4039 .windowed(2 )
4140 .sumOf { (s, e) ->
42- paths (keyPad, s, e).minOf { getLength (DIRECTION_PAD , " ${it} A" , indirections - 1 ) }
41+ memoizedPaths (keyPad, s, e).minOf { memoizedGetLength (DIRECTION_PAD , " ${it} A" , indirections - 1 ) }
4342 }
4443
45- return minLength. also { LENGTH_CACHE [lengthKey] = it }
44+ return minLength
4645 }
4746
4847 private fun paths (keyPad : Map <Char , Pair <Int , Int >>, start : Char , end : Char ): List <String > {
49- val pathKey = PathKey (keyPad.size, start, end)
50-
51- if (PATHS_CACHE .containsKey(pathKey)) {
52- return PATHS_CACHE [pathKey]!!
53- }
54-
5548 val paths = mutableListOf<String >()
49+
5650 val partialPaths = LinkedList <Pair <Pair <Int , Int >, String >> ().apply {
5751 add(keyPad[start]!! to " " )
5852 }
5953
6054 pathGeneration@ while (partialPaths.isNotEmpty()) {
6155 val (position, path) = partialPaths.poll()
62-
6356 val target = keyPad[end]!!
57+
6458 if (position == target) {
6559 paths.add(path)
6660 continue @pathGeneration
6761 }
6862
69- val yDelta = target.second - position.second
70- if (yDelta != 0 ) {
71- val newPoint = position.first to position.second + yDelta.sign
63+ val (yDelta, xDelta) = target - position
64+
65+ if (xDelta != 0 ) {
66+ val newPoint = position.first to position.second + xDelta.sign
7267 if (newPoint in keyPad.values) {
73- val dir = if (yDelta > 0 ) { " >" } else { " <" }
68+ val dir = if (xDelta > 0 ) { " >" } else { " <" }
7469 partialPaths.add(newPoint to " $path$dir " )
7570 }
7671 }
7772
78- val xDelta = target.first - position.first
79- if (xDelta != 0 ) {
80- val newPoint = position.first + xDelta.sign to position.second
73+ if (yDelta != 0 ) {
74+ val newPoint = position.first + yDelta.sign to position.second
8175 if (newPoint in keyPad.values) {
82- val dir = if (xDelta > 0 ) { " v" } else { " ^" }
76+ val dir = if (yDelta > 0 ) { " v" } else { " ^" }
8377 partialPaths.add(newPoint to " $path$dir " )
8478 }
8579 }
8680 }
8781
88- return paths. also { PATHS_CACHE [pathKey] = it }
82+ return paths
8983 }
9084
85+ private operator fun Pair <Int , Int >.minus (other : Pair <Int , Int >) =
86+ this .first - other.first to this .second - other.second
87+
9188 companion object {
9289 val NUMERIC_PAD = mapOf (
9390 ' 7' to (0 to 0 ), ' 8' to (0 to 1 ), ' 9' to (0 to 2 ),
@@ -100,13 +97,5 @@ class Day21 @Inject constructor(
10097 ' ^' to (0 to 1 ), ' A' to (0 to 2 ),
10198 ' <' to (1 to 0 ), ' v' to (1 to 1 ), ' >' to (1 to 2 )
10299 )
103-
104- val LENGTH_CACHE = mutableMapOf<LengthKey , Long >()
105-
106- val PATHS_CACHE = mutableMapOf<PathKey , List <String >>()
107100 }
108101}
109-
110- data class LengthKey (val padIndicator : Int , val pattern : String , val robots : Int )
111-
112- data class PathKey (val padIndicator : Int , val start : Char , val end : Char )
0 commit comments