-1

I'm trying to write a program that outputs (in the console) all possible paths (in (x1,x1) --> (x2,x2) --> etc.. format) for navigating a grid of size NxN, from top-left to bottom-right; i.e. from (0,0) to (N-1,N-1). You can only move down or right; i.e. from (0,0) to (0,1) or to (1,0). I want the program to output each time a full path set is found (i.e. all moves from top-left to bottom-right), and what that path set is.

It seems as though the best way to write this is with a recursive method inputting each move into an arrayList (see the buildPath method - the last method in the program), which is where I'm having trouble.

To make it slightly more complicated, I'm also generating random grid positions that are "off-limits" and as such can't be passed through. That said, I can probably work that part out for myself once we/I figure out how to actually get the thing working with any paths at all.

How would I implement a recursive method to determine which paths are possible? Any help is appreciated (even pseudo-code would be better than nothing)!

Here is my code so far (the simple bits are in pseudo-code to make it easier to work through, but let me know if I should put the full code in):

import java.util.*;

public class RecursiveAlgorithm {

    public static ArrayList<Integer> allPaths = new ArrayList<Integer>();
    public static ArrayList<String> pathSet = new ArrayList<String>();
    public static int path;
    public static int N, M, x = 0, y = 0;
    public static String nString, mString;
    public static boolean grid[][];
    public static int right, down;

    @SuppressWarnings("resource")
    public static void main(String[] args) {

        //sets the current position to (0,0)
        right = 0;
        down = 0;

        Input value of N (size of grid)

        Input value of M (number of off-limits locations)

        offLimits(N, M); //calls offLimits method to randomly generate off-limits locations

        buildPath(right, down, allPaths, N); //calls buildPath method

    }

    public static void offLimits (int N, int M) {

        int mCount = 0;
        if (M == 0){
        } else {
            while (mCount < (M + 1)) {
              //int range1 = (max - min) + 1;
                int range1 = ((N-1) - 1) + 1;
                int range2 = ((N-1) - 0) + 1;
                int random1 = (int)((Math.random() * range1) + 1);
                int random2 = (int)(Math.random() * range2);


                //if an 'off-limits' point is generated at the finish point, move it to either 1 place to the left or 1 place above
                if ((random1 == N-1) && (random2 == N-1)) {
                    int switchSelect = (int)(Math.random() * 2);
                    while (switchSelect > 0) {
                        switch (switchSelect){

                        case 1: random1--;
                                break;

                        case 2: random2--;
                                break;

                        }
                    }
                }
                //sets a grid position to 'off-limits' (i.e. random1 = 1, random2 = 2 --> (1, 2) is 'off-limits')
                grid[random1][random2] = true;
                //counts the amount of off-limits grid locations generated
                mCount++;
            }
        }

    }

