OneEdit: I just noticed you don't have a fixed endpoint to steer towards.
In this case, we can solve this with recursive backtracking:
Path FindPathOfLength(int length, Point startPoint) {
// Track visited state so we don't touch/cross.
MarkVisited(startPoint, true);
foreach(cardinal direction in random order) {
// Check if there's a path of the desired length in this direction.
path = Extend(length, startPoint, direction);
if(path == null)
continue;
// Finish & return the path.
path.Add(startPoint);
return path;
}
// Search failed. No such path exists!
return null;
}
Path Extend(int remainingLength, Point startPoint, Direction currentDirection) {
// Proceed in the given direction to find our next point.
point = startPoint + currentDirection;
if(point is out of bounds OR already visited)
return null;
// Avoid touching/crossing path so far.
if(point + currentDirection is in range AND already visited)
return null;
MarkVisited(point, true);
// Endpoint! Time to bubble back up.
if(remainingLength == 0)
return new Path(point);
foreach (turnDirection forward, left, or right of currentDirection, in random order ) {
// Search for a feasible solution to a smaller sub-problem.
path = Extend(remainingLength - 1, startPoint, turnDirection);
if(path == null)
continue;
// Extend that path to include this point.
path.Add(point);
return path;
}
// No such path through this point panned out. Undo our choice to try it.
MarkVisited(point, false);
return null;
}
Or, assuming a fixed endpoint (that's feasible to reach in the desired path length. ie. desiredPathLength - ManhattanDistance(start, end) is even), one way we could do this is using a force-directed graph.