



'''simple docstring'''




from __future__ import annotations

lowerCamelCase							:Optional[int]				    =					list[list[int]]

# assigning initial values to the grid
lowerCamelCase							:Matrix				    =					[
    [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
lowerCamelCase							:Matrix				    =					[
    [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 	a			( lowerCamelCase__						,      lowerCamelCase__						,      lowerCamelCase__						,      lowerCamelCase__    ):
			'''simple docstring'''





			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 	a			( lowerCamelCase__    ):
			'''simple docstring'''





			for i in range(9    ):
						for j in range(9    ):
									if grid[i][j] == 0:
												return i, j
			return None



def 	a			( lowerCamelCase__    ):
			'''simple docstring'''





			if location := find_empty_location(lowerCamelCase__    ):
						A_,    A_	:						Union[str, Any]	=     location
			else:
						# If the location is ``None``, then the grid is solved.
						return grid

			for digit in range(1						,      10    ):
						if is_safe(lowerCamelCase__						,      lowerCamelCase__						,      lowerCamelCase__						,      lowerCamelCase__    ):
									A_	:						int	=     digit

									if sudoku(lowerCamelCase__    ) is not None:
												return grid

									A_	:						Dict	=     0

			return None



def 	a			( lowerCamelCase__    ):
			'''simple docstring'''





			for row in grid:
						for cell in row:
									print(lowerCamelCase__						,      end=""" """    )
						print()


if __name__ == "__main__":
						# make a copy of grid so that you can compare with the unmodified grid
						for example_grid in (initial_grid, no_solution):
												print('''\nExample grid:\n''' + '''=''' * 2_0)
												print_solution(example_grid)
												print('''\nExample grid solution:''')
												lowerCamelCase							:Optional[int]				    =					sudoku(example_grid)
												if solution is not None:
																		print_solution(solution)
												else:
																		print('''Cannot find a solution.''')




'''simple docstring'''




# Author: OMKAR PATHAK, Nwachukwu Chidiebere

# Use a Python dictionary to construct the graph.
from __future__ import annotations

from pprint import pformat
from typing import Generic, TypeVar

lowerCamelCase							:str				    =					TypeVar('''T''')







class 	_lowerCAmelCase							(			Generic[T] ):


	def __init__(self       ,      lowercase = True							):
				A_	:						dict[T, list[T]]	=     {}  # dictionary of lists
				A_	:						Any	=     directed


	def     _a	(self       ,      lowercase       ,      lowercase							):

				if not self.directed:  # For undirected graphs
							# if both source vertex and destination vertex are both present in the
							# adjacency list, add destination vertex to source vertex list of adjacent
							# vertices and add source vertex to destination vertex list of adjacent
							# vertices.
							if source_vertex in self.adj_list and destination_vertex in self.adj_list:
										self.adj_list[source_vertex].append(lowercase							)
										self.adj_list[destination_vertex].append(lowercase							)
							# if only source vertex is present in adjacency list, add destination vertex
							# to source vertex list of adjacent vertices, then create a new vertex with
							# destination vertex as key and assign a list containing the source vertex
							# as it's first adjacent vertex.
							elif source_vertex in self.adj_list:
										self.adj_list[source_vertex].append(lowercase							)
										A_	:						Dict	=     [source_vertex]
							# if only destination vertex is present in adjacency list, add source vertex
							# to destination vertex list of adjacent vertices, then create a new vertex
							# with source vertex as key and assign a list containing the source vertex
							# as it's first adjacent vertex.
							elif destination_vertex in self.adj_list:
										self.adj_list[destination_vertex].append(lowercase							)
										A_	:						int	=     [destination_vertex]
							# if both source vertex and destination vertex are not present in adjacency
							# list, create a new vertex with source vertex as key and assign a list
							# containing the destination vertex as it's first adjacent vertex also
							# create a new vertex with destination vertex as key and assign a list
							# containing the source vertex as it's first adjacent vertex.
							else:
										A_	:						Optional[Any]	=     [destination_vertex]
										A_	:						Tuple	=     [source_vertex]
				else:  # For directed graphs
							# if both source vertex and destination vertex are present in adjacency
							# list, add destination vertex to source vertex list of adjacent vertices.
							if source_vertex in self.adj_list and destination_vertex in self.adj_list:
										self.adj_list[source_vertex].append(lowercase							)
							# if only source vertex is present in adjacency list, add destination
							# vertex to source vertex list of adjacent vertices and create a new vertex
							# with destination vertex as key, which has no adjacent vertex
							elif source_vertex in self.adj_list:
										self.adj_list[source_vertex].append(lowercase							)
										A_	:						Tuple	=     []
							# if only destination vertex is present in adjacency list, create a new
							# vertex with source vertex as key and assign a list containing destination
							# vertex as first adjacent vertex
							elif destination_vertex in self.adj_list:
										A_	:						Tuple	=     [destination_vertex]
							# if both source vertex and destination vertex are not present in adjacency
							# list, create a new vertex with source vertex as key and a list containing
							# destination vertex as it's first adjacent vertex. Then create a new vertex
							# with destination vertex as key, which has no adjacent vertex
							else:
										A_	:						int	=     [destination_vertex]
										A_	:						List[str]	=     []

				return self


	def __repr__(self							):
				return pformat(self.adj_list							)