Skip to content
← All posts

Robot Bounded In Circle: Simulation and Direction Vectors

6 min read
leetcodeproblemmediummathstringssimulation

On an infinite plane, a robot starts at position (0, 0) facing north. It receives a string of instructions where each character is one of: 'G' (go forward one unit), 'L' (turn left 90 degrees), or 'R' (turn right 90 degrees). The robot repeats the instructions forever. Return true if there exists a circle in the plane such that the robot never leaves the circle, meaning the robot's path is bounded.

This is LeetCode 1041: Robot Bounded In Circle, and it is an excellent problem for building intuition around direction vectors and simulation. The technique it teaches applies to any problem where you need to track position and orientation on a grid.

"GGLLGG"Returns to origin(0,0)NBounded"GL"Ends facing West(0,0)(0,1)WBounded"GG"Ends facing North, away(0,0)(0,2)NUnbounded
Three examples. "GGLLGG" returns to the origin, so it is bounded. "GL" ends facing West, so after 4 repetitions it will cycle back, and it is bounded. "GG" ends facing North and not at the origin, so it drifts forever and is unbounded.

Why this problem matters

Direction vectors show up constantly in grid and simulation problems. You need to move in four directions, turn left or right, and track where you end up. This problem distills that pattern into its purest form: no obstacles, no boundaries, just movement and rotation on an infinite plane.

Once you internalize how direction arrays and modular arithmetic handle turning, you can apply the same building blocks to problems like "Spiral Matrix," "Walking Robot Simulation," and any grid traversal where orientation matters.

The key insight

You do not need to simulate infinite repetitions. After executing the instruction string once, you can determine boundedness with a simple check.

If the robot ends up back at the origin (0, 0), it will obviously repeat the same loop forever. But here is the less obvious part: if the robot is not facing north after one pass, it is also bounded. Why? Because a direction change means the robot's path will rotate on each repetition. If it turns 90 degrees per pass, after 4 passes it faces north again and returns to the origin. If it turns 180 degrees per pass, after 2 passes it returns. Only when the robot ends at a non-origin position and is still facing north will it drift away forever in the same direction.

So the rule is: after one pass of the instructions, the robot is bounded if and only if it returns to the origin OR it is not facing north.

The solution

def is_robot_bounded(instructions: str) -> bool:
    dx = [0, 1, 0, -1]
    dy = [1, 0, -1, 0]
    x, y = 0, 0
    direction = 0

    for inst in instructions:
        if inst == 'G':
            x += dx[direction]
            y += dy[direction]
        elif inst == 'L':
            direction = (direction + 3) % 4
        elif inst == 'R':
            direction = (direction + 1) % 4

    return (x == 0 and y == 0) or direction != 0

Let's walk through what each piece does.

The dx and dy arrays encode the four cardinal directions. Index 0 is North (0, 1), index 1 is East (1, 0), index 2 is South (0, -1), and index 3 is West (-1, 0). This is the direction vector pattern: instead of writing four separate if-branches for movement, you index into an array.

The direction variable tracks which way the robot faces as an integer from 0 to 3. Turning right adds 1 (mod 4). Turning left adds 3 (mod 4), which is equivalent to subtracting 1 but avoids negative numbers.

For each 'G' instruction, we add the current direction's delta to the position. For 'L' and 'R', we update the direction index.

After processing all instructions, we check the two conditions. If the robot is back at the origin, it is bounded. If the direction is anything other than 0 (North), it is bounded. Only when both conditions fail, meaning the robot is somewhere other than the origin and still facing north, does it escape to infinity.

Turning left is (direction + 3) % 4 rather than (direction - 1) % 4. In many languages, the modulo of a negative number can produce a negative result. Adding 3 instead of subtracting 1 gives the same answer and avoids that pitfall entirely.

Visual walkthrough

Let's trace through the instructions "GL" step by step. Watch how the robot moves forward and turns, then see why repeating the instructions four times brings it back to the start.

Initial state

Robot starts at the origin (0,0) facing North. Direction index is 0.

