From 3e6bd1a2f81706540777242fb648d549cd1d1c45 Mon Sep 17 00:00:00 2001 From: adith Date: Tue, 13 Aug 2019 13:48:41 +0530 Subject: [PATCH 1/5] Added sudoku solver in backtracking --- backtracking/sudoku.py | 127 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 backtracking/sudoku.py diff --git a/backtracking/sudoku.py b/backtracking/sudoku.py new file mode 100644 index 000000000000..47d32b5e8f47 --- /dev/null +++ b/backtracking/sudoku.py @@ -0,0 +1,127 @@ + +''' + + Given a partially filled 9×9 2D array, the objective is to fill a 9×9 + square grid with digits numbered 1 to 9, so that every row, column, and + and each of the nine 3×3 sub-grids contains all of the digits. + + This can be solved using Backtracking and is similar to n-queens. + We check to see if a cell is safe or not and recursively call the + function on the next column to see if it returns True. if yes, we + have solved the puzzle. else, we backtrack and place another number + in that cell and repeat this process. + +''' + +def is_safe(grid, row, column, n): + ''' + This function checks the grid to see if each row, + column, and the 3x3 subgrids contain the digit 'n'. + It returns False if it is not 'safe' (a duplicate digit + is found) else returns True if it is 'safe' + + ''' + + for i in range(9): + if(grid[row][i] == n): + return False + + for i in range(9): + if(grid[i][column] == n): + return False + + for i in range(3): + for j in range(3): + if(grid[(row - row%3) + i][(column - column%3) + j] == n): + return False + + return True + + +def is_completed(grid): + ''' + This function checks if the puzzle is completed or not. + it is completed when all the cells are assigned with a number(not zero) + and There is no repeating number in any column, row or 3x3 subgrid. + + ''' + + for i in range(9): + for j in range(9): + if(grid[i][j] == 0): + return False + + return True + + +def find_empty_location(grid): + ''' + This function finds an empty location so that we can assign a number + for that particular row and column. + + ''' + + for i in range(9): + for j in range(9): + if(grid[i][j] == 0): + return i, j + + +def sudoku(grid): + ''' + Takes a partially filled-in grid and attempts to assign values to + all unassigned locations in such a way to meet the requirements + for Sudoku solution (non-duplication across rows, columns, and boxes) + + ''' + + if(is_completed(grid)): + return True + + row, column = find_empty_location(grid) + + for digit in range(1, 10): + if(is_safe(grid, row, column, digit)): + grid[row][column] = digit + + if(sudoku(grid)): + return True + + grid[row][column] = 0 + + return False + + +def print_solution(grid): + ''' + A function to print the solution in the form + of a 9x9 grid + + ''' + + for i in range(9): + for j in range(9): + print(grid[i][j], end = ' ') + print() + + +if __name__ == '__main__': + # assigning initial values to the grid + 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]] + + if(sudoku(grid)): + print_solution(grid) + else: + print('Cannot find a solution') + + + + From 228ddb627f4aea78119ee08217ccc40f82d8f2fa Mon Sep 17 00:00:00 2001 From: adith Date: Tue, 13 Aug 2019 18:34:49 +0530 Subject: [PATCH 2/5] Added sudoku solver program --- backtracking/sudoku.py | 61 +++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/backtracking/sudoku.py b/backtracking/sudoku.py index 47d32b5e8f47..d16921716b72 100644 --- a/backtracking/sudoku.py +++ b/backtracking/sudoku.py @@ -13,6 +13,17 @@ ''' +# assigning initial values to the grid +initial_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]] + def is_safe(grid, row, column, n): ''' This function checks the grid to see if each row, @@ -23,16 +34,16 @@ def is_safe(grid, row, column, n): ''' for i in range(9): - if(grid[row][i] == n): + if grid[row][i] == n: return False for i in range(9): - if(grid[i][column] == n): + if grid[i][column] == n: return False for i in range(3): for j in range(3): - if(grid[(row - row%3) + i][(column - column%3) + j] == n): + if grid[(row - row%3) + i][(column - column%3) + j] == n: return False return True @@ -45,10 +56,10 @@ def is_completed(grid): and There is no repeating number in any column, row or 3x3 subgrid. ''' - - for i in range(9): - for j in range(9): - if(grid[i][j] == 0): + + for row in grid: + for cell in row: + if cell == 0: return False return True @@ -63,7 +74,7 @@ def find_empty_location(grid): for i in range(9): for j in range(9): - if(grid[i][j] == 0): + if grid[i][j] == 0: return i, j @@ -75,17 +86,17 @@ def sudoku(grid): ''' - if(is_completed(grid)): + if is_completed(grid): return True row, column = find_empty_location(grid) for digit in range(1, 10): - if(is_safe(grid, row, column, digit)): + if is_safe(grid, row, column, digit): grid[row][column] = digit - if(sudoku(grid)): - return True + if sudoku(grid): + return grid grid[row][column] = 0 @@ -99,26 +110,20 @@ def print_solution(grid): ''' - for i in range(9): - for j in range(9): - print(grid[i][j], end = ' ') + for row in grid: + for cell in row: + print(cell, end = ' ') print() if __name__ == '__main__': - # assigning initial values to the grid - 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]] - - if(sudoku(grid)): - print_solution(grid) + + # make a copy of grid so that you can compare with the unmodified grid + grid1 = list(map(list, initial_grid)) + ans = sudoku(grid1) + if ans: + print('grid after solving:\n') + print_solution(ans) else: print('Cannot find a solution') From de80d0c3976bd98d9dc9389ca8d509c16422978c Mon Sep 17 00:00:00 2001 From: adith Date: Tue, 13 Aug 2019 18:43:22 +0530 Subject: [PATCH 3/5] Added sudoku solver --- backtracking/sudoku.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/backtracking/sudoku.py b/backtracking/sudoku.py index d16921716b72..3f88212342c6 100644 --- a/backtracking/sudoku.py +++ b/backtracking/sudoku.py @@ -23,6 +23,16 @@ [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]] +# a grid with no solution +no_solution = [[5,0,6,5,0,8,4,0,3], + [5,2,0,0,0,0,0,0,2], + [1,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]] def is_safe(grid, row, column, n): ''' @@ -120,10 +130,12 @@ def print_solution(grid): # make a copy of grid so that you can compare with the unmodified grid grid1 = list(map(list, initial_grid)) - ans = sudoku(grid1) - if ans: + grid2 = list(map(list, no_solution)) + ans1 = sudoku(grid1) + ans2 = sudoku(grid2) + if ans1: print('grid after solving:\n') - print_solution(ans) + print_solution(ans1) else: print('Cannot find a solution') From aced37a8407fdc2ae13aea725aef96ae4120f6b5 Mon Sep 17 00:00:00 2001 From: adith Date: Tue, 13 Aug 2019 18:57:43 +0530 Subject: [PATCH 4/5] Added sudoku solver --- backtracking/sudoku.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtracking/sudoku.py b/backtracking/sudoku.py index 3f88212342c6..6a4b6674843b 100644 --- a/backtracking/sudoku.py +++ b/backtracking/sudoku.py @@ -97,7 +97,7 @@ def sudoku(grid): ''' if is_completed(grid): - return True + return grid row, column = find_empty_location(grid) From 466d7b887cbccbcec9140ede02302ac8214095ad Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 13 Aug 2019 15:50:34 +0200 Subject: [PATCH 5/5] Format with black, add doctests, cleanup main --- backtracking/sudoku.py | 245 +++++++++++++++++++++-------------------- 1 file changed, 126 insertions(+), 119 deletions(-) diff --git a/backtracking/sudoku.py b/backtracking/sudoku.py index 6a4b6674843b..b33351fd4911 100644 --- a/backtracking/sudoku.py +++ b/backtracking/sudoku.py @@ -1,144 +1,151 @@ - -''' - - Given a partially filled 9×9 2D array, the objective is to fill a 9×9 - square grid with digits numbered 1 to 9, so that every row, column, and - and each of the nine 3×3 sub-grids contains all of the digits. - - This can be solved using Backtracking and is similar to n-queens. - We check to see if a cell is safe or not and recursively call the - function on the next column to see if it returns True. if yes, we - have solved the puzzle. else, we backtrack and place another number - in that cell and repeat this process. - -''' - -# assigning initial values to the grid -initial_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]] +""" + + Given a partially filled 9×9 2D array, the objective is to fill a 9×9 + square grid with digits numbered 1 to 9, so that every row, column, and + and each of the nine 3×3 sub-grids contains all of the digits. + + This can be solved using Backtracking and is similar to n-queens. + We check to see if a cell is safe or not and recursively call the + function on the next column to see if it returns True. if yes, we + have solved the puzzle. else, we backtrack and place another number + in that cell and repeat this process. + +""" + +# assigning initial values to the grid +initial_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], +] # a grid with no solution -no_solution = [[5,0,6,5,0,8,4,0,3], - [5,2,0,0,0,0,0,0,2], - [1,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]] +no_solution = [ + [5, 0, 6, 5, 0, 8, 4, 0, 3], + [5, 2, 0, 0, 0, 0, 0, 0, 2], + [1, 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], +] + def is_safe(grid, row, column, n): - ''' - This function checks the grid to see if each row, - column, and the 3x3 subgrids contain the digit 'n'. - It returns False if it is not 'safe' (a duplicate digit - is found) else returns True if it is 'safe' - - ''' - - for i in range(9): - if grid[row][i] == n: - return False - - for i in range(9): - if grid[i][column] == n: - return False - - for i in range(3): - for j in range(3): - if grid[(row - row%3) + i][(column - column%3) + j] == n: - return False - - return True + """ + This function checks the grid to see if each row, + column, and the 3x3 subgrids contain the digit 'n'. + It returns False if it is not 'safe' (a duplicate digit + is found) else returns True if it is 'safe' + + """ + + for i in range(9): + if grid[row][i] == n or grid[i][column] == n: + return False + + for i in range(3): + for j in range(3): + if grid[(row - row % 3) + i][(column - column % 3) + j] == n: + return False + + return True def is_completed(grid): - ''' - This function checks if the puzzle is completed or not. - it is completed when all the cells are assigned with a number(not zero) - and There is no repeating number in any column, row or 3x3 subgrid. - - ''' + """ + This function checks if the puzzle is completed or not. + it is completed when all the cells are assigned with a number(not zero) + and There is no repeating number in any column, row or 3x3 subgrid. + + """ - for row in grid: - for cell in row: - if cell == 0: - return False + for row in grid: + for cell in row: + if cell == 0: + return False + + return True - return True - def find_empty_location(grid): - ''' - This function finds an empty location so that we can assign a number - for that particular row and column. + """ + This function finds an empty location so that we can assign a number + for that particular row and column. - ''' + """ - for i in range(9): - for j in range(9): - if grid[i][j] == 0: - return i, j + for i in range(9): + for j in range(9): + if grid[i][j] == 0: + return i, j def sudoku(grid): - ''' - Takes a partially filled-in grid and attempts to assign values to - all unassigned locations in such a way to meet the requirements - for Sudoku solution (non-duplication across rows, columns, and boxes) - - ''' - - if is_completed(grid): - return grid - - row, column = find_empty_location(grid) - - for digit in range(1, 10): - if is_safe(grid, row, column, digit): - grid[row][column] = digit - - if sudoku(grid): - return grid - - grid[row][column] = 0 - - return False + """ + Takes a partially filled-in grid and attempts to assign values to + all unassigned locations in such a way to meet the requirements + for Sudoku solution (non-duplication across rows, columns, and boxes) + >>> sudoku(initial_grid) # doctest: +NORMALIZE_WHITESPACE + [[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]] + >>> sudoku(no_solution) + False + """ -def print_solution(grid): - ''' - A function to print the solution in the form - of a 9x9 grid + if is_completed(grid): + return grid + + row, column = find_empty_location(grid) + + for digit in range(1, 10): + if is_safe(grid, row, column, digit): + grid[row][column] = digit - ''' + if sudoku(grid): + return grid - for row in grid: - for cell in row: - print(cell, end = ' ') - print() + grid[row][column] = 0 + return False + + +def print_solution(grid): + """ + A function to print the solution in the form + of a 9x9 grid -if __name__ == '__main__': + """ - # make a copy of grid so that you can compare with the unmodified grid - grid1 = list(map(list, initial_grid)) - grid2 = list(map(list, no_solution)) - ans1 = sudoku(grid1) - ans2 = sudoku(grid2) - if ans1: - print('grid after solving:\n') - print_solution(ans1) - else: - print('Cannot find a solution') + for row in grid: + for cell in row: + print(cell, end=" ") + print() - +if __name__ == "__main__": + # make a copy of grid so that you can compare with the unmodified grid + for grid in (initial_grid, no_solution): + grid = list(map(list, grid)) + solution = sudoku(grid) + if solution: + print("grid after solving:") + print_solution(solution) + else: + print("Cannot find a solution.")