-2

For a project I had to write a program that recursively solves the 8 Queens Puzzle in all 92 solutions. The program works fine until you make the "main" method run recursively. The odd part is that it throws the error at a point that is not related to the "main" method's loop (including in the toString method). I have tried to place the recursive call everywhere possible and even my instructor can't figure it out. I also have to mention that moving the recursive call for the loop moves where it throughs the error and the program is inconsistent with at what solution throws the error.

import java.util.Scanner;
    public class NonAttackingQueens {
        private Scanner scan = new Scanner(System.in);
        //Row
        private int r = 0;
        //Column
        private int c = 0;
        private int solution = 1;
        private int[] taken = {9,9,9,9,9,9,9,9};
        private int[][] board = {
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0}};

        public static void main(String[] args){
            NonAttackingQueens board = new NonAttackingQueens();
        }

        public NonAttackingQueens(){
            place();
        }

        //This is the main method that runs everything.
        private void place(){
            //There are only 92 solutions, and this stops it after the 92th iteration
            while (solution <= 92){
                //If r==8 then it has found a solution
                if (r == 8){
                    System.out.println(this);
                    r = 7;
                    //This forces the program to continue
                    //It removes the last queen tries to move it right one
                    backTrack(0);

                    //The Scanner is used to pause the program after every solution
                    //Just hit enter to continue
                    scan.nextLine();

                    //place();
                }
                else {
                    //If it is not a legal spot
                    if (poss()){
                        board[r][c] = 1;

                        //The taken array is the location of all the queens
                        //It works the same as a regular coordinate system
                        //but being an array is a little more difficult to read
                        /*
                         *   0 1 2 3 4 5 6 7
                         * 0 9 9 9 9 9 3 9 9
                         * 1 9 9 9 9 9 3 9 9
                         * 2 9 9 9 9 9 3 9 9
                         * 3 9 9 9 9 9 3 9 9
                         * 4 9 9 9 9 9 3 9 9
                         * 5 9 9 9 9 9 3 9 9
                         * 6 9 9 9 9 9 3 9 9         
                         * 7 9 9 9 9 9 3 9 9
                         * 
                         * {9,9,9,9,9,3,9,9}
                         * 
                         */
                        //The element of the array is equal to its column
                        //The value of the element is equal to its row
                        //So a queen in row 3 column 5 is equal
                        //is equal to taken[5]=3;
                        //Or the entire first solution would have to array equal
                        //{0,6,4,7,1,3,2,5}
                        taken[c] = r;

                        r++;
                        c = 0;

                        //place();
                    }
                    //Then find a new one
                    else {
                        findNext();
                        //This is how it would run recursively........
                        //If it did not give a stack overflow
                        //this.place();
                    }
                }
                place();
            }
        }

        //Tests if it is legal to move here
        private boolean poss(){
            if (c >= 8 || taken[c] != 9 || diag()) return false;

            else return true;
        }

        //Checks for any diagonal attacks
        //It's logic is opposite of the other two conditions in the .poss()
        private boolean diag(){
            int left = c;
            int right = c;
            int tmpR = r;

            boolean found = false;

            while (left >= 0 && tmpR >= 0){
                if (board[tmpR][left] == 1) {
                    found = true;
                }
                tmpR -= 1;
                left -= 1;
            }

            tmpR = r;

            //These worked intuitively
            //They go up one row then left or right one column
            //If it hits a 1 then there's a diagonal
            //If it hits -1 then there is not
            while (right <= 7 && tmpR >= 0 && found != true){
                if (board[tmpR][right] == 1){
                    found = true;
                }
                tmpR -= 1;
                right += 1;
            }
            return found;
        }

        //This literally keeps going right until it finds an opening or hits the right side
        //Then it does the back track method
        private void findNext(){
            //The last column did not work so it immediately goes to the next one
            c++;
            //100% recursive
            if (c < 8){
                //Tests if it is a legal spot
                if (poss()){
                    return;
                }
                //If not then go to the next column
                else findNext();
            }
            //If it hits the right side then it back tracks
            else {
                //Nothing on this row so immediately go to the one before
                r--;
                backTrack(0);
            }
        }

        private void backTrack(int x){
            if (x < taken.length){
                //This is the main reason why I have the taken array
                //It checks every array element until it finds the one equal to the
                //element that needs to be removed.
                //It changes that element to 9 and removes it from the board
                //It then makes c equal one more than the column it just removed the element from
                if (taken[x] == r){
                    taken[x] = 9;
                    board[r][x] = 0;
                    c = x + 1;
                    return;
                }
                else {
                    x++;
                    backTrack(x);
                }
            }

        }

        public String toString(){
            String result="Solution: "+solution+"\n";
            for (int i=0; i<board.length; i++){
                for (int j=0; j<board[i].length; j++){
                    result += board[i][j];
                }
                result += "\n";
            }
            solution++;
            return result;
        }
    }   