(0,0)N

Instruction 1:'G'

Go forward one unit in the current direction (North). Position moves from (0,0) to (0,1). Direction stays North.

(0,1)N

Instruction 2:'L'

Turn left 90 degrees. Direction changes from North (0) to West (3). Position stays at (0,1).

(0,1)W

End of pass 1

Position is (0,1), not the origin. But direction is West, not North. Since the robot is not facing North, it is bounded. Let's verify with more repetitions.

(0,1)W

After repetition 2

Executing "GL" again from (0,1) facing West: G moves to (-1,1), L turns to face South. The robot spirals inward.

(-1,1)S

After repetition 3

Executing "GL" again from (-1,1) facing South: G moves to (-1,0), L turns to face East.

(-1,0)E

After repetition 4

Executing "GL" from (-1,0) facing East: G moves to (0,0), L turns to face North. The robot is back at the origin facing North. Cycle complete.

(0,0)N

After one pass, the robot is at (0, 1) facing West. It did not return to the origin, but it is not facing North either. That is enough to conclude it is bounded. The subsequent repetitions confirm it: the robot traces a square and returns to (0, 0) facing North after exactly four passes.

Complexity analysis

ApproachTimeSpace
Single pass simulationO(n)O(1)

Time is O(n) where n is the length of the instructions string. We iterate through the string once, performing constant work per character.

Space is O(1). We only store the position (two integers), the direction (one integer), and the direction arrays (four elements each, fixed size). No data structures grow with input size.

The building blocks

1. Direction vectors

The pattern of encoding directions as arrays:

dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]

Index 0 is North, 1 is East, 2 is South, 3 is West. To move in the current direction, you add dx[direction] to x and dy[direction] to y. This replaces branching logic with array indexing and makes the code shorter and less error-prone. You will see this same pattern in Spiral Matrix, where you cycle through right, down, left, and up as you traverse the matrix.

2. Turning with modular arithmetic

The pattern of changing direction using modular arithmetic:

direction = (direction + 1) % 4
direction = (direction + 3) % 4

Right turn adds 1 mod 4. Left turn adds 3 mod 4. This keeps the direction index in the range [0, 3] without any conditional checks. The % 4 wraps around: turning right from West (3) gives (3 + 1) % 4 = 0, which is North. Turning left from North (0) gives (0 + 3) % 4 = 3, which is West. This modular arithmetic approach to cyclic indexing comes up in circular buffer problems, rotational transforms, and anywhere you need to wrap around a fixed set of options.

Edge cases

Before submitting, think through these scenarios:

  • All G instructions ("GGGG"): the robot walks north in a straight line and still faces north. Not at origin, facing north, so return false.
  • All L instructions ("LLLL"): the robot spins in place and returns to facing north at the origin. Return true.
  • Single instruction "G": ends at (0,1) facing north. Unbounded. Return false.
  • Single instruction "L": ends at (0,0) facing west. At origin, so return true.
  • Alternating "GLGLGLGL": each GL moves forward and turns left. After four GL pairs, the robot returns to the origin. Return true.
  • Instructions that return to origin with changed direction: e.g. "GRGRGRGR". The robot traces a square each pass. Return true.

From understanding to recall

You have seen how direction vectors and modular arithmetic combine to simulate robot movement, and how a single pass is enough to determine boundedness. The logic fits in a handful of lines. But under interview pressure, the details matter. Is left +1 or +3? Is the condition direction != 0 or direction == 0? Do you check both position and direction, or just one?

Spaced repetition is how you lock these details in. You practice writing the direction arrays, the turning logic, and the final check from memory at increasing intervals. After a few rounds, you do not need to rederive the formula. You see "robot," "direction," and "bounded" in a problem statement, and the solution flows out automatically.

Related posts

CodeBricks breaks Robot Bounded In Circle into its direction vector and modular turning building blocks, then drills them independently with spaced repetition. You type each piece from scratch until the pattern is automatic. When a simulation problem shows up in your interview, you do not think about it. You just write it.