Trace (Right-Hand)

Trace (Right-Hand) pathfinding algorithm — interactive grid visualization, pseudocode in five languages, and complexity reference.

Time O(steps) Unweighted Uniform

Implementation

function tracerightPathfind(grid, start, end) {
  wallFollowerGenerator(grid, start, end, false);
}
function wallFollowerGenerator(grid, start, end, keepLeftHand) {
  const rows = grid.length;
  const cols = grid[0].length;
  const dirs = [[-1, 0], [0, 1], [1, 0], [0, -1]];
  const prev = new Map();
  const visitedState = new Set();
  let r = start[0];
  let c = start[1];
  let dirIdx = 1;
  const drToEnd = end[0] - start[0];
  const dcToEnd = end[1] - start[1];
  if (Math.abs(drToEnd) > Math.abs(dcToEnd)) {
    dirIdx = drToEnd >= 0 ? 2 : 0;
  } else {
    dirIdx = dcToEnd >= 0 ? 1 : 3;
  }
  const maxSteps = rows * cols * 8;
  for (let step = 0; step < maxSteps; step++) {
    visitNode(r, c);
    if (r === end[0] && c === end[1]) {
      reconstructPath(prev, start, end);
      return;
    }
    const stateKey = `${r},${c},${dirIdx}`;
    if (visitedState.has(stateKey)) break;
    visitedState.add(stateKey);
    const preferredOrder = keepLeftHand ? [(dirIdx + 3) % 4, dirIdx, (dirIdx + 1) % 4, (dirIdx + 2) % 4] : [(dirIdx + 1) % 4, dirIdx, (dirIdx + 3) % 4, (dirIdx + 2) % 4];
    let moved = false;
    for (const nextDir of preferredOrder) {
      const nr = r + dirs[nextDir][0];
      const nc = c + dirs[nextDir][1];
      if (!inBounds(rows, cols, nr, nc) || grid[nr][nc] === WALL) continue;
      const neighborKey = key(nr, nc);
      if (!prev.has(neighborKey) && !(nr === start[0] && nc === start[1])) {
        prev.set(neighborKey, [r, c]);
      }
      dirIdx = nextDir;
      r = nr;
      c = nc;
      pushFrontier(r, c);
      moved = true;
      break;
    }
    if (!moved) break;
  }
  reportNoPath();
}