Autopilot for a Submarine Navigating Shifting Reef Gaps
AqrData Scientist · Online AssessmentLast updated
Write a controller that decides, on every tick, whether a mini-submarine should blow ballast to rise through reef-pair gaps of varying heights on unseen maps, using a short deterministic lookahead search.
A side-scrolling submarine game moves a sub to the right at a constant speed while it slowly sinks. Blowing ballast on a tick gives the sub a fixed upward velocity for that instant; otherwise it keeps sinking under constant downward drift. Reef pairs rise from the sea floor and hang from the surface, each pair leaving a gap the sub must pass through; touching a reef, the floor, or the surface ends the run. Instead of a player tapping a key, your code decides on every tick whether to blow ballast.
The controller is graded on several maps it has never seen, which differ in gap heights from one reef pair to the next and from one map to another — a controller tuned to one map's exact timings does not count.
Assume the following interface, and confirm the exact physics with the interviewer before relying on them:
from dataclasses import dataclass
@dataclass
class Reef:
x_left: float # left edge of the reef pair
x_right: float # right edge of the reef pair
gap_bottom: float # top of the lower reef
gap_top: float # bottom of the upper reef
@dataclass
class SubState:
x: float # sub's horizontal position (center)
y: float # sub's depth above the floor (center); y grows upward
vy: float # vertical velocity this tick; positive means rising
reefs: list # reefs the controller can see, sorted by x_left
def should_surface(state: SubState) -> bool:
"""Called once per tick. Return True to blow ballast on this tick."""
Constraints and Clarifications
- Assumed physics, one tick at a time: blowing ballast sets
vyto a fixed positive value; otherwisevydecreases by a constant sink rate each tick. The sub'sxthen advances by a constant forward speed andychanges by the newvy. - The sub, the floor, and the surface all have a small fixed radius/thickness to account for when checking collisions.
- The game is fully deterministic and the physics constants are known in advance.
Clarifying Questions
- How far ahead can the controller see — only the next reef, or the whole visible list?
- Is there a per-tick time budget the controller must respect?
- Should the same function handle an already-unwinnable state gracefully, or can it assume the state it's called with is always survivable?
Hints
Hint 1
The physics are fully known and deterministic. Before committing to this tick's action, simulate forward several ticks for each candidate action and check which one still has a way to survive, instead of reacting to only the very next tick.
Hint 2
Re-run that lookahead fresh on every tick (a receding horizon) rather than committing to one plan permanently, so new information about the upcoming gap keeps correcting the sub.
Hint 3
Test a tall gap immediately followed by a low one, and a gap barely taller than the sub, before trusting a controller that only looks easy on gentle maps.
Hint 4
If the sink rate and ballast strength make a gap's height physically impossible to clear, no controller can pass it — before debugging your code, check whether your own hand-built test maps are actually feasible.
Follow-up questions
- How would you cut the exponential lookahead cost for much larger horizons, for example with memoization or a heuristic search like A*?
- How would the controller need to change if ballast strength or sink rate were unknown and had to be estimated from observation?
- How would you validate that the controller generalizes to maps it has never seen, beyond a handful of hand-built test cases?
- What would change if the sub could also vary its forward speed instead of only its vertical velocity?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.