|
| 1 | +""" |
| 2 | + Author : Mohit Kumar |
| 3 | +
|
| 4 | + 9*9 Sudoku Solver in python using Backtracking |
| 5 | + |
| 6 | + Given a partially filled 9×9 2D array, the objective is to fill a 9×9 |
| 7 | + square grid with digits numbered 1 to 9, so that every row, column, and |
| 8 | + and each of the nine 3×3 sub-grids contains all of the digits. |
| 9 | +
|
| 10 | + In This Solver we try filling digits one by one. Whenever we find that current |
| 11 | + digit cannot lead to a solution, we remove it (backtrack) and try next digit. |
| 12 | + This is better than naive approach (generating all possible combinations of digits |
| 13 | + and then trying every combination one by one as it drops a set of permutations |
| 14 | + whenever it backtracks. |
| 15 | +
|
| 16 | +
|
| 17 | +""" |
| 18 | +from typing import List, Tuple |
| 19 | + |
| 20 | +Table = List[List[int]] # typing hint for board |
| 21 | + |
| 22 | +# intial values of sudoku board |
| 23 | +# 0 represents place to be filled |
| 24 | + |
| 25 | +board = [ |
| 26 | + [5, 0, 0, 0, 0, 0, 0, 0, 0], |
| 27 | + [3, 4, 0, 1, 0, 0, 0, 0, 7], |
| 28 | + [0, 9, 0, 0, 0, 6, 0, 0, 0], |
| 29 | + [6, 0, 0, 0, 2, 0, 0, 0, 9], |
| 30 | + [0, 0, 4, 9, 8, 0, 1, 0, 0], |
| 31 | + [0, 1, 0, 0, 4, 0, 0, 0, 0], |
| 32 | + [0, 0, 0, 0, 0, 3, 0, 2, 6], |
| 33 | + [0, 0, 0, 0, 0, 0, 8, 0, 0], |
| 34 | + [9, 0, 0, 0, 0, 0, 3, 4, 0], |
| 35 | +] |
| 36 | + |
| 37 | + |
| 38 | +def find_empty(board: Table) -> Tuple[int, int]: |
| 39 | + """ |
| 40 | + This function finds the empty position |
| 41 | + to be filled |
| 42 | +
|
| 43 | + Parameters : |
| 44 | + Input : Sudoku Table |
| 45 | + Output : Tuple[int,int] |
| 46 | + value of row and column of empty position |
| 47 | +
|
| 48 | + """ |
| 49 | + for i, row in enumerate(board): |
| 50 | + for j, val in enumerate(row): |
| 51 | + if val == 0: |
| 52 | + return (i, j) |
| 53 | + |
| 54 | + |
| 55 | +def valid(board: Table, num: int, pos: Tuple[int, int]) -> bool: |
| 56 | + """ |
| 57 | + This function checks the Table to see if each row, |
| 58 | + column, and the 3x3 subgrids contain the digit 'num. |
| 59 | + It returns False if it is not 'safe' (a duplicate digit |
| 60 | + is found) else returns True if it is 'safe' |
| 61 | +
|
| 62 | + Parameters : |
| 63 | + Input : Board : Table |
| 64 | + num : int |
| 65 | + pos : Tuple[int, int] |
| 66 | + which contain(row, column) of pos |
| 67 | + """ |
| 68 | + |
| 69 | + for i in range(len(board)): |
| 70 | + # this loop checks number in same row and column |
| 71 | + if board[pos[0]][i] == num or board[i][pos[1]] == num: |
| 72 | + return False |
| 73 | + |
| 74 | + # these are the row and column value for 3*3 subgrid |
| 75 | + # in which the num belong |
| 76 | + cur_row = 3 * (pos[0] // 3) |
| 77 | + cur_col = 3 * (pos[1] // 3) |
| 78 | + |
| 79 | + # this loop check for the num present in 3*3 subgrid |
| 80 | + for i in range(cur_row, cur_row + 3): |
| 81 | + for j in range(cur_col, cur_col + 3): |
| 82 | + if board[i][j] == num: |
| 83 | + return False |
| 84 | + return True |
| 85 | + |
| 86 | + |
| 87 | +def solve(board: Table) -> bool: |
| 88 | + """ |
| 89 | + This is Solver function which uses Backtracking |
| 90 | + it repeatedly fills values in empty spaces and if filled |
| 91 | + value is wrong it backtracks to last value and start filling again |
| 92 | + with diffrent value |
| 93 | +
|
| 94 | + Parameteres : |
| 95 | + Input : Board : Table |
| 96 | +
|
| 97 | + Output : True if it solves the Sudoku Table |
| 98 | + False if Sudoku Table is incorrect |
| 99 | +
|
| 100 | + """ |
| 101 | + # finds the empty position to be filled |
| 102 | + find = find_empty(board) |
| 103 | + |
| 104 | + if not find: |
| 105 | + |
| 106 | + # if no empty position is there |
| 107 | + # we solved sudoku and returns True |
| 108 | + return True |
| 109 | + else: |
| 110 | + # row and column value for the corresponding empty position |
| 111 | + row, col = find |
| 112 | + |
| 113 | + # this loop fills the value from 1- 10 to empty position |
| 114 | + for i in range(1, 10): |
| 115 | + |
| 116 | + # this checks if corresponding filled value is correct or not |
| 117 | + if valid(board, i, (row, col)): |
| 118 | + board[row][col] = i |
| 119 | + |
| 120 | + if solve(board): |
| 121 | + # if value is correct then moves to next value |
| 122 | + return True |
| 123 | + |
| 124 | + # if value is not correct mark this as empty |
| 125 | + board[row][col] = 0 |
| 126 | + |
| 127 | + # backtracks to previous filled value |
| 128 | + return False |
| 129 | + |
| 130 | + |
| 131 | +def print_board(board: Table) -> None: |
| 132 | + """ |
| 133 | + This function prints Board in form of |
| 134 | + 9*9 matrix |
| 135 | + """ |
| 136 | + for i in range(len(board)): |
| 137 | + if i % 3 == 0 and i > 0: |
| 138 | + print("- - - - - - - - - - - - - - - ") |
| 139 | + for j in range(len(board[i])): |
| 140 | + if j % 3 == 0 and j > 0: |
| 141 | + print("| ", end="") |
| 142 | + print(board[i][j], " ", end="") |
| 143 | + if j == len(board[i]) - 1: |
| 144 | + print("\n") |
| 145 | + |
| 146 | + |
| 147 | +print("Before Solving Sudoku : \n") |
| 148 | +print_board(board) |
| 149 | +if solve(board): |
| 150 | + print("\n********After Solving *********\n") |
| 151 | + print_board(board) |
| 152 | +else: |
| 153 | + print("Enter Valid 3*3 sudoku pattern\n") |
0 commit comments