Skip to content

Check initial grid availability for backtracking/sudoku.py #3849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 72 additions & 25 deletions backtracking/sudoku.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
in that cell and repeat this process.
"""
# assigning initial values to the grid
small_grid = [[0, 1], [1, 0]]


initial_grid = [
[3, 0, 6, 5, 0, 8, 4, 0, 0],
[5, 2, 0, 0, 0, 0, 0, 0, 0],
Expand All @@ -26,6 +29,18 @@
[0, 0, 5, 2, 0, 6, 3, 0, 0],
]

initial_not_solvable_grid = [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[3, 0, 0, 0, 0, 0, 0, 0, 0],
[3, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
]

# a grid with no solution
no_solution = [
[5, 0, 6, 5, 0, 8, 4, 0, 3],
Expand All @@ -45,15 +60,27 @@ def is_safe(grid: Matrix, row: int, column: int, n: int) -> bool:
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'
is found) else returns True if it is 'safe' or 0.
"""
if n == 0:
return True

elif n < 0 or n > 9 or (not isinstance(n, int)):
return False

for i in range(9):
if grid[row][i] == n or grid[i][column] == n:
if (grid[row][i] == n and i != column) or (grid[i][column] == n and i != row):
return False

for i in range(3):
for j in range(3):
if grid[(row - row % 3) + i][(column - column % 3) + j] == n:
new_row = (row - row % 3) + i
new_column = (column - column % 3) + j
if (
new_row != row
and new_column != column
and grid[new_row][new_column] == n
):
return False

return True
Expand Down Expand Up @@ -91,24 +118,29 @@ def find_empty_location(grid: Matrix) -> Tuple[int, int]:
return i, j


def sudoku(grid: Matrix) -> Union[Matrix, bool]:
def check_original_solvable(grid: Matrix) -> bool:
"""
This function checks whether the original grid provided is solvable.

>>> check_original_solvable(initial_not_solvable_grid)
False
>>> check_original_solvable(no_solution)
False
"""
for original_row in range(9):
for origin_col in range(9):
origin_digit = grid[original_row][origin_col]
if origin_digit:
if not is_safe(grid, original_row, origin_col, origin_digit):
return False
return True


def sudoku_solve(grid: Matrix) -> Union[Matrix, bool]:
"""
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
"""

if is_completed(grid):
Expand All @@ -120,29 +152,44 @@ def sudoku(grid: Matrix) -> Union[Matrix, bool]:
if is_safe(grid, row, column, digit):
grid[row][column] = digit

if sudoku(grid):
if sudoku_solve(grid):
return grid

grid[row][column] = 0

return False


def print_solution(grid: Matrix) -> None:
def print_solution(grid: Union[Matrix, bool]) -> None:
"""
A function to print the solution in the form
of a 9x9 grid
"""
for row in grid:
for cell in row:
print(cell, end=" ")
print()
if grid:
for row in grid:
for cell in row:
print(cell, end=" ")
print()


def sudoku(grid: Matrix) -> Union[Matrix, bool]:
"""
Find the solution of a sudoku.
"""

if not check_original_solvable(grid):
return False
return sudoku_solve(grid)


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))
for grid in (
initial_grid,
no_solution,
initial_not_solvable_grid,
):
grid = [list(col) for col in grid]
solution = sudoku(grid)
if solution:
print("grid after solving:")
Expand Down