Skip to content

Commit 8695183

Browse files
committed
Precompute the shortest path graphs
1 parent 577d5d0 commit 8695183

File tree

1 file changed

+40
-8
lines changed

1 file changed

+40
-8
lines changed

day21/src/day21.scala

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,36 @@ val PAD_LAYOUTS = Map(
3030
)
3131

3232
extension (ptype: PadType) {
33-
def locate(c: Char) = PAD_LAYOUTS(ptype).find(_._2 == c).get._1
33+
def layout = PAD_LAYOUTS(ptype)
34+
35+
def locate(c: Char) = ptype.layout.find(_._2 == c).get._1
36+
37+
def shortestPath(startPos: Vec2, endPos: Vec2): String =
38+
case class Node(pos: Vec2, program: String = "") extends Ordered[Node] {
39+
def compare(that: Node): Int = that.program.length compare program.length // Intentionally reversed for min-heap
40+
}
41+
42+
val queue = mutable.PriorityQueue[Node]()
43+
val visited = mutable.Set[Vec2]()
44+
45+
queue.enqueue(Node(startPos))
46+
visited.add(startPos)
47+
48+
while !queue.isEmpty do
49+
val node = queue.dequeue()
50+
if node.pos == endPos then
51+
return node.program.appended('A')
52+
53+
for (action, dir) <- DIRECTIONS do
54+
val neigh = node.pos + dir
55+
if layout.contains(neigh) && !visited.contains(neigh) then
56+
visited.add(neigh)
57+
queue.enqueue(Node(neigh, node.program.appended(action)))
58+
59+
throw RuntimeException("No shortest program found")
60+
61+
def shortestPaths: Map[(Char, Char), String] =
62+
layout.flatMap { case (p1, a1) => layout.map { case (p2, a2) => ((a1, a2), shortestPath(p1, p2)) } }.toMap
3463
}
3564

3665
val DIRECTIONS = Map(
@@ -43,7 +72,7 @@ val DIRECTIONS = Map(
4372
val ACTIONS = List('A') ++ DIRECTIONS.keySet
4473

4574
case class Pad(ptype: PadType, pos: Vec2) {
46-
def layout = PAD_LAYOUTS(ptype)
75+
def layout = ptype.layout
4776

4877
def activate: Char = layout(pos)
4978

@@ -86,7 +115,7 @@ def shortestProgram(robots: Int, goal: String): String =
86115
// Your run-of-the-mill Dijkstra implementation
87116

88117
val queue = mutable.PriorityQueue[Node]()
89-
val visited = mutable.HashSet[State]()
118+
val visited = mutable.Set[State]()
90119

91120
val startState = State()
92121
val start = Node(startState)
@@ -107,7 +136,7 @@ def shortestProgram(robots: Int, goal: String): String =
107136
visited.add(newState)
108137
queue.enqueue(Node(newState, node.program.appended(action)))
109138

110-
throw new RuntimeException("No shortest program found")
139+
throw RuntimeException("No shortest program found")
111140

112141
def shortestProgramLength(robots: Int, goal: String): Int =
113142
case class State(pos: Vec2 = PadType.Num.locate('A'), dPos: Vec2 = PadType.Dir.locate('A'), output: String = "")
@@ -129,7 +158,7 @@ def shortestProgramLength(robots: Int, goal: String): Int =
129158
// Your run-of-the-mill Dijkstra implementation (this time on the numpad)
130159

131160
val queue = mutable.PriorityQueue[Node]()
132-
val visited = mutable.HashSet[State]()
161+
val visited = mutable.Set[State]()
133162

134163
val startState = State()
135164
val start = Node(startState)
@@ -154,7 +183,7 @@ def shortestProgramLength(robots: Int, goal: String): Int =
154183
visited.add(newState)
155184
queue.enqueue(Node(newState, node.total + c))
156185

157-
throw new RuntimeException("No shortest program found")
186+
throw RuntimeException("No shortest program found")
158187

159188
def solve(robots: Int, goals: List[String], func: (Int, String) => Int): Int =
160189
goals.map { goal =>
@@ -167,8 +196,11 @@ def solve(robots: Int, goals: List[String], func: (Int, String) => Int): Int =
167196
// println(s"Part 1: ${solve(2, goals)}")
168197
// println(s"Part 2: ${solve(25, goals)}")
169198

170-
for i <- (0 to 3) do
171-
println(s"${solve(i, goals, { (r, g) => shortestProgram(r, g).length })} vs ${solve(i, goals, shortestProgramLength)}")
199+
println(PadType.Num.shortestPaths)
200+
println(PadType.Dir.shortestPaths)
201+
202+
// for i <- (0 to 3) do
203+
// println(s"${solve(i, goals, { (r, g) => shortestProgram(r, g).length })} vs ${solve(i, goals, shortestProgramLength)}")
172204

173205
// for c <- ('0' to '5') do
174206
// println(s"$c -> ${(0 to 3).map { i => shortestProgram(makeState(i), s"$c").length }}")

0 commit comments

Comments
 (0)