why is this recursive sudoku code not working? - python

im learning python, I wanted the sudoku numbers to be read from a csv file and to be reconstructed. that part works. but it does not solve the sudoku. it just prints the same input again.
Can somebody please help me? Any idea why?
Question number 2: Any Tipps how i could modify this code to give the number of possible sudoku solutions? In case, there are multiple solutions possible.
Thank you so much in Advanced! :)
import csv
with open('sudoko.csv') as f:
board = list(csv.reader(f,delimiter=';'))
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for num in range(1,10):
if valid(bo, num, (row, col)):
bo[row][col] = num
if solve(bo):
return True
bo[row][col] = 0
return False
def valid(bo, num, pos):
# Check row
for field in range(len(bo[0])):
if bo[pos[0]][field] == num and pos[1] != field:
return False
# Check column
for line in range(len(bo)):
if bo[line][pos[1]] == num and pos[0] != line:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y*3, box_y*3 + 3):
for j in range(box_x * 3, box_x*3 + 3):
if bo[i][j] == num and (i,j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range(len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) # row, col
return None
if __name__ == "__main__":
print_board(board)
solve(board)
print("___________________")
print("")
print_board(board)

Related

N Queen code (python) only working for n as 1 or 5. Doesnt return anything for anything else

So I tried coding a program to solve NQueen problem in python. It is only outputing correct response for n as 1 or 5. It doesn't throw an error or anything for the rest of numbers.
Here is the code:
import numpy as np
def isSafe(arr, row, col, n):
for ind in range(row):
if(arr[ind][col] == 1):
return False
x = row
y = col
while x >= 0 and y >= 0:
if arr[x][y] == 1:
return False
x -= 1
y -= 1
x = row
y = col
while x >= 0 and y < n:
if arr[x][y] == 1:
return False
x -= 1
y += 1
return True
def nQueen(arr, row, n):
if row >= n:
return True
for col in range(n):
if isSafe(arr,row,col,n) == True:
arr[row][col] = 1
if nQueen(arr, row+1, n) == True:
return True
return False
def main():
n = int(input("Enter the size of board: "))
arr = np.zeros((n,n)).astype(int)
if nQueen(arr, 0, n):
for x in range(n):
for y in range(n):
print(arr[x][y], end='\t')
print("\n")
else:
print("No Solution: ")
if __name__ == '__main__':
main()\
Using Lists:
import numpy as np
def isSafe(arr, row, col, n):
for ind in range(row):
if(arr[ind][col] == 1):
return False
x = row
y = col
while x >= 0 and y >= 0:
if arr[x][y] == 1:
return False
x -= 1
y -= 1
x = row
y = col
while x >= 0 and y < n:
if arr[x][y] == 1:
return False
x -= 1
y += 1
return True
def nQueen(arr, row, n):
if row >= n:
return True
for col in range(n):
if isSafe(arr,row,col,n) == True:
arr[row][col] = 1
if nQueen(arr, row+1, n) == True:
return True
return False
def main():
n = int(input("Enter the size of board: "))
arr = [[0]*n]*n
if nQueen(arr, 0, n):
for x in range(n):
for y in range(n):
print(arr[x][y], end='\t')
print("\n")
else:
print("No Solution: ")
if __name__ == '__main__':
main()
I tried using every single integer from 0 to 20 but only 1 and 5 seemed to output something while any other number just outputted "No Solution".
Also, The lists one doesnt even output an answer for 5, just 1
When you determine that an assignment arr[row][col] is not safe, you never reset it for future tests.
def nQueen(arr, row, n):
if row >= n:
return True
for col in range(n):
if isSafe(arr,row,col,n) == True:
arr[row][col] = 1 # Put a queen here
if nQueen(arr, row+1, n) == True:
return True
arr[row][col] = 0 # Take it back; it didn't work here
return False

how to fix 'ValueError: math domain error' in Python

def distinctIntegers(n):
board = [n]
lenBoard = 0
while lenBoard != len(board):
lenBoard = len(board)
for num in board:
temp = num - 1
for i in range(2, int(math.sqrt(temp)) + 1):
if temp % i == 0:
if i not in board:
board.append(i)
if temp / i not in board:
board.append(temp / i)
return len(board)
it's fine for now.
i wanted put that (if temp not in board : board.append(temp)) in first for loop. 'ValueError: math domain error in Python' occured after putting that .
def distinctIntegers(n):
board = [n]
lenBoard = 0
while lenBoard != len(board):
lenBoard = len(board)
for num in board:
temp = num - 1
if temp not in board:
board.append(temp)
for i in range(2, int(math.sqrt(temp)) + 1):
if temp % i == 0:
if i not in board:
board.append(i)
if temp / i not in board:
board.append(temp / i)
return len(board)
this and
def distinctIntegers(n):
board = [n]
lenBoard = 0
while lenBoard != len(board):
lenBoard = len(board)
for num in board:
temp = num - 1
for i in range(2, int(math.sqrt(temp)) + 1):
if temp % i == 0:
if i not in board:
board.append(i)
if temp / i not in board:
board.append(temp / i)
if temp not in board:
board.append(temp)
return len(board)
this, both of them didn't work
i changed the location and put 'num - 1' instead of temp..
but still doesn't works. I dont know why..

Sudoku Solver Python backtracking input

For school, we should program a sudoku solver and I just followed a tutorial to program one and it works:
board = [
[7,8,0,4,0,0,1,2,0],
[6,0,0,0,7,5,0,0,9],
[0,0,0,6,0,1,0,7,8],
[0,0,7,0,4,0,2,6,0],
[0,0,1,0,5,0,9,3,0],
[9,0,4,0,6,0,0,0,5],
[0,7,0,3,0,0,0,1,2],
[1,2,0,0,0,7,4,0,0],
[0,4,9,2,0,6,0,0,7]
]
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for i in range(1,10):
if valid(bo, i, (row, col)):
bo[row][col] = i
if solve(bo):
return True
bo[row][col] = 0
return False
def valid(bo, num, pos):
# Check row
for i in range(len(bo[0])):
if bo[pos[0]][i] == num and pos[1] != i:
return False
# Check column
for i in range(len(bo)):
if bo[i][pos[1]] == num and pos[0] != i:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y*3, box_y*3 + 3):
for j in range(box_x * 3, box_x*3 + 3):
if bo[i][j] == num and (i,j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range(len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) # row, col
return None
print_board(board)
solve(board)
print("___________________")
print_board(board)
But my problem is we have to handle strings like:
003020600
900305000
001806400
008102900
700000008
006708200
002609500
800203009
005010300
and couldn't separate them with a comma. Do you have an idea how to fix the problem?
You can transform a multiline string to a 2d-list of integers like:
s = """003020600
900305000
001806400
008102900
700000008
006708200
002609500
800203009
005010300"""
board = [[*map(int, line)] for line in s.splitlines()]
Or, if you are reading these lines as input from stdin:
board = []
for _ in range(9):
board.append([*map(int, input())])

Recursive Sudoku solver not solving anything

I was working on a Sudoku solver, and when I ran it, it just didn't work- the function f returned a none type. After debugging, I found out the code didn't solve some of the squares. I don't know why this happened, but I suspect the loop checking all the numbers possible in a square stops after finding one possible number and doesn't check the rest too. Can you please pinpoint me the problem in my code? Thanks.
Note: for empty spaces in the Sudoku, enter 0.
# enter the Sudoku as a two-dimensional array (a[i][j])
def square_check(array, loc_x, loc_y, val):
added_x = loc_x - (loc_x % 3)
added_y = loc_y - (loc_y % 3)
for i in range(3):
for j in range(3):
if i+added_y != loc_y or j+added_x != loc_x:
if array[i+added_y][j+added_x] == val:
return False
return True
def line_check(array, loc_x, loc_y, val):
for i in range(9):
if i != loc_x:
if array[loc_y][i] == val:
return False
return True
def col_check(array, loc_x, loc_y, val):
for i in range(9):
if i != loc_y:
if array[i][loc_x] == val:
return False
return True
def f(array):
flag = True
mark = True
for i in range(0, 9):
for j in range(0, 9):
if array[i][j] == 0:
flag = False
if flag:
return array
for i in range(0, 9):
for j in range(0, 9):
if array[i][j] == 0:
for num in range(1, 10):
if square_check(array, j, i, num):
if col_check(array, j, i, num):
if line_check(array, j, i, num):
new_array = array.copy()
new_array[i][j] = num
mark = False
f(new_array)
if mark:
break
def to_str(array):
for i in range(len(array)):
print(array[i])
print("")
to_str(f(sudoku))

Can someone help explain the recursion in this back tracking algorithm?

This is a program that solves a sudoku board using python and the back-tracking algorithm, but I don't seem to understand the recursion in solve(bo). Like it seems like if the condition is not met, then the index is reset to 0 and it continues to try numbers at the same position.
Can someone help explain in simpler terms perhaps, how the function back tracks and rechecks conditions?
board = [
[7,8,0,4,0,0,1,2,0],
[6,0,0,0,7,5,0,0,9],
[0,0,0,6,0,1,0,7,8],
[0,0,7,0,4,0,2,6,0],
[0,0,1,0,5,0,9,3,0],
[9,0,4,0,6,0,0,0,5],
[0,7,0,3,0,0,0,1,2],
[1,2,0,0,0,7,4,0,0],
[0,4,9,2,0,6,0,0,7]
]
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for i in range(1,10):
if valid(bo, i, (row, col)):
bo[row][col] = i
if solve(bo):
return True
bo[row][col] = 0
return False
def valid(bo, num, pos):
# Check row
for i in range(len(bo[0])):
if bo[pos[0]][i] == num and pos[1] != i:
return False
# Check column
for i in range(len(bo)):
if bo[i][pos[1]] == num and pos[0] != i:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y*3, box_y*3 + 3):
for j in range(box_x * 3, box_x*3 + 3):
if bo[i][j] == num and (i,j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range(len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) # row, col
return None
print_board(board)
solve(board)
print("___________________")
print_board(board)
Right! So the way this solution operates is it finds the next empty field on the board, attempts to insert number from range 1..9 there and then check the validity. The validity check is a tentative answer to whether a given number is correct, i.e. whether it does not produce a violation of the rules. If so, the number gets inserted into the array and solve is called recursively. Now, here the implicit backtracking is taking place. If this recursive call to solve fails to produce a fully consistent solution to the puzzle, then the whole "branch" starting with our tentative guess gets removed from the call stack, the failed guess is reset on the board (removed), and we continue to the next guess.

Categories

Resources