    public static ArrayList<String> buildPath (int right, int down, ArrayList<Integer> allPaths, int N) {

        //Updates path with current location (right, down)  


        /***** FROM HERE ON IS WHERE I AM HAVING TROUBLE *****/

        //Stopping Condition
        if ((right == N-1) && (down == N-1)) { //robot cannot go right
            allPaths.add(path);
            return pathSet;
        }   
        //Recursive Steps
        if (right == N-1) { //robot cannot go right
            buildPath (right, down + 1, allPaths, N);

        } else if (down == N-1) { //robot cannot go down
            buildPath (right + 1, down, allPaths, N);
        } else { //robot CAN go right or go down
                buildPath (right + 1, down, allPaths, N);
                //pathSet.add(Integer.toString(right));
                //pathSet.add(Integer.toString(down));
                buildPath (right, down + 1, allPaths, N);

            if (grid[x][y] == false) {
                //valid new position (substitute x and y for proposed new path step)

            } else if (grid[x][y] == true) {
                //off-limits position (substitute x and y for proposed new path step)

            }
        }
        return pathSet;
    }
}
rst-2cv
  • 1,130
  • 1
  • 15
  • 31
  • Welcome to Stack Overflow! We are a question-and-answer site, not a coders-for-hire service. Please narrow your question down to a specific coding problem that would be on-topic for this site. See: [Why is "Can someone help me?" not an actual question?](http://meta.stackoverflow.com/q/284236) and [How to ask a good question when I'm not sure what I'm looking for?](https://meta.stackoverflow.com/questions/262527/how-to-ask-a-good-question-when-im-not-sure-what-im-looking-for) – Joe C Apr 01 '17 at 14:15
  • 4
    You obviously didn't read my OP if you think I'm not asking a specific question. – rst-2cv Apr 01 '17 at 14:18
  • Possible duplicate of [Algorithm for finding all paths in a NxN grid](http://stackoverflow.com/questions/9105699/algorithm-for-finding-all-paths-in-a-nxn-grid) – fps Apr 01 '17 at 15:58

1 Answers1

2

You're on the right track, but headed toward a solution more complex than needed. Here's one approach that finds them allowing all 4 compass directions (not just right and down). See how simple you can make it by removing code.

import java.util.LinkedHashSet;

class Experimental {
  static class PathFinder {
    final int gridSize;
    final boolean [] [] isBlocked;
    final Coord goal;
    final LinkedHashSet<Coord> path = new LinkedHashSet<>();
    final Random gen = new Random();

    PathFinder(int gridSize, int nBlocked) {
      this.gridSize = gridSize;
      this.isBlocked = new boolean[gridSize][gridSize];
      this.goal = new Coord(gridSize - 1, gridSize - 1);
      // This gets really inefficient if nBlocked is too big.
      for (int n = 0; n < nBlocked; ++n) {
        int x, y;
        do {
          x = gen.nextInt(gridSize);
          y = gen.nextInt(gridSize);
        } while (isBlocked[x][y] || (x == gridSize - 1 && y == gridSize - 1));
        isBlocked[x][y] = true;
      }
    }

    void searchFrom(Coord coord) {
      if (path.contains(coord)) return;
      path.add(coord);
      if (coord.equals(goal)) System.out.println(path);
      if (coord.x > 0 && !isBlocked[coord.x - 1][coord.y])
        searchFrom(new Coord(coord.x - 1, coord.y));
      if (coord.y > 0 && !isBlocked[coord.x][coord.y - 1])
        searchFrom(new Coord(coord.x, coord.y - 1));
      if (coord.x < gridSize - 1 && !isBlocked[coord.x + 1][coord.y])
        searchFrom(new Coord(coord.x + 1, coord.y));
      if (coord.y < gridSize - 1 && !isBlocked[coord.x][coord.y + 1])
        searchFrom(new Coord(coord.x, coord.y + 1));
      path.remove(coord);
    }

    void printAllPaths() {
      searchFrom(new Coord(0, 0));
    }

    static class Coord {
      final int x, y;
      public Coord(int x, int y) {
        this.x = x;
        this.y = y;
      }
      @Override
      public boolean equals(Object obj) {
        if (obj instanceof Coord) {
          Coord other = (Coord) obj;
          return x == other.x && y == other.y;
        }
        return false;
      }
      @Override
      public int hashCode() {
        return Integer.hashCode(x) ^ Integer.hashCode(-y);
      }
      @Override
      public String toString() {
        return '(' + Integer.toString(x) + ',' + Integer.toString(y) + ')';
      }
    }
  }

  public static void main(String[] args) {
    new PathFinder(4, new boolean [] [] {
      { false, false, false, false },
      { false, false, true, false },
      { true, false, false, false },
      { false, false, false, false },
    }).printAllPaths();
  }
}

One hint: The linked hash set is a reasonable choice for the path here because we need to look "backward" at each step to make sure we're not about to visit a location already visited. The set makes the lookups O(1), while the linking ensures order is maintained, which normal hash sets don't. Your problem is different.

Gene
  • 46,253
  • 4
  • 58
  • 96
  • In your `main` method, you define a 2D boolean array with 2 points marked as true. I'm assuming you've done this to define which points are off-limits. I want them to be generated randomly. In which case, does my code in my `offLimits` method achieve that or does it not work? – rst-2cv Apr 02 '17 at 03:13
  • 1
    @RThomP Well, you don't have any code there, so hard to tell. – Gene Apr 02 '17 at 04:07
  • Welp. Forgot I only had pseudo-code there. I've updated the OP with my code for that method. – rst-2cv Apr 02 '17 at 08:17
  • @RThomP Your code is again more complex than needed. I don't understand why you picked the number of rows to be the number of random choices. Also you allow the same square to be chosen more than once. I added a random picker that's simpler and lets the user choose exactly how many squares to make off limits. But it assumes the grid is square, and it works too hard if you specify a number of blocked squares that's too high. You can have fun fixing these. There's an algorithm with run time linear in the number of picked off limits square, regardless of how many are being picked. – Gene Apr 03 '17 at 04:51