To make it run recursive change the while in the place method to if and uncomment the .place() methods.

LegoNinja39
  • 5
  • 1
  • 5
  • What is the purpose of having `place()` call itself recursively at the end of the `while` loop? – Andreas Feb 19 '16 at 20:57
  • 2
    `toString()` should **not** change the state of the object!! `solution++;` doesn't belong there. – Andreas Feb 19 '16 at 20:58
  • Welcome to StackOverflow. Please read and follow the posting guidelines in the help documentation. [Minimal, complete, verifiable example](http://stackoverflow.com/help/mcve) applies here. We cannot effectively help you until you post your code and accurately describe the problem. In this case, I expect to see minimal code, such as a 4x4 board, and output tracing the program's execution and partial solutions. – Prune Feb 19 '16 at 21:16
  • Why do you have a while loop in your recursive function? – Brian Feb 19 '16 at 21:52
  • Your problem is definitely the while() loop inside your place() method. I added a `System.out.println("Recursion done");` call right after the recursive `place()` call and ran your code (with "while (solution <=3)" as the loop condition). After it found the third solution, I had 490 lines of "Recursion done" all at once. – Brian Feb 19 '16 at 22:45
  • See also http://stackoverflow.com/questions/4734108/what-is-the-maximum-depth-of-the-java-call-stack. After my previous comment, I ran your program successfully in my environment -- but I have Java configured to take a lot of RAM. – Brian Feb 19 '16 at 22:52
  • @Brian I never got that many lines. At most it would give me 50 lines, which I've run other programs that go much deeper than that. Which is BlueJ (the very very very lightweight java environment I have to use because of how it saves packages) failing again. And that explains it. – LegoNinja39 Feb 20 '16 at 02:22
  • In my test run, it did help the situation if I moved the `place()` call to after `scan.nextLine();` -- then it would at least get one complete solution before recursing. That raises an interesting question -- *how* are you intending recursion to solve this problem? Your current code is sort of a hybrid between recursion and iteration. – Brian Feb 20 '16 at 07:49
  • First off I hate recursion. I will go out of my way (unless it would be excessive, like in a sort) to use iteration. Because of this and the requirement of having to demonstrate recursion I just added some recursion here and there (most of it conversion from iteration to recursion which is more than likely the biggest problem). My instructor was very vague (and did not mention it did _not_ meet the recursion requirement) on what had to be and to what extent so "technically" the program runs on indirect recursion. – LegoNinja39 Feb 21 '16 at 00:00
  • Also this is a very basic class and is not very critical on the scoring (I gave my instructor a faulty version of my last project and still got a 90 :P). – LegoNinja39 Feb 21 '16 at 00:03

1 Answers1

0

If you're getting the overflow outside of the recursive call, that suggests a counter is causing something to go out of bounds. Either that, or the recursion is running too deep and you're running out of stack space that way. Look to the arrays being used outside of that; I would suggest printing out the values of the involved counters to see where that's happening.

If I ever get an overflow error, counters are typically where I start; particularly when I'm dealing with arrays.

Hope this helps!

X0r
  • 113
  • 5