2

I am trying to write a program that will use backtracking to create a Sudoku solver. I have been able to create a black Sudoku grid and I can check to see if a move is a valid move. My program works fine until there are more than one choice of numbers for a square.

Problem: Will you look at my Solve method and see how I could modify it to backtrack, change the answer and move forward again. I gave the names of all of my other methods above and every one of those work.

Example input:

int board[ROWS][COLS] = {
    { 6, 0, 3, 0, 2, 0, 0, 9, 0 },
    { 0, 0, 0, 0, 5, 0, 0, 8, 0 },
    { 0, 2, 0, 4, 0, 7, 0, 0, 1 },
    { 0, 0, 6, 0, 1, 4, 3, 0, 0 },
    { 0, 0, 0, 0, 8, 0, 0, 5, 6 },
    { 0, 4, 0, 6, 0, 3, 2, 0, 0 },
    { 8, 0, 0, 2, 0, 0, 0, 0, 7 },
    { 0, 1, 0, 0, 7, 5, 8, 0, 0 },
    { 0, 3, 0, 0, 0, 6, 1, 0, 5 }
};

bool sudokuBoard::emptyCell(int i, int j);

bool sudokuBoard::isValidCol(int i, int j, int number);

bool sudokuBoard::isValidRow(int i, int j, int number);

bool sudokuBoard::isValidSquare(int i, int j, int number);

bool sudokuBoard::validMove(int i, int j, int number);

void sudokuBoard::solvePuzzle(int row, int col) {

    for (int i = 1; i < 10; i++) {
        if (validMove(row, col, i)) {
            board[row][col] = i;
            showBoard();
        } 
    }
    if (row < 8 && col < 8) {
        if (col < 8) {
            solvePuzzle(row, col + 1);
        }
        else {
            col = 0;
            solvePuzzle(row + 1, col);
        }
    }
}

Example current output:

  6  5  3|  1  2  8|  4  9  0|
  0  0  0|  0  5  0|  0  8  0|
  0  2  0|  4  0  7|  0  0  1|
--------------------------------
  0  0  6|  0  1  4|  3  0  0|
  0  0  0|  0  8  0|  0  5  6|
  0  4  0|  6  0  3|  2  0  0|
--------------------------------
  8  0  0|  2  0  0|  0  0  7|
  0  1  0|  0  7  5|  8  0  0|
  0  3  0|  0  0  6|  1  0  5|

my program stops at the last 0 of the first row since there is no solution unless that previous 4 changes to a 7, the program terminates.

Asuu
  • 121
  • 1
  • 11
  • It looks like you are missing the backtracking part of the recursive backtracking. – M Y Mar 15 '17 at 14:14
  • Yea i figured that much out lol, just not sure exactly how it works or how to implement – Asuu Mar 15 '17 at 17:12
  • 1
    Try putting a solvePuzzle call inside your first loop after showboard – M Y Mar 15 '17 at 17:30
  • I tried to do this but it did not work. I think my problem lies with doing the row+1 and col+1 in my if statement, everything I have seen that uses backtracking does not increment their rows and columns, I think they just look for an open position but I just don't understand how this works once you place a number. The number 9 in row 0 is there before I ran the program but if I just subtract 1 then I will be changing that number instead of the 4 which is needed to be changed to a 7 and the 4 should be on the end. – Asuu Mar 16 '17 at 00:41

2 Answers2

4

Backtracking can be hard to wrap your mind around the first time so we will take this step by step starting with some pseudocode of about what you have now :

    while(puzzlenotsolved)
   {
    foreach row   
      {
         findEmptySquare
         {
         findValidMove(1-9)
         }
      }
   }

This of course gets stuck once no valid move can be found for a square because of a previously chosen value.

To counter this we need to return false when we run out of valid moves in a square, we also need to unassign our guess to make the square empty again. We then need to resume looping in the previous square where we left off.

So our find valid move function (Solve puzzle in your case) could look something like this :

bool findValidMove
{
  if(noEmptySquare) {return true;}  //important bit

  findEmptySquare()
  for (1-9) 
       { if (isvalidMove )
            {
                assignMoveToSquare
            }
            if (findValidMove) {return true}  //important bit

         unassignMoveFromSquare   
       }
    return false; //no values valid in this square, a previous square has a wrong value
}

Now this is considered a brute force approach, and can be optimized, but for your question lets get backtracking working and you can worry about speed optimizations later if you wish.

Note the two places I commented as important bits, the first is a signifier that there are no empty squares left. Since your program only assigns valid moves the puzzle should be complete and correct here, so the program returns true. This is the base case, In general recursive functions need a base case.

The second important bit is where the function recursively calls itself. Take note that it is still within the loop, so when a call returns false, it will resume looping in a previous call. Each call stacks onto the other like in this example except our example returns back into a loop.

Notice that the cell does not get unassigned until after the recursive function returns, this allows you to not worry about adding 1 to your rows and columns as you mentioned in your comment. All you have to do is have a reliable findEmptySquare method and recursion takes care of the rest.

Your showBoard(); method will be invaluable for debugging, i'd say put it right after assignMoveToSquare

Hopefully this helps, you are really close so I think it will. If you have further questions feel free to comment on this and I'll try to get to you when I have time.

M Y
  • 1,831
  • 4
  • 24
  • 52
0

This is what solved it for me. Thank you for all your help.

bool sudokuBoard::solvePuzzle() {
    int row, col;

    if (emptyCell(row, col) == false) {
        return true; 
    }

    for (int i = 1; i < 10; i++) {
        cout << "Trying " << i << " in spot [" << row << "][" << col << "]" << endl;
        if (validMove(row, col, i)) {
            board[row][col] = i;
            showBoard();
            if (solvePuzzle()) {
                return true;
            }
            board[row][col] = 0;
        }
    }
    return false;
}
Asuu
  • 121
  • 1
  • 11