Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9must occur exactly once in each row. - Each of the digits
1-9must occur exactly once in each column. - Each of the digits
1-9must occur exactly once in each of the 93x3sub-boxes of the grid.
The '.' character indicates empty cells.
solution
Trying to convert the solution from 36-valid-sudoku into this solution is a little bit of a trap. We want to find something more efficient than checking the entire puzzle at each iteration when we’re backtracking.
Instead, we want to keep sets to store what unique values are in each row, column, and square. Then, keeping track of all the slots that we still need to fill, we try to fill the next one with a valid value at each backtracking step.
from collections import defaultdict, deque
def solveSudoku(self, board: List[List[str]]) -> None:
sets = defaultdict(set)
empty = deque()
# Initialize sets for rows, columns, and 3x3 blocks
for i in range(9):
for j in range(9):
if board[i][j] != ".":
num = board[i][j]
sets[f"r{i}"].add(num) # Row set
sets[f"c{j}"].add(num) # Column set
sets[f"sq{i//3}{j//3}"].add(num) # 3x3 block set
else:
empty.append((i, j))
# Define backtrack function to recursively solve Sudoku
def backtrack():
if not empty: # Check if there are no more empty cells to fill
return True
x, y = empty[0]
# Try placing each number from '1' to '9' in the empty cell
for num in {'1', '2', '3', '4', '5', '6', '7', '8', '9'}:
if (
num not in sets[f"r{x}"]
and num not in sets[f"c{y}"]
and num not in sets[f"sq{x//3}{y//3}"]
):
# Place the number and update sets
board[x][y] = num
sets[f"r{x}"].add(num)
sets[f"c{y}"].add(num)
sets[f"sq{x//3}{y//3}"].add(num)
empty.popleft()
# Recursively attempt to solve Sudoku
if backtrack():
return True
else:
# Backtrack if placing num does not lead to a solution
board[x][y] = "."
sets[f"r{x}"].remove(num)
sets[f"c{y}"].remove(num)
sets[f"sq{x//3}{y//3}"].remove(num)
empty.appendleft((x, y))
return False
# Start solving Sudoku from the first empty cell
backtrack()