Quantcast
Channel: Active questions tagged python - Stack Overflow
Viewing all articles
Browse latest Browse all 13921

Repeating values on recursive sudoku solver in python [closed]

$
0
0

I'm trying to make a sudoku solver using recursion by storing possible values in a dictionary with index as key and the set of possible values as value.Parameter b is just the board expressed as a single list, and .get_row, .get_col, .get_box methods return their respective values properly.If an entry in the dictionary has a set with a single element then it gets put into the board b, otherwise if there's no possible set with a single element a value gets picked from the set of possible numbers and the recursion starts. This is the full repeatable code:

class Sudoku:    def solve_it(self, board: List[List[str]]) -> None:"""        :param board: sudoku board gets modified inplace at .create_board_from_list        :return: None"""        unit_values = []        for i in range(len(board)):  # flattening the board into unit_values            for j in range(len(board[i])):                unit_values.append(board[i][j])        self.go_through_recursive(board, unit_values)    def get_row(self, n: int, b):  # retrieve all elements of nth row in the board        assert 0 <= n <= 8        return set(b[9 * n: 9 * (n + 1)])    def get_col(self, n: int, b):  # retrieve all elements of nth col in the board        assert 0 <= n <= 8        return set(b[n::9])    def get_box(self, n: int, b):  # retrieve all elements of nth box in the board        assert 0 <= n <= 8        return set(b[i] for i in range(81) if (i // 27) == (n // 3) and i % 9 // 3 == n % 3)    def go_through_recursive(self, board, b, d=False):"""        :param board: sudoku board as matrix where each row is a line        :param b: sudoku board as a single long list"""        numbers = {'1', '2', '3', '4', '5', '6', '7', '8', '9'}        while True:            if d:                return True            missing_dict = {}  # populate missing_dict            for idx in range(len(b)):                if b[idx] == '.':                    row = int(idx / 9)                    col = idx % 9                    box = int(row / 3) * 3 + int(col / 3)                    values = self.get_row(row, b).union(self.get_col(col, b)).union(self.get_box(box, b))                    values.remove('.')                    missing_ones = numbers.difference(values)                    if len(missing_ones) == 0:  # impossible to continue                        return False                    missing_dict[idx] = missing_ones            old_count = b.count('.')            for idx, missings in missing_dict.items():  # store assured values                if len(missings) == 1:                    v = missings.pop()                    b[idx] = v            if b.count('.') == 0:  # check if complete                self.create_board_from_list(board, b)                return True            if b.count('.') == old_count:  # if no progress has been made                for idx, s in missing_dict.items():  # iterate through the dictionary                    for number in s:  # create a new board and store indecisive value then recur                        if d:                            return True                        bb = b[:]                        bb[idx] = number                        d = self.go_through_recursive(board, bb)    def create_board_from_list(self, board, b):        temp_board = []        chunk = 9        for idx in range(0, len(b), chunk):            temp_board.append(b[idx: idx + chunk])        for idx in range(len(board)):            board[idx] = temp_board[idx]        print('done')

The issue I have is that once it completes, some numbers are repeated (either in the rows, cols or boxes). Also I've noticed that if I check the possible values inside the 'store assured values' loop it sometimes returns the whole range [1, 9] possibly being the reason of some rewriting

   row = int(idx / 9)   col = idx % 9   box = int(row / 3) * 3 + int(col / 3)   values = self.get_row(row, b).union(self.get_col(col, b)).union(self.get_box(box, b))   values.remove('.')  # some of these values are [1, 9]

for example

board =[[".",".","9","7","4","8",".",".","."],  ["7",".",".",".",".",".",".",".","."], [".","2",".","1",".","9",".",".","."], [".",".","7",".",".",".","2","4","."],  [".","6","4",".","1",".","5","9","."],  [".","9","8",".",".",".","3",".","."],  [".",".",".","8",".","3",".","2","."], [".",".",".",".",".",".",".",".","6"], [".",".",".","2","7","5","9",".","."]]

transforms the above into the incorrect

 board = [["3","1","9","7","4","8","6","5","2"], ["7","8","5","6","3","2","1","1","9"], ["4","2","6","1","5","9","8","7","3"], ["5","3","7","9","8","6","2","4","1"], ["2","6","4","3","1","7","5","9","8"], ["1","9","8","5","2","4","3","6","7"], ["9","7","1","8","6","3","4","2","5"], ["8","5","2","4","9","1","7","3","6"], ["6","4","3","2","7","5","9","8","4"]]

while the correct board should be:

 board = [["5","1","9","7","4","8","6","3","2"],  ["7","8","3","6","5","2","4","1","9"], ["4","2","6","1","3","9","8","7","5"], ["3","5","7","9","8","6","2","4","1"], ["2","6","4","3","1","7","5","9","8"], ["1","9","8","5","2","4","3","6","7"], ["9","7","5","8","6","3","1","2","4"], ["8","3","2","4","9","1","7","5","6"], ["6","4","1","2","7","5","9","8","3"]]

Viewing all articles
Browse latest Browse all 13921

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>