def brute_force_solve_sudoku(sudoku: sudoku_board.Sudoku): # 'l' is a list variable that keeps the record of row and col in find_empty_location Function arr = sudoku.board_numbers location = [0, 0] # If there is no unassigned location, we are done if not find_empty_location(arr, location): return True # Assigning list values to row and col that we got from the above Function row = location[0] col = location[1] # consider digits 1 to 9 for num in range(1, 10): # if looks promising if check_location_is_safe(arr, row, col, num): # make tentative assignment sudoku.add_cell(row, col, num) # return, if success, ya! if brute_force_solve_sudoku(sudoku): return True # failure, unmake & try again sudoku.add_cell(row, col, 0) # this triggers backtracking return False
def test_add_cell_with_valid(): sudoku_board = Sudoku(boards.unsolved_easy) row = 3 column = 7 value = 5 sudoku_board.add_cell(row, column, value) assert sudoku_board.board_numbers[row][column] == value
def test_add_cell_with_invalid(): sudoku_board = Sudoku(boards.unsolved_easy) row = 3 column = 7 value = 's' with pytest.raises(Exception): # noinspection PyTypeChecker sudoku_board.add_cell(row, column, value)
def solve_all_single_value_cells(sudoku: sudoku_board.Sudoku) -> None: solved_value = True while solved_value: solved_value = False for row in range(9): for column in range(9): values = get_possible_cell_values(sudoku, row, column) if len(values) == 1 and sudoku.board_numbers[row][column] == 0: sudoku.add_cell(row, column, values[0]) solved_value = True
def crosshatch_box(sudoku: sudoku_board.Sudoku, box_number: int) -> bool: all_values = [1, 2, 3, 4, 5, 6, 7, 8, 9] unused_values = [] box = sudoku.get_box_from_index(box_number) box_values = box.flatten() for value in all_values: if value not in box_values: unused_values.append(value) solved_value = False # Loop through each value that is not in the box. for value in unused_values: possible_rows = [] possible_columns = [] # Check each row that goes through the box. for row in get_rows_from_box_index(box_number): # If the value is not in that row then it could be in that row of the box. if not check_row_for_value(sudoku, row, value): possible_rows.append(row) # Check each column that goes through the box. for column in get_columns_from_box_index(box_number): # If the value is not in that column then it could be in that column of the box. if not check_column_for_value(sudoku, column, value): possible_columns.append(column) # Remove duplicates from possible rows and columns. possible_rows = list(set(possible_rows)) possible_columns = list(set(possible_columns)) # A cell position is only possible if the value is 0. Save the index if it is. possible_index = [] for row in possible_rows: for column in possible_columns: if sudoku.board_numbers[row, column] == 0: possible_index.append([row, column]) # If there is only one possible value for this cell then add it to the board. if len(possible_index) == 1: sudoku.add_cell(possible_index[0][0], possible_index[0][1], value) solved_value = True return solved_value
def solve_naked_subset_row(sudoku: sudoku_board.Sudoku, row: int) -> None: cell_possible_values = [] for column in range(9): cell_possible_values.append( get_possible_cell_values(sudoku, row, column)) subset_indices_two = [] for cell in range(9): if len(cell_possible_values[cell]) == 2: subset_indices_two.append(cell) values_two = [] if len(subset_indices_two) == 2: values_two = cell_possible_values[subset_indices_two[0]] for index in range(9): if index not in subset_indices_two: cell_possible_values[index] = ( list(set(cell_possible_values[index]) - set(values_two))) for column in range(9): if len(cell_possible_values[column]) == 1: sudoku.add_cell(row, column, cell_possible_values[column][0])