3

I've this Sudoku code that's done using backtracking and I understand everything, except few lines of code which I ask to be explained. This is the whole code.

public class Sudoku {


    static int N = 9;


    static int grid[][] = { { 3, 0, 6, 5, 0, 8, 4, 0, 0 }, 
            { 5, 2, 0, 0, 0, 0, 0, 0, 0 }, 
            { 0, 8, 7, 0, 0, 0, 0, 3, 1 }, 
            { 0, 0, 3, 0, 1, 0, 0, 8, 0 }, 
            { 9, 0, 0, 8, 6, 3, 0, 0, 5 }, 
            { 0, 5, 0, 0, 9, 0, 6, 0, 0 }, 
            { 1, 3, 0, 0, 0, 0, 2, 5, 0 }, 
            { 0, 0, 0, 0, 0, 0, 0, 7, 4 }, 
            { 0, 0, 5, 2, 0, 6, 3, 0, 0 } };

    static class Cell {

        int row, col;

        public Cell(int row, int col) {
            super();
            this.row = row;
            this.col = col;
        }

        @Override
        public String toString() {
            return "Cell [row=" + row + ", col=" + col + "]";
        }
    };



    static boolean isValid(Cell cell, int value) {

        if (grid[cell.row][cell.col] != 0) {
            throw new RuntimeException("Cannot call for cell which already has a value");
        }


        for (int c = 0; c < 9; c++) {
            if (grid[cell.row][c] == value)
                return false;
        }


        for (int r = 0; r < 9; r++) {
            if (grid[r][cell.col] == value)
                return false;
        }


        int x1 = 3 * (cell.row / 3);
        int y1 = 3 * (cell.col / 3);
        int x2 = x1 + 2;
        int y2 = y1 + 2;

        for (int x = x1; x <= x2; x++)
            for (int y = y1; y <= y2; y++)
                if (grid[x][y] == value)
                    return false;

        return true;
    }


    static Cell getNextCell(Cell cur) {

        int row = cur.row;
        int col = cur.col;


        col++;

        if (col > 8) {

            col = 0;
            row++;
        }


        if (row > 8)
            return null; 

        Cell next = new Cell(row, col);
        return next;
    }


    static boolean solve(Cell cur) {


        if (cur == null)
            return true;


        if (grid[cur.row][cur.col] != 0) {

            return solve(getNextCell(cur));
        }


        for (int i = 1; i <= 9; i++) {

            boolean valid = isValid(cur, i);

            if (!valid)
                continue;


            grid[cur.row][cur.col] = i;


            boolean solved = solve(getNextCell(cur));

            if (solved)
                return true;
            else
                grid[cur.row][cur.col] = 0; 

        }

        return false;
    }

    public static void main(String[] args) {
        boolean solved = solve(new Cell(0, 0));
        if (!solved) {
            System.out.println("SUDOKU cannot be solved.");
            return;
        }
        System.out.println("SOLUTION\n");
        printGrid(grid);
    }


    static void printGrid(int grid[][]) {
        for (int row = 0; row < N; row++) {
            for (int col = 0; col < N; col++)
                System.out.print(grid[row][col]);
            System.out.println();
        }
    }
}

However, if you go to isValid method I can't really understand this part. If someone can explain this part in detail and what exactly it does, that would be great. I saw this in many codes, but I still can not comprehend it.

        int x1 = 3 * (cell.row / 3);
        int y1 = 3 * (cell.col / 3);
        int x2 = x1 + 2;
        int y2 = y1 + 2;

        for (int x = x1; x <= x2; x++)
            for (int y = y1; y <= y2; y++)
                if (grid[x][y] == value)
                    return false;

        return true;
Seinfeld
  • 433
  • 7
  • 24
  • Have you tested these codes? Are they able to run without any exceptions? – user3437460 Jan 16 '17 at 18:09
  • Yeah, it works 100%. – Seinfeld Jan 16 '17 at 18:10
  • I get you, but it does not. I have this code in eclipse and it works, but I get what you are referring to. This is not my code, that' why I'm asking these lines, cuz it doesn't make much sense for me. – Seinfeld Jan 16 '17 at 18:14
  • Nvm, I know what those codes are doing already. See my solution in a min – user3437460 Jan 16 '17 at 18:14
  • One hint for your next question: please take the time and format/indent all of your input properly. There is no point in wasting those many empty lines for example. – GhostCat Jan 16 '17 at 19:04

3 Answers3

3
        int x1 = 3 * (cell.row / 3);
        int y1 = 3 * (cell.col / 3);
        int x2 = x1 + 2;
        int y2 = y1 + 2;

        for (int x = x1; x <= x2; x++)
            for (int y = y1; y <= y2; y++)
                if (grid[x][y] == value)
                    return false;

        return true;

This block of code locates the 3x3 box containing your current number. The nested loops checks that the given number does not exist in the 3x3 box.


If you are wondering why the formula (divide by 3 then multiply by 3) followed by adding of 2. Take a look:

If current row is 0..8:

3 * (0 / 3) + 2 = 2 (read 3x3 box starting from pos 0 to 2)
3 * (1 / 3) + 2 = 2 (read 3x3 box starting from pos 0 to 2)
3 * (2 / 3) + 2 = 2 (read 3x3 box starting from pos 0 to 2)

3 * (3 / 3) + 2 = 5 (read 3x3 box starting from pos 3 to 5)
3 * (4 / 3) + 2 = 5 (read 3x3 box starting from pos 3 to 5)
3 * (5 / 3) + 2 = 5 (read 3x3 box starting from pos 3 to 5)

3 * (6 / 3) + 2 = 8 (read 3x3 box starting from pos 6 to 8)
3 * (7 / 3) + 2 = 8 (read 3x3 box starting from pos 6 to 8)
3 * (8 / 3) + 2 = 8 (read 3x3 box starting from pos 6 to 8)
user3437460
  • 17,253
  • 15
  • 58
  • 106
  • But why x2 and y2 are even made ? And what does 11 has to do with the grid that's 3x3. Shouldn't for loop that's looping to x1 + 1 be enough ? – Seinfeld Jan 16 '17 at 18:19
  • @Seinfeld It won't become 11. It always +2 because your grid array index always starts from 0. So if it is 2, it reads a 3x3 box (i.e.: index 0,1,2). – user3437460 Jan 16 '17 at 18:22
  • 1
    Oh, I finally get it. That's what made my some troubles. Thanks. GJ – Seinfeld Jan 16 '17 at 18:23
1

Assuming comments were meant to be useful to explain the code -

/** your row and column index are based on 0, 
 * and you evaluate the start index or lower bound for the 3x3 grid */
int x1 = 3 * (cell.row / 3);
int y1 = 3 * (cell.col / 3);
/** with the upper bound or the end index for the 3x3 grid 
 * at postion = initial + 2 */
int x2 = x1 + 2;
int y2 = y1 + 2;

/** Iterate through the 3x3 to validate the same element is not present
 * twice in the 3x3 inner grid */
for (int x = x1; x <= x2; x++)
    for (int y = y1; y <= y2; y++)
        if (grid[x][y] == value)
            return false; // false if its already there

return true;

For the lower and upper bound vaules, think of grouping indexes 0-2, 3-5, 6-8 both in rows and columns.

Naman
  • 27,789
  • 26
  • 218
  • 353
0

Simply spoken, isValid() checks those conditions that allow putting another value into a new position.

For example: it has a look into all the rows above/below; columns left/right and checks that the provided value isn't already there.

In other words: there are various conditions that need to be meet before "adding" a new number, and this method simply checks that board with that new value is still legit.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    I understand that, but I don't get this multiplaying and division ... What does it do, line by line ? : ) – Seinfeld Jan 16 '17 at 18:10