PSYCHORAPTURE, pt. 2 Challenge #2 - Scout
This challenge can be found when Martina asks Piscis for a route to Wheeler.
The Setup
Tuffy scouted the Nucleus for an emergency exit before the team's cover got blown. Eli's relying on the route data to fall back to the van.
Trace the shortest unblocked path from the Debugging Chamber to the Motor Pool, the waypoint codes along that path will spell the flag.
We are given recon.json, a scout's map of "The Nucleus" facility.
The Path
The file describes 26 waypoints (NX-01 to NX-26), each with a single hex character chalked at the junction (its code), and 38 corridors between them.
Each corridor has a length in meters and a status: clear or blocked.
We need the shortest passable route from the Debugging Chamber (NX-02) to the Motor Pool (NX-26), then read off the codes along it.
In other words, this is a weighted shortest-path problem on an undirected graph: waypoints are nodes, corridors are edges, and lengths are weights.
The only twist is that four corridors are blocked ("sealed bulkhead", "downloads jammed" twice, and "quarantine lock engaged"), so they have to be removed before searching.
The classic tool for this is Dijkstra's algorithm. The idea is to explore the graph outwards from the start, always continuing from the closest node we haven't finished with yet:
- Give every node a tentative distance:
0for the start, infinity for everything else. - Pick the unvisited node with the smallest tentative distance and mark it as visited. Its distance is now final.
- For each of its neighbours, check if going through the current node is shorter than the neighbour's tentative distance. If it is, update the distance and remember the current node as the neighbour's predecessor.
- Repeat from step 2 until the destination gets visited.
Once that's done, we rebuild the path by following the predecessors backwards from the destination to the start.
I wrote a small Python script that builds an adjacency list from the clear corridors only, adding each one in both directions, runs Dijkstra from NX-02 to NX-26, and joins the code of every node on the path, including the start and end nodes:
#!/usr/bin/env python3
"""Find the shortest clear route through the Nucleus and print its codes."""
import heapq
import json
from collections import defaultdict
with open("recon.json") as f:
recon = json.load(f)
codes = {w["id"]: w["code"] for w in recon["waypoints"]}
graph = defaultdict(list)
for c in recon["corridors"]:
if c["status"] != "clear":
continue
graph[c["from"]].append((c["to"], c["meters"]))
graph[c["to"]].append((c["from"], c["meters"]))
start, end = "NX-02", "NX-26"
dist = {start: 0}
prev = {}
queue = [(0, start)]
visited = set()
while queue:
d, node = heapq.heappop(queue)
if node in visited:
continue
visited.add(node)
if node == end:
break
for neighbour, length in graph[node]:
if d + length < dist.get(neighbour, float("inf")):
dist[neighbour] = d + length
prev[neighbour] = node
heapq.heappush(queue, (d + length, neighbour))
path = [end]
while path[-1] != start:
path.append(prev[path[-1]])
path.reverse()
print(" -> ".join(path), f"({dist[end]} m)")
print("".join(codes[n] for n in path))
The trap is the blocked corridor from the Pneumo-Tube Nexus (NX-17) to the RNA Vault (NX-01), which is only 14 m long.
If you ignore the blocked flags, the shortest route is Debugging Chamber → Pneumo-Tube Nexus → RNA Vault → Motor Pool, which totals 11 + 14 + 13 = 38 m.
With the blocked corridors removed, the route has to go around through the East Catwalk and the Sub-Level Junction.
Reading the codes of these six waypoints in order gives us the flag!