Skip to content

Commit 7c7712a

Browse files
committed
Implement the 0-robots problem as a search on the numpad
1 parent b43b7d9 commit 7c7712a

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

day21/src/day21.scala

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,44 @@ def makePads(robots: Int): List[Pad] = List.fill(robots)(Pad(PadType.Dir)) :+ Pa
110110

111111
def makeState(robots: Int) = State(makePads(robots))
112112

113-
def solve(robots: Int, goals: List[String]): Int =
114-
val state = makeState(robots)
113+
def cost(robots: Int, pos: Vec2, action: Char): Int = 1
114+
115+
def shortestProgramLength(robots: Int, goal: String): Int =
116+
case class Node(pos: Vec2, output: String = "", total: Int = 0) extends Ordered[Node] {
117+
def compare(that: Node): Int = that.total compare total // Intentionally reversed for min-heap
118+
}
119+
120+
// Your run-of-the-mill Dijkstra implementation (this time on the numpad)
121+
122+
val queue = mutable.PriorityQueue[Node]()
123+
val visited = mutable.HashSet[(Vec2, String)]()
124+
125+
val startPos = PadType.Num.locate('A')
126+
val start = Node(startPos)
127+
queue.enqueue(start)
128+
visited.add((start.pos, start.output))
129+
130+
while !queue.isEmpty do
131+
val node = queue.dequeue()
132+
if node.output == goal then
133+
return node.total
134+
135+
if node.output.length < goal.length then
136+
for
137+
action <- ACTIONS
138+
do
139+
val newPos = node.pos + DIRECTIONS.get(action).getOrElse(Vec2(0, 0))
140+
if PAD_LAYOUTS(PadType.Num).contains(newPos) then
141+
val newOutput = if action == 'A' then node.output.appended(PAD_LAYOUTS(PadType.Num)(node.pos)) else node.output
142+
if !visited.contains((newPos, newOutput)) then
143+
visited.add((newPos, newOutput))
144+
queue.enqueue(Node(newPos, newOutput, node.total + cost(robots, node.pos, action)))
145+
146+
throw new RuntimeException("No shortest program found")
147+
148+
def solve(robots: Int, goals: List[String], func: (Int, String) => Int): Int =
115149
goals.map { goal =>
116-
val shortest = shortestProgram(state, goal).length
150+
val shortest = func(robots, goal)
117151
shortest * goal.dropRight(1).toInt
118152
}.sum
119153

@@ -122,5 +156,8 @@ def solve(robots: Int, goals: List[String]): Int =
122156
// println(s"Part 1: ${solve(2, goals)}")
123157
// println(s"Part 2: ${solve(25, goals)}")
124158

125-
for c <- ('0' to '5') do
126-
println(s"$c -> ${(0 to 3).map { i => shortestProgram(makeState(i), s"$c").length }}")
159+
for i <- (0 to 3) do
160+
println(s"${solve(i, goals, { (r, g) => shortestProgram(makeState(r), g).length })} vs ${solve(i, goals, shortestProgramLength)}")
161+
162+
// for c <- ('0' to '5') do
163+
// println(s"$c -> ${(0 to 3).map { i => shortestProgram(makeState(i), s"$c").length }}")

0 commit comments

Comments
 (0)