-1

I am working on a program that generates sudoku puzzles. I was trying to use a backtracking algorithm to do this but my program is not working. The program just runs infinitely and never returns a solution. I don't know if its just a minor problem or I misunderstand how to write a backtracking algorithm.

package sudoku;

import java.util.Random;

public class Puzzle {

    // 9x9 puzzle
    private int puzzle[][] = new int[9][9];

    // generate a completely solved sudoku board
    public int[][] generate() {

        Random gen = new Random();

        // add each number to the board square by square
        for (int y = 0; y < 9; y++) {
            for (int x = 0; x < 9; x++) {

                // generate random number 1-9
                int num = gen.nextInt(9) + 1;

                int count = 0;
                boolean valid = false;

                while (valid == false) {

                    // check if number is valid
                    if (checkRow(num, x) && checkCol(num, y)
                            && checkSection(num, x, y)) {

                        // add number to the board
                        puzzle[x][y] = num;

                        // exit loop, move on to next square
                        valid = true;

                    } else {

                        // try next number
                        if (num == 9) {
                            num = 1;
                        } else {
                            num++;
                        }

                        // increase counter.
                        count++;

                        // if counter reached 9, then all numbers were tried and
                        // none were valid, begin backtracking
                        if (count == 9) {

                            // go back 1 square
                            if (x == 0) {
                                x = 8;
                                y--;
                            } else {
                                x--;
                            }

                            // empty square
                            puzzle[x][y] = 0;

                            //reset count
                            count = 0;

                        }

                    }

                }
            }
        }

        return puzzle;
    }

    // check each element of the row for num, if num is found return false
    private boolean checkRow(int num, int row) {

        for (int i = 0; i < 9; i++) {
            if (puzzle[row][i] == num) {
                return false;
            }
        }

        return true;
    }

    // check each element of the column for num, if num is found return false
    private boolean checkCol(int num, int col) {

        for (int i = 0; i < 9; i++) {
            if (puzzle[i][col] == num) {
                return false;
            }
        }

        return true;
    }

    // check each element of the section for num, if num is found return false
    private boolean checkSection(int num, int xPos, int yPos) {

        int[][] section = new int[3][3];
        section = getSection(xPos, yPos);

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (section[i][j] == num)
                    return false;
            }
        }
        return true;

    }

    // return the 3x3 section the given coordinates are in
    private int[][] getSection(int xPos, int yPos) {

        int[][] section = new int[3][3];
        int xIndex = 3 * (xPos / 3);
        int yIndex = 3 * (yPos / 3);

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                section[i][j] = puzzle[xIndex + i][yIndex + j];
            }
        }

        return section;

    }
}
Dave Newton
  • 158,873
  • 26
  • 254
  • 302
Petefic
  • 657
  • 6
  • 14
  • 31
  • 3
    What do you use to write your program? Are you using a text editor or an IDE like NetBeans or Eclipse. If the later, you should learn how to use the debugger. This is an essential tool for any programmer. – Code-Apprentice Jun 22 '13 at 22:44
  • I've never done backtracking w/o recursion before; now I think I know why. Start tracing through program execution. Start with a smaller board. – Dave Newton Jun 22 '13 at 22:50
  • 1
    Don't change the indexes of the `for` in the middle of the loop, that is bad practice that prevents the compiler from optimizing your code. – SJuan76 Jun 22 '13 at 22:56

2 Answers2

1

There are a number of issues that may happen. I will just put an example.

The principal reason backtracking is not working is because you are not doing backtracking. You only go back one state in the tree, backtracking means that you check all possibilities of a subtree and then (if none is valid) you ignore that subtree, no matter how high is it.

Let's see. Your approach is "put all the numbers in a line and hope that the square gets completed. In case there is an error dealing with the current square, clear the previous one".

At the beginning no problem, getting the first lines will cause no error. But think of the possibility that you have completed the first 8 lines, with something like that:

1
2
3
----
4
5
6
---
79
832|179|456     
x

There is no valid value for x. What does your algorithm do? Go back and try to change the 6! Unsurprisingly, that will end with replacing the 6 with a 6, and trying again to set a value to x.

Sudokus generators that I found in the internet have no backtracking, just take a valid solution and perform a series of changes to it, in a way that all the changes bring valid solutions (for more details, ask google).

If you wanted to use backtracking, at each step you should scan if the sudoku is still solvable (or at least, that is not "broken"). And have a way of not repeating the non-solvable combinations.

Additionally, trying to put the numbers in order seems (that is an opinion) to add a constraint too strong at the beginning. Filling the first two lines is easy, but it will condition the entire solution (note that filling the first line does not affect it! :-D).

SJuan76
  • 24,532
  • 6
  • 47
  • 87
0

I don't think that this is a good way to approach the problem; unfortunately, I don't have a solution for you, but I do see that once count == 9, you change x and y, which isn't something that's necessarily good to do. Nonetheless, you do not provide a way to terminate the while(!valid) loop. You need to change valid to true to actually backtrack; however, this won't make the method work.

Steve P.
  • 14,489
  • 8
  • 42
  • 72