Random Path Creation
Pathfinding
Algorithm Design
Programming Tips
Computer Science

How do I create a random path?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

"Random path" can mean several different things, so the first step is deciding what constraints the path must satisfy. A path for a game enemy, a simulation, and a maze generator are all random in different ways, and the code should reflect that instead of choosing random steps blindly.

Start with the Rules of Movement

Before writing code, define:

  • the space, such as a 2D grid
  • the starting point
  • the number of steps or target point
  • whether revisiting positions is allowed
  • whether the path must stay inside bounds

The simplest version is a bounded random walk. At each step, choose one of the allowed directions and move there.

python
1import random
2
3def random_walk(start, steps, width, height):
4    x, y = start
5    path = [(x, y)]
6    moves = [(1, 0), (-1, 0), (0, 1), (0, -1)]
7
8    for _ in range(steps):
9        valid_moves = []
10        for dx, dy in moves:
11            nx, ny = x + dx, y + dy
12            if 0 <= nx < width and 0 <= ny < height:
13                valid_moves.append((nx, ny))
14
15        x, y = random.choice(valid_moves)
16        path.append((x, y))
17
18    return path
19
20print(random_walk((2, 2), steps=10, width=5, height=5))

This produces a valid random path, but it may revisit the same cell many times. That is fine for diffusion-like simulations and wandering agents, but not for every use case.

Create a Non-Repeating Random Path

If you want a path that does not cross itself, track visited cells and only choose from unvisited neighbors.

python
1import random
2
3def non_repeating_path(start, steps, width, height):
4    x, y = start
5    path = [(x, y)]
6    visited = {(x, y)}
7    moves = [(1, 0), (-1, 0), (0, 1), (0, -1)]
8
9    for _ in range(steps):
10        candidates = []
11        for dx, dy in moves:
12            nx, ny = x + dx, y + dy
13            if 0 <= nx < width and 0 <= ny < height and (nx, ny) not in visited:
14                candidates.append((nx, ny))
15
16        if not candidates:
17            break
18
19        x, y = random.choice(candidates)
20        visited.add((x, y))
21        path.append((x, y))
22
23    return path
24
25print(non_repeating_path((0, 0), steps=12, width=5, height=5))

This version stops early if it runs out of valid unvisited moves. That is not a bug. It is a consequence of the constraints.

Random Path from Start to Goal

Sometimes a path must be random but still reach a destination. In that case, a pure random walk is the wrong tool because it may never arrive. A better pattern is randomized depth-first search or randomized breadth-first search.

Here is a simple randomized depth-first search on a grid:

python
1import random
2
3def random_path_to_goal(start, goal, width, height):
4    stack = [(start, [start])]
5    visited = set()
6    moves = [(1, 0), (-1, 0), (0, 1), (0, -1)]
7
8    while stack:
9        (x, y), path = stack.pop()
10        if (x, y) == goal:
11            return path
12        if (x, y) in visited:
13            continue
14
15        visited.add((x, y))
16        neighbors = []
17        for dx, dy in moves:
18            nx, ny = x + dx, y + dy
19            if 0 <= nx < width and 0 <= ny < height and (nx, ny) not in visited:
20                neighbors.append((nx, ny))
21
22        random.shuffle(neighbors)
23        for neighbor in neighbors:
24            stack.append((neighbor, path + [neighbor]))
25
26    return None
27
28print(random_path_to_goal((0, 0), (4, 4), width=5, height=5))

Because the neighbor order is shuffled, the path is different on different runs, but it still obeys the start-to-goal requirement.

Add Obstacles or Bias

Real path generation often needs more than uniform randomness. You may want to avoid walls, prefer forward movement, or create smoother turns.

One simple improvement is weighted choice. For example, if moving east should be twice as likely as other directions, assign weights and sample from them. In Python, random.choices handles that cleanly.

You can also filter out blocked cells:

python
blocked = {(1, 1), (1, 2), (2, 2)}

Then skip those coordinates when building the candidate move list.

The general rule is simple: randomness decides among valid options, but your constraints define what "valid" means.

Common Pitfalls

The biggest mistake is not defining the problem precisely. "Create a random path" is underspecified until you decide whether the path can revisit nodes, whether it must terminate at a goal, and what counts as a legal move.

Another common issue is generating moves first and checking validity later. That often creates messy code with lots of rejected steps. Build the valid candidate list first, then choose from it.

People also forget that stronger constraints reduce randomness. A path that must avoid revisits, avoid obstacles, stay in bounds, and hit a specific target cannot be generated with a trivial random walk.

Finally, be careful with reproducibility. If you need testable behavior, set a seed with random.seed(...) before generating the path.

Summary

  • Define movement rules before writing the generator.
  • Use a random walk for simple wandering behavior.
  • Track visited cells when the path must not cross itself.
  • Use randomized search when the path must reach a goal.
  • Randomness should operate within constraints, not replace them.

Course illustration
Course illustration

All Rights Reserved.