Beispiel #1
0
def create_extreme_sudoku(sudoku,
                          goal=17,
                          eliminate_randomly=50,
                          objective=lambda sudoku: sudoku.metric):
    assert goal >= 17  # Minimum number for solvable sudokus
    assert eliminate_randomly < 64
    given_coordinates = sudoku.given_coordinates
    solver = SudokuSolver()

    # Step 1: Remove n random numbers from the sudoku
    coordinates_to_eliminate = random.sample(given_coordinates,
                                             eliminate_randomly)
    for x, y in coordinates_to_eliminate:
        sudoku[x][y] = 0

    # Step 2: Try to optimize sudoku according to the objective function
    given_coordinates = sudoku.given_coordinates

    dead_numbers = set()
    resample = lambda dead_numbers: random.sample(
        set(range(1, 10)) - dead_numbers, 1)[0]
    while len(given_coordinates) > goal:
        current_number_to_remove = resample(dead_numbers)
        deltas = {
        }  # Changes in value for objective function given the removal of coordinates of index i

        if len(dead_numbers) == 9:
            print("Fail at {} given numbers".format(len(given_coordinates)))
            import time
            time.sleep(4)
            return sudoku

        for x, y in given_coordinates:
            temp_sudoku = copy.copy(sudoku)
            old = objective(temp_sudoku)
            temp_sudoku[x][y] = 0
            temp_sudoku.update()
            new = objective(temp_sudoku)
            delta = new - old

            deltas[(x, y)] = (delta, sudoku[x][y])

        max_delta_indices = list(
            reversed(
                sorted(zip(range(len(deltas)), list(deltas.values())),
                       key=lambda x: x[1][0])))
        max_delta_indices = list(
            filter(
                lambda delta_tuple: delta_tuple[1][1] ==
                current_number_to_remove, max_delta_indices))

        print(current_number_to_remove)
        print("Indices", max_delta_indices)
        if len(max_delta_indices) == 0:
            current_number_to_remove = resample(dead_numbers)
            continue

        # Iterate through all the values, starting with the max, to see whether deleting the associated given number
        # results in a proper sudoku or not
        removed_number = False
        for max_delta_index, max_delta in max_delta_indices:
            if max_delta_index == len(max_delta_indices) - 1:
                print("Fail at {} given numbers".format(
                    len(given_coordinates)))
                import time
                time.sleep(4)
                return sudoku

            x_max, y_max = given_coordinates[max_delta_index]
            temp_sudoku = copy.copy(sudoku)
            temp_sudoku[x][y] = 0
            temp_sudoku.update()

            if solver.is_proper(temp_sudoku):
                print("Eliminating given at ({}, {}), {} numbers left.".format(
                    x_max, y_max,
                    len(given_coordinates) - 1))
                given_coordinates.pop(max_delta_index)
                sudoku[x_max][y_max] = 0
                sudoku.update()
                print(str(sudoku))

                removed_number = True
                dead_numbers = set()
                break

        if not removed_number:
            dead_numbers.add(current_number_to_remove)

    sudoku.update()  # Save changes internally
    return sudoku