Skip to content
All reading material
Foundations·11 min read

Simulation & Enumeration

When the fastest path is to model the process directly — direction vectors, snapshot-vs-in-place updates, state machines, and bounded brute force.


Sometimes there’s no trick

A whole class of problems just asks you to follow the rules: move a robot, run a Game of Life step, walk a spiral, apply a list of operations, parse and execute. The challenge is correctness and clean state-handling, not cleverness. These reward readable code with the state changed in one place.

Grid movement with direction vectors

Replace four ifs with a list of offsets; index into it to turn:

DIRS = [(0, 1), (1, 0), (0, -1), (-1, 0)]    # E, S, W, N
d = 0                                         # facing index
# turn right: d = (d + 1) % 4 ; turn left: d = (d - 1) % 4
r, c = r + DIRS[d][0], c + DIRS[d][1]         # step forward

This cleanly handles “spiral matrix,” “robot bounded in a circle,” “walking robot simulation,” “snake game.” For 8-directional moves, list all eight offsets.

Snapshot vs in-place updates (the classic bug)

When every cell updates from the previous state simultaneously (Game of Life, cellular automata), reading already-updated neighbors corrupts the step. Two fixes:

  • Copy first — compute into a fresh grid (simple, O(n) extra space).
  • Encode both states in one cell — e.g. use bit flags (next << 1 | cur) so the old state is still readable while you write the new one, then shift down. O(1) space, the “in-place Game of Life” trick.

State machines

“Valid number,” “string to integer (atoi),” “robot/parser” problems are cleanest as an explicit state machine: enumerate states, define transitions per input class, and step through. It turns a thicket of conditionals into a table you can verify.

Centralize the fiddly bits

  • One bounds/visited helper (in_grid(r, c)) instead of scattered checks.
  • Modular arithmetic for cyclic motion / wrap-around (pos = (pos + step) % n).
  • Name the state explicitly (position, direction, score) and mutate it in one place.

Enumeration (bounded brute force)

When the search space is small, just try everything and keep the best — all pairs, all start points, all subsets. Bound the work first from the constraints:

  • n ≤ ~10–12 → permutations / O(n!) may be fine.
  • n ≤ ~20 → subset enumeration via bitmasks (see the bit-manipulation primer).
  • small grids → brute force over cells/paths.

If enumeration is exponential and overlaps, lift it to backtracking (with pruning) or DP (see those primers). Stating “n ≤ 20, so 2ⁿ enumeration is ~10⁶ — fine” is exactly the reasoning interviewers want.

Pitfalls

  • Reading updated state mid-step (snapshot or encode both states).
  • Off-by-one at boundaries — test the first step, the last step, and wrap-around explicitly.
  • Mutating the input when the caller needs it preserved.
  • Over-engineering — if the constraints are tiny, clean brute force beats a clever algorithm you might get wrong.

Choosing in an interview

  • “Follow these rules / steps” → simulate, with direction vectors and one state-update site.
  • Simultaneous-update grid → snapshot or encode two states.
  • Parser/validator → state machine.
  • Small constraints, “find any/best arrangement” → bounded enumeration (→ backtracking/DP if it blows up).

The win condition is provably-correct, readable code: name the state, change it in one place, and test the edge steps.