Skip to content

Update solver.py #35

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
173 changes: 113 additions & 60 deletions Sudoku Solver/solver.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,131 @@
b = [
[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(b):
find = find_empty(b) # Check empty box
if not find:
return True # Final state of the board when every box is filled
else:
row, col = find
import typing

def print_board(board: list[list[int]]) -> None:
"""
Prints the Sudoku board in a formatted way.

Args:
board (list[list[int]]): The 9x9 Sudoku board.
"""
for i in range(len(board)):
# Print horizontal separator after every 3 rows (except the first)
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ")

for j in range(len(board[0])):
# Print vertical separator after every 3 columns (except the last)
if j % 3 == 0 and j != 0:
print(" | ", end="")

# Print the number, followed by a space, unless it's the last column
if j == 8:
print(board[i][j])
else:
print(str(board[i][j]) + " ", end="")


def find_empty(board: list[list[int]]) -> typing.Optional[tuple[int, int]]:
"""
Finds the next empty (0) cell on the Sudoku board.

Args:
board (list[list[int]]): The 9x9 Sudoku board.

for i in range(1,10):
if valid(b, i, (row, col)):
b[row][col] = i # Place the number in the board if its valid
Returns:
tuple[int, int]: A tuple (row, col) of the empty cell, or None if no empty cell is found.
"""
for r in range(len(board)):
for c in range(len(board[0])):
if board[r][c] == 0: # Check if the current cell contains a 0 (empty)
return (r, c) # Return the row and column of the empty cell
return None # No empty cells found, board is full

if solve(b):
return True # Continue from that board state onwards

b[row][col] = 0

return False
def valid(board: list[list[int]], num: int, pos: tuple[int, int]) -> bool:
"""
Checks if placing a number 'num' at 'pos' (row, col) is valid according to Sudoku rules.

def valid(b, num, pos):

for i in range(len(b[0])): # Check row
if b[pos[0]][i] == num and pos[1] != i: # Check element in row if its equal to the number added and if its the current position being added to then ignore it
Args:
board (list[list[int]]): The 9x9 Sudoku board.
num (int): The number (1-9) to check for validity.
pos (tuple[int, int]): The position (row, col) on the board where 'num' is being considered.

Returns:
bool: True if the number is valid at the given position, False otherwise.
"""
row, col = pos

# Check row: Iterate through all columns in the current row
for c in range(len(board[0])):
# If the number 'num' is found in the row and it's not the position we are checking
if board[row][c] == num and col != c:
return False


for i in range(len(b)): # Check column
if b[i][pos[1]] == num and pos[0] != i: # Check element column-wise if it equals the number added and its not the position that the new number was just added into
# Check column: Iterate through all rows in the current column
for r in range(len(board)):
# If the number 'num' is found in the column and it's not the position we are checking
if board[r][col] == num and row != r:
return False

box_x = pos[1] // 3 # Check 3x3 box
box_y = pos[0] // 3
# Check 3x3 box: Determine the top-left corner of the 3x3 box
box_x = col // 3 # Integer division to get the box's column index (0, 1, or 2)
box_y = row // 3 # Integer division to get the box's row index (0, 1, or 2)

for i in range(box_y*3, box_y*3 + 3): # Loop through the 3x3 boxes
for j in range(box_x * 3, box_x*3 + 3):
if b[i][j] == num and (i,j) != pos: # Check if same number exits in the 3x3 box and (i, j) was the position the new number was just added to
# Iterate through cells within the determined 3x3 box
for r_box in range(box_y * 3, box_y * 3 + 3):
for c_box in range(box_x * 3, box_x * 3 + 3):
# If the number 'num' is found in the box and it's not the position we are checking
if board[r_box][c_box] == num and (r_box, c_box) != pos:
return False

return True
return True # If no conflicts are found, the number is valid

def print_board(b):
for i in range(len(b)):
if i % 3 == 0 and i != 0:
print("- - - - - - - - - - - - - ") # Separate sections of the board row-wise (Every 3x3 box)

for j in range(len(b[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="") # Separate sections of the board column-wise
def solve(board: list[list[int]]) -> bool:
"""
Solves the Sudoku board using a backtracking algorithm.

if j == 8:
print(b[i][j])
else:
print(str(b[i][j]) + " ", end="")
This function attempts to fill empty cells (represented by 0) with valid numbers
(1-9). If a number leads to a solution, it returns True. If not, it backtracks
and tries another number.

Args:
board (list[list[int]]): The 9x9 Sudoku board to be solved.
This board will be modified in-place.

Returns:
bool: True if the board is successfully solved, False otherwise (no solution exists).
"""
find = find_empty(board) # Find the next empty cell (row, col)

# Base case: If no empty cell is found, the board is solved
if not find:
return True
else:
row, col = find # Unpack the row and column of the empty cell

# Try numbers from 1 to 9 in the current empty cell
for num_to_try in range(1, 10):
if valid(board, num_to_try, (row, col)): # Check if the number is valid at this position
board[row][col] = num_to_try # If valid, place the number on the board

# Recursively call solve for the updated board
if solve(board):
return True # If the recursive call finds a solution, propagate True

# Backtrack: If the current number doesn't lead to a solution, reset the cell to 0
board[row][col] = 0

def find_empty(b):
for i in range(len(b)):
for j in range(len(b[0])):
if b[i][j] == 0: # Check if there is a 0 in each position of the box
return (i, j) # Return the row and column
return False # No number from 1-9 worked for the current empty cell, so backtrack further

return None

print_board(b)
print(" ")
solve(b)
print_board(b)
if __name__ == "__main__":
# Example Sudoku board
initial_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,