This is a working code that solves the sudoku:
def is_valid(board, row, col, num):
for i in range(9):
if board[row][i] == num:
return False
for i in range(9):
if board[i][col] == num:
return False
box_row = (row - row % 3)
box_col = (col - col % 3)
for i in range(3):
for j in range(3):
if board[box_row i][box_col j] == num:
return False
return True
def solve(board):
for row in range(9):
for col in range(9):
if board[row][col] == 0:
for num in range(1,10):
if is_valid(board, row, col, num):
board[row][col] = num
solve(board)
board[row][col] = 0
return False
print(np.matrix(board))
solve(board)
The part that confuses me is:
if board[row][col] == 0:
for num in range(1,10):
if is_valid(board, row, col, num):
board[row][col] = num
solve(board)
board[row][col] = 0
return False
how is this part working? I know it will assign the number, to the current row and col THEN, run the solve() function again, so, when will the program run this:
board[row][col] = 0
because as I understand it, the code won't run unless there's a 0 already. Then the program will check if the number is valid or not. also if there's no num [1~9] that is valid, won't it return false and quit the function?
talking about it makes my head spin, I know it's even hard to explain, I googled it.
Edit:
this is the board I'm dealing with:
board_1 = [
[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]
]
Output:
[[3 1 6 5 7 8 4 9 2]
[5 2 9 1 3 4 7 6 8]
[4 8 7 6 2 9 5 3 1]
[2 6 3 4 1 5 9 8 7]
[9 7 4 8 6 3 1 2 5]
[8 5 1 7 9 2 6 4 3]
[1 3 8 9 4 7 2 5 6]
[6 9 2 3 5 1 8 7 4]
[7 4 5 2 8 6 3 1 9]]
CodePudding user response:
Assuming that there is (at the time of writing) an indentation error in the code in the question, the solver looks like this:
def solve(board):
for row in range(9):
for col in range(9):
if board[row][col] == 0:
# ignore the code here for now
return False
print(np.matrix(board))
Ignore what the code that I've replaced with a comment does for the time being, what this function does is take a board, iterate through every square, and if any is 0, return False
, otherwise print the board.
That is, if board is already solved, print it, if it's not solved, return False.
The fact that False
is returned is irrelevant; it might as well just be return
.
So, for the code that was commented out. What that does is for each 0 that was found, try replacing it with each valid number, and recursively try and solve that.
if board[row][col] == 0:
for num in range(1,10):
if is_valid(board, row, col, num):
board[row][col] = num
solve(board)
board[row][col] = 0
So, if it was the only 0 on the board, then if it finds a valid number, the call to solve
will result in the board being printed out.
If there are no valid numbers, then one of the numbers inserted into the board at some point was incorrect; we don't recursively call solve
, and just proceed to return
.
So the recursive call to solve
may or may not have found a valid solution, the code isn't assuming only one solution exists and will continue looking in either case. It needs to undo what it has done, because it is only valid in the context of what previous recursive calls have chosen. Hence setting the square back to 0.
CodePudding user response:
There are two cases where the solve
function returns. I'll rewrite the code to make it sweeter (but yours works too)*:
def solve(board):
for row in range(9):
for col in range(9):
if board[row][col] == 0:
for num in range(1,10):
if is_valid(board, row, col, num):
board[row][col] = num
solve(board)
board[row][col] = 0
return False
return True
So, whenever the solve method reaches one of those return
statements, it returns to the method that called it. Note that there are a two if-statements outside the call to solve. These can evaluate to False
. And if they evaluate to False
often enough, one of the return
statements will be reached. That's how you get to board[row][col] = 0
If you want to see the solved Sudoku, you have to repeat print(np.matrix(board))
after the call to solve
at the very end too.
*Side notes:
- As you wrote it, the solve method can return either
None
orFalse
which is bad style becausebool(None)
evaluates toFalse
too. Why does it returnNone
? That's because noreturn
statement at the end of a function is equivalent toreturn None
. - You could also just use
return
unless you need theTrue
/False
later. That's becausesolve(board)
is not assigned to anything. - If the Sudoku doesn't have a solution, you'll enter a convoluted infinite loop that will only end once the maximum recursion depth is reached (in CPython).