Skip to content

Commit f926e4e

Browse files
committed
Day 21, part 1: One shortest sequence for each keypad
But not the shortest sequence over all stages. To get there, we have to evaluate all shortest paths for each code on each keypad and take the shortest among all.
1 parent d79dd40 commit f926e4e

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package de.ronny_h.aoc.year24.day21
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.Coordinates
5+
import de.ronny_h.aoc.extensions.Direction
6+
import de.ronny_h.aoc.extensions.Grid
7+
import de.ronny_h.aoc.extensions.ShortestPath
8+
import de.ronny_h.aoc.extensions.aStar
9+
import de.ronny_h.aoc.extensions.asList
10+
11+
fun main() = KeypadConundrum().run(0, 0)
12+
13+
class KeypadConundrum : AdventOfCode<Int>(2024, 21) {
14+
override fun part1(input: List<String>): Int {
15+
println("directionalKeypad: $directionalKeypadLayout")
16+
17+
val numericKeypad = Keypad(numericKeypadLayout)
18+
val sequence = input.map { code ->
19+
val sequence1 = code.map { position ->
20+
numericKeypad.moveTo(position)
21+
}.joinToString("")
22+
println("robot1: $sequence1")
23+
24+
val directionalKeypad1 = Keypad(directionalKeypadLayout)
25+
val sequence2 = sequence1.map { direction ->
26+
directionalKeypad1.moveTo(direction)
27+
}.joinToString("")
28+
println("robot2: $sequence2")
29+
30+
val directionalKeypad2 = Keypad(directionalKeypadLayout)
31+
val sequence3 = sequence2.map { direction ->
32+
directionalKeypad2.moveTo(direction)
33+
}.joinToString("")
34+
println("$code: $sequence3")
35+
}
36+
37+
return 0
38+
}
39+
40+
override fun part2(input: List<String>): Int {
41+
TODO("Not yet implemented")
42+
}
43+
}
44+
45+
/*
46+
+---+---+---+
47+
| 7 | 8 | 9 |
48+
+---+---+---+
49+
| 4 | 5 | 6 |
50+
+---+---+---+
51+
| 1 | 2 | 3 |
52+
+---+---+---+
53+
| 0 | A |
54+
+---+---+
55+
*/
56+
val numericKeypadLayout = """
57+
789
58+
456
59+
123
60+
0A
61+
""".asList()
62+
63+
/*
64+
+---+---+
65+
| ^ | A |
66+
+---+---+---+
67+
| < | v | > |
68+
+---+---+---+
69+
*/
70+
val directionalKeypadLayout = """
71+
^A
72+
<v>
73+
""".asList()
74+
75+
class Keypad(layout: List<String>) : Grid<Char>(layout, ' ') {
76+
override fun Char.toElementType(): Char = this
77+
78+
data class Node(val direction: Direction, val position: Coordinates) {
79+
override fun toString() = "$position$direction"
80+
}
81+
82+
private var currentPosition = find('A')
83+
84+
fun moveTo(target: Char): String {
85+
val targetPosition = find(target)
86+
val path = shortestPath(currentPosition, targetPosition)
87+
currentPosition = targetPosition
88+
val directions = path.path.drop(1).joinToString("") {
89+
when (it.direction) {
90+
Direction.NORTH -> "^"
91+
Direction.EAST -> ">"
92+
Direction.SOUTH -> "v"
93+
Direction.WEST -> "<"
94+
}
95+
}
96+
return "${directions}A"
97+
}
98+
99+
fun shortestPath(start: Coordinates, goal: Coordinates): ShortestPath<Node> {
100+
101+
val neighbours: (Node) -> List<Node> = { node ->
102+
Direction
103+
.entries
104+
.map { Node(it, node.position + it) }
105+
.filter { getAt(it.position) != nullElement }
106+
}
107+
108+
val d: (Node, Node) -> Int = { a, b ->
109+
// pre-condition: a and b are neighbours
110+
1
111+
}
112+
113+
val h: (Node) -> Int = { it.position taxiDistanceTo goal }
114+
115+
return aStar(Node(Direction.EAST, start), { this.position == goal }, neighbours, d, h)
116+
}
117+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package de.ronny_h.aoc.year24.day21
2+
3+
import de.ronny_h.aoc.extensions.asList
4+
import io.kotest.core.spec.style.StringSpec
5+
import io.kotest.matchers.shouldBe
6+
7+
class KeypadConundrumTest : StringSpec({
8+
val input = """
9+
029A
10+
980A
11+
179A
12+
456A
13+
379A
14+
""".asList()
15+
16+
"make the 1st robot type 029A" {
17+
val numericKeypad = Keypad(numericKeypadLayout)
18+
numericKeypad.moveTo('0') shouldBe "<A"
19+
numericKeypad.moveTo('2') shouldBe "^A"
20+
numericKeypad.moveTo('9') shouldBe "^^>A"
21+
numericKeypad.moveTo('A') shouldBe "vvvA"
22+
}
23+
24+
"make the 2nd robot type ^^>A" {
25+
val directionalKeypad = Keypad(directionalKeypadLayout)
26+
directionalKeypad.moveTo('^') shouldBe "<A"
27+
directionalKeypad.moveTo('^') shouldBe "A"
28+
directionalKeypad.moveTo('>') shouldBe ">vA"
29+
directionalKeypad.moveTo('A') shouldBe "^A"
30+
}
31+
32+
"part 1: The sum of the complexities of the five codes" {
33+
KeypadConundrum().part1(input) shouldBe 126384
34+
}
35+
})

0 commit comments

Comments
 (0)