0

The issue I am currently having is my code is failing to solve different variations of a peg solitaire board. My test program tests 4 simple solvable boards. (1 move solutions) one move up, one move down, one move left, one move right. My code solves these with no problems along with testing an unsolvable board. The issue I am having is with solving more complicated problems such as a plus, a rhombus, and a standard board.

enter image description here

I'm not quite sure how to add the recursion to this problem. I have added it at the end of the solveHelp method calling setupMove again but that breaks the rest of my code. Not allowing the simple solutions to be solved correctly.

What would be the best way to apply the recursion for this problem?

public static boolean setupMove(
        boolean[][] pegs, int startX, int startY, int jumpX, int jumpY, int endX, int endY) {

    // Look at all of the pegs in the board
    for (int x = 0; x < pegs.length; x++) {
        for (int y = 0; y < pegs[x].length; y++) {
            if (pegs[x][y]) {
                startX = x;
                startY = y;

                if (startX <= 5 && pegs[startX][startY] == true
                        && pegs[startX + 1][startY] == true && pegs[startX + 2][startY] == false) {
                    tryMove(pegs, startX, startY, startX + 1, startY, startX + 2, startY);
                }
                if (startX >= 2 && pegs[startX][startY] == true 
                        && pegs[startX - 1][startY] == true && pegs[startX - 2][startY] == false) {
                    tryMove(pegs, startX, startY, startX - 1, startY, startX - 2, startY);
                }
                if (startY <= 5 && pegs[startX][startY] == true 
                        && pegs[startX][startY + 1] == true && pegs[startX][startY + 2] == false) {
                    tryMove(pegs, startX, startY, startX, startY + 1, startX, startY + 2);
                }
                if (startY >= 2 && pegs[startX][startY] == true 
                        && pegs[startX][startY - 1] == true && pegs[startX][startY - 2] == false) {
                    tryMove(pegs, startX, startY, startX, startY - 1, startX, startY - 2);
                }
            }
        }
    }
    if (win) {
        return true;
    } else {
        solution = null;
        return false;
    }
}

public static void tryMove(
        boolean[][] pegs, int startX, int startY, int jumpX, int jumpY, int endX, int endY) {
    pegs[startX][startY] = false;
    pegs[jumpX][jumpY] = false;
    pegs[endX][endY] = true;
    prevSolution = solution;
    solution = solution + " " + startY + " " + startX + " " + endY + " " + endX;
    solveHelp(pegs, startX, startY, jumpX, jumpY, endX, endY);
}

public static void solveHelp(
        boolean[][] pegs, int startX, int startY, int jumpX, int jumpY, int endX, int endY) {
    for (int x = 0; x < pegs.length; x++) {
        for (int y = 0; y < pegs[x].length; y++) {
            if (pegs[x][y]) {
                pegCount++;
            }
        }
    }
    if (pegs[3][3] && pegCount == 1) {
        // WE WIN!!!
        win = true;
    }

    if ((!win && pegCount == 1) || (endX < 0 || endY < 0 
            || endX >= pegs.length || endY >= pegs[endX].length 
            || (endX < 2 && endY < 2) || (endX >= 5 && endY < 2) 
            || (endX < 2 && endY >= 5) || (endX >= 5 && endY >= 5))) {
        pegs[startX][startY] = true;
        pegs[jumpX][jumpY] = true;
        pegs[endX][endY] = false;
        pegCount++;
        solution = prevSolution;
    }
    pegCount = 0;
}
Pawel Veselov
  • 3,996
  • 7
  • 44
  • 62
  • Possible duplicate of [What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?](https://stackoverflow.com/questions/5554734/what-causes-a-java-lang-arrayindexoutofboundsexception-and-how-do-i-prevent-it) – Sascha May 23 '19 at 12:33
  • Please see [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask). One recommendation there is to post [mcve] (please also include hard-coded test data for both "pass" and "fail" ). Another recomendation is "DO NOT post images of code, data, error messages". – c0der May 23 '19 at 13:12
  • Side note: I can't find recursive call in the code. – c0der May 23 '19 at 13:19
  • @c0der Yes, sorry. There is no recursion. I can't figure out where to put it. That was my main question. Sorry I will edit it and make that more clear. Also why not to post images of error messages? – Anthony Perez May 23 '19 at 23:01
  • This is a poor problem for recursion. Look up "Best First Heuristic Search" for the standard simple open set / closed set algorithm, which uses a loop. – Gene May 24 '19 at 00:16
  • It's for a homework assignment. I have to use recursion @Gene – Anthony Perez May 24 '19 at 00:18
  • Kind of like driving a screw with a hammer. I'll let some notes about how you can do it. – Gene May 24 '19 at 00:29
  • I know that's what everyone has been saying. It's super annoying it's actually over a week late as is. I have to have it done by Friday or I can't turn it in. – Anthony Perez May 24 '19 at 00:38

1 Answers1

0

Expressing an algorithm recursively is about writing it as a method that solves the problem by transforming it into slightly simpler versions of itself. Then call the same method recursively to solve those.

The method finally stops the chain of self-calls by checking for one or more "base cases." These are when the problem is so simple that the answer is obvious.

You've chosen a method signature that won't allow a recursive solution. There's no dishonor in this. Getting a usable recursive method signature is a skill acquired through lots of practice.

Here you'll do better if the method accepts just a solitaire board configuration and the number of pegs it contains, say N. Then for each legal way of making a jump, it makes that jump, producing a new version of the board with N-1 pegs. It calls itself to solve this new, smaller problem. The base case is 1 peg, which of course means you win.

void play(boolean [][] board, int nPegs) {
  if (nPegs == 1) { System.out.println("We win!"); System.exit(0); }
  else {
    for (int i = 0; i < 7; ++i) { // i is the row
      for (int j = 0; j < 7; ++j) { // j is the column
        if (!board[i][j]) continue; // No pin. Skip this position
        if (isLegalToJumpEast(board, i, j)) {
          // Do the jump east and solve recursively.
          board[i][j] = board[i][j + 1] = false;
          board[i][j + 2] = true;
          play(board, n - 1);
          // Undo the jump so the search can continue.
          board[i][j] = board[i][j + 1] = true;
          board[i][j + 2] = false;
        }
        // .. similar if()'s for West, North, and South.
      }
    }
  }
}

Of course this skips interesting parts of the problem like printing the solution once it's found.

Also, this algorithm is incredibly wasteful because it will re-evaluate the same board configuration many times. This is totally unnecessary. Once you've explored all possible outcomes of a given board, there's no sense in doing it again.

You can fix this problem by "memoizing" the recursive method. At the start of the method, check a set of already-explored boards and do nothing if the current board is found. Else save a copy in the set and proceed.

The Java details of copying and saving 2d matrices in a Set<> are another topic for you to explore. You might need to figure this out for your algorithm to finish in reasonable time.

Gene
  • 46,253
  • 4
  • 58
  • 96
  • Sorry if im being dumb, I just started coding a few months ago and had no previous knowledge to it prior. isLegalToJumpEast is another method that is checking if [i][j] is true [i][j + 1] is true and [i][j + 2] is false. correct? – Anthony Perez May 24 '19 at 01:52
  • @AnthonyPerez yes. It looks like `isLegalToJumpEast(board, i, j)` checks if going east from i,j position is valid. You should make four 4 similar methods (east, west, south, north) or have one that does all like `isValidJumpTo(board, i, j, newI, newJ)` – c0der May 24 '19 at 04:11
  • Well, and also if he two spaces to the right actually exist on the board. Remember the corners are illegal jump targets. – Gene May 25 '19 at 03:15