数独的递归回溯

时间:2017-05-25 22:13:23

标签: python python-3.x recursion sudoku

我仍然很擅长编码,我正在尝试稍微更难的主题,例如为数独修改递归回溯程序的解决方案。原始解决方案适用于大小为3x3的数独游戏,我希望我能使用正常大小的数独游戏(9x9)。找到3x3解决方案here

我觉得我对算法的理解非常好:对于网格中的每个列表(保存该单元格的可能值),在每一步尝试每个数字,确保板仍然有效,移到下一个列表,分配一个可能的数字,直到其有效等等,回溯到最后一块仍然有效的板,如果当前的板不正确。

编辑:添加了一些函数来缩小每个空单元格的可能值,以及填充只有一个可能值的单元格。我已经验证这些功能是否正常工作。 仅在初始化数独时调用fill_zerosmake_nodes构建了董事会的最新节点。 node_to_board以节点格式接收板并以行格式返回板。 refine_by函数不言自明。

def make_nodes(board):
    nodes = [[board[0][0], board[0][1], board[0][2],
             board[1][0], board[1][1], board[1][2],
             board[2][0], board[2][1], board[2][2]],
             [board[0][3], board[0][4], board[0][5],
              board[1][3], board[1][4], board[1][5],
              board[2][3], board[2][4], board[2][5]],
             [board[0][6], board[0][7], board[0][8],
              board[1][6], board[1][7], board[1][8],
              board[2][6], board[2][7], board[2][8]],
             [board[3][0], board[3][1], board[3][2],
              board[4][0], board[4][1], board[4][2],
              board[5][0], board[5][1], board[5][2]],
             [board[3][3], board[3][4], board[3][5],
              board[4][3], board[4][4], board[4][5],
              board[5][3], board[5][4], board[5][5]],
             [board[3][6], board[3][7], board[3][8],
              board[4][6], board[4][7], board[4][8],
              board[5][6], board[5][7], board[5][8]],
             [board[6][0], board[6][1], board[6][2],
              board[7][0], board[7][1], board[7][2],
              board[8][0], board[8][1], board[8][2]],
             [board[6][3], board[6][4], board[6][5],
              board[7][3], board[7][4], board[7][5],
              board[8][3], board[8][4], board[8][5]],
             [board[6][6], board[6][7], board[6][8],
              board[7][6], board[7][7], board[7][8],
              board[8][6], board[8][7], board[8][8]]
             ]
    return nodes


def fill_zeros(board):
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for i in range(9):
        for j in range(9):
            possible = [h for h in allnums if h not in nodes[i]]
            if nodes[i][j] == 0:
                nodes[i][j] = possible
    return nodes


def node_to_board(nodes):
    board = []
    for y in range(3):
        for i in range(0,9, 3):
            for node in nodes[(y*3):((y+1)*3)]:
                for x in range(3):
                    board.append(node[i+x])
    board = [board[pos:pos + 9] for pos in range(0, 9 * 9, 9)]
    return board


def refine_empty_by_col(board):
    for col in range(9):
        col_done = []
        for row in range(9):
            if type(board[row][col]) == int:
                col_done.append(board[row][col])
        for row in range(9):
            if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in col_done]
        for row in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board


def refine_empty_by_row(board):
    for row in range(9):
        row_done = []
        for col in range(9):
            if type(board[row][col]) == int:
                row_done.append(board[row][col])
        for col in range(9):
             if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in row_done]
        for col in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board

def refine_empty_by_node(board):
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for node in range(9):
        taken = [x for x in allnums if x in nodes[node]]
        for item in range(9):
            if type(nodes[node][item]) == list:
                nodes[node][item] = [x for x in nodes[node][item] if x not in taken]
                if len(nodes[node][item]) == 1:
                    k = nodes[node][item].pop()
                    taken.append(k)
                    nodes[node][item] = k
        node_list_nums = []
        for item in range(9):
            if type(nodes[node][item]) == list:
                node_list_nums += nodes[node][item]
        node_list_nums = [x for x in node_list_nums if node_list_nums.count(x) == 1]
        for item in range(9):
            if type(nodes[node][item]) == list:
                if any(nodes[node][item]) in node_list_nums:
                    for x in node_list_nums:
                        if x in nodes[node][item]:
                            nodes[node][item] = x
                            node_list_nums.remove(x)

    board = node_to_board(nodes)
    return board

def refine_easy_style(board):
    board_after = board
    board_orig = []
    while board_orig != board_after:
        board_orig = board_after
        board_after = refine_empty_by_col(board_orig)
        board_after = refine_empty_by_row(board_after)
        board_after = refine_empty_by_node(board_after)

    return board_after

以下是(编辑过的)辅助功能:

def is_distinct(passed):
    used = []
    for item in passed:
        if type(item) == list:
            continue
        if item in used:
            return False
        used.append(item)
    return True

def is_valid(board):
    for i in range(9):
        row = [board[i][row] for row in range(9)]
        if not is_distinct(row):
            return False

        col = [board[row][i] for row in range(9)]
        if not is_distinct(col):
            return False

    for node in make_nodes(board):
        if not is_distinct(node):
            return False

    return True

is_distinct传递一个列表,它会循环通过以确保每个项目都是唯一的(return True),否则返回False

is_valid包含电路板的细分部分:行,列和节点(每个3x3平方)。然后它将每块板子传递给is_distinct

(编辑过的)递归函数是

def solve_puzzle(board):
    empties = 0
    for row in board:
        for item in row:
            if type(item) == list:
                empties += 1

    if empties == 0:
        if is_valid(board):
            return board
        else:
            print('0 empties')
            return False

    for i in range(9):
        for j in range(9):
            if type(board[i][j]) == list:
                board2 = board
                for k in board2[i][j]:
                    print('trying = {}, cell-list ={}, coords = {},{}'.format(k, board2[i][j], i, j))
                    board2[i][j] = k
                    if is_valid(board2) and solve_puzzle(board2):
                        return True
                    else:
                        print('{} at slot {}, {} didnt work.'.format(k, i , j))
                    print('Backtracking here...')
                    board2[i][j] = board[i][j]
    return False

设置是:

#below this line works
inp = [int(x) for x in input().split()]
empties = inp.count(0)
board = [inp[pos:pos+9] for pos in range(0, 9*9, 9)]
board = node_to_board(fill_zeros(board))
print(board)
board = refine_easy_style(board)
print(board)
#above this line works
# below this line is testing
board = solve_puzzle(board)
print(board)

编辑:根据Prune的建议,我投入了几个打印调用来输出一些有用的信息。在跟踪输出后,我认为问题在于程序在运行每个可能的输出后如何回溯。例如:在输出中,电路板有效直到达到(3,8),然后它会通过输出而不是回溯到较早的单元,而是移动到下一个空(4,1)。此外,看起来回溯可能会走得太远;在输出结束时,它表示即使第一个猜测(1)是正确值,它也会在(0,1)处尝试新值。

我试过看别人'类似风格的数独解决方案,但似乎无法弄清楚我哪里出错了。

编辑:示例: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

示例:

[[3, [1, 4, 9], 6, 5, [1, 2, 3, 4, 6, 7, 9], 8, 4, [2, 5, 6, 7, 8, 9], [2, 5, 6, 7, 8, 9]], [5, 2, [1, 4, 9], [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [2, 5, 6, 7, 8, 9], [2, 5, 6, 7, 8, 9], [2, 5, 6, 7, 8, 9]], [[1, 4, 9], 8, 7, [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [2, 5, 6, 7, 8, 9], 3, 1], [[1, 2, 4, 6, 7, 8], [1, 2, 4, 6, 7, 8], 3, [2, 4, 5, 7], 1, [2, 4, 5, 7], [1, 2, 3, 4, 7, 9], 8, [1, 2, 3, 4, 7, 9]], [9, [1, 2, 4, 6, 7, 8], [1, 2, 4, 6, 7, 8], 8, 6, 3, [1, 2, 3, 4, 7, 9], [1, 2, 3, 4, 7, 9], 5], [[1, 2, 4, 6, 7, 8], 5, [1, 2, 4, 6, 7, 8], [2, 4, 5, 7], 9, [2, 4, 5, 7], 6, [1, 2, 3, 4, 7, 9], [1, 2, 3, 4, 7, 9]], [1, 3, [2, 4, 6, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], 2, 5, [1, 6, 8, 9]], [[2, 4, 6, 7, 8, 9], [2, 4, 6, 7, 8, 9], [2, 4, 6, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 6, 8, 9], 7, 4], [[2, 4, 6, 7, 8, 9], [2, 4, 6, 7, 8, 9], 5, 2, [1, 3, 4, 5, 7, 8, 9], 6, 3, [1, 6, 8, 9], [1, 6, 8, 9]]]
[[3, [1, 9], 6, 5, 7, 8, 4, [2, 9], [2, 9]], [5, 2, [1, 9], [1, 3, 4], [3, 4], [1, 4], [7, 8, 9], [6, 9], [6, 7, 8, 9]], [4, 8, 7, 6, 2, 9, 5, 3, 1], [[2, 6, 7], [4, 6, 7], 3, [4, 7], 1, [2, 4, 5, 7], [7, 9], 8, [2, 7, 9]], [9, [1, 4, 7], [1, 2, 4], 8, 6, 3, [1, 7], [1, 2, 4], 5], [[2, 7, 8], 5, [1, 2, 4, 8], [4, 7], 9, [2, 4, 7], 6, [1, 2, 4], [2, 3, 7]], [1, 3, [4, 8, 9], [4, 7, 9], [4, 8], [4, 7], 2, 5, [6, 8, 9]], [[2, 6, 8], [6, 9], [2, 8, 9], [1, 3, 9], [3, 5, 8], [1, 5], [1, 8, 9], 7, 4], [[7, 8], [4, 7, 9], 5, 2, [4, 8], 6, 3, [1, 9], [8, 9]]]
trying = 1, board-list =[1, 9], coords = 0,1
trying = 2, board-list =[2, 9], coords = 0,7
trying = 2, board-list =[2, 9], coords = 0,8
2 at slot 0, 8 didnt work.
Backtracking here...
trying = 9, board-list =2, coords = 0,8
trying = 1, board-list =[1, 9], coords = 1,2
1 at slot 1, 2 didnt work.
Backtracking here...
trying = 9, board-list =1, coords = 1,2
trying = 1, board-list =[1, 3, 4], coords = 1,3
trying = 3, board-list =[3, 4], coords = 1,4
trying = 1, board-list =[1, 4], coords = 1,5
1 at slot 1, 5 didnt work.
Backtracking here...
trying = 4, board-list =1, coords = 1,5
trying = 7, board-list =[7, 8, 9], coords = 1,6
trying = 6, board-list =[6, 9], coords = 1,7
trying = 6, board-list =[6, 7, 8, 9], coords = 1,8
6 at slot 1, 8 didnt work.
Backtracking here...
trying = 7, board-list =6, coords = 1,8
7 at slot 1, 8 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 1,8
trying = 2, board-list =[2, 6, 7], coords = 3,0
trying = 4, board-list =[4, 6, 7], coords = 3,1
trying = 4, board-list =[4, 7], coords = 3,3
4 at slot 3, 3 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 3,3
trying = 2, board-list =[2, 4, 5, 7], coords = 3,5
2 at slot 3, 5 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 3,5
4 at slot 3, 5 didnt work.
Backtracking here...
trying = 5, board-list =4, coords = 3,5
trying = 7, board-list =[7, 9], coords = 3,6
7 at slot 3, 6 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 3,6
trying = 2, board-list =[2, 7, 9], coords = 3,8
2 at slot 3, 8 didnt work.
Backtracking here...
trying = 7, board-list =2, coords = 3,8
7 at slot 3, 8 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 3,8
9 at slot 3, 8 didnt work.
Backtracking here...
trying = 1, board-list =[1, 4, 7], coords = 4,1
1 at slot 4, 1 didnt work.
Backtracking here...
trying = 4, board-list =1, coords = 4,1
4 at slot 4, 1 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 4,1
7 at slot 4, 1 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4], coords = 4,2
1 at slot 4, 2 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 4,2
2 at slot 4, 2 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 4,2
4 at slot 4, 2 didnt work.
Backtracking here...
trying = 1, board-list =[1, 7], coords = 4,6
1 at slot 4, 6 didnt work.
Backtracking here...
trying = 7, board-list =1, coords = 4,6
7 at slot 4, 6 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4], coords = 4,7
1 at slot 4, 7 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 4,7
2 at slot 4, 7 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 4,7
4 at slot 4, 7 didnt work.
Backtracking here...
trying = 2, board-list =[2, 7, 8], coords = 5,0
2 at slot 5, 0 didnt work.
Backtracking here...
trying = 7, board-list =2, coords = 5,0
7 at slot 5, 0 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 5,0
8 at slot 5, 0 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4, 8], coords = 5,2
1 at slot 5, 2 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 5,2
2 at slot 5, 2 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 5,2
4 at slot 5, 2 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 5,2
8 at slot 5, 2 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7], coords = 5,3
4 at slot 5, 3 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 5,3
7 at slot 5, 3 didnt work.
Backtracking here...
trying = 2, board-list =[2, 4, 7], coords = 5,5
2 at slot 5, 5 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 5,5
4 at slot 5, 5 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 5,5
7 at slot 5, 5 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4], coords = 5,7
1 at slot 5, 7 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 5,7
2 at slot 5, 7 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 5,7
4 at slot 5, 7 didnt work.
Backtracking here...
trying = 2, board-list =[2, 3, 7], coords = 5,8
2 at slot 5, 8 didnt work.
Backtracking here...
trying = 3, board-list =2, coords = 5,8
3 at slot 5, 8 didnt work.
Backtracking here...
trying = 7, board-list =3, coords = 5,8
7 at slot 5, 8 didnt work.
Backtracking here...
trying = 4, board-list =[4, 8, 9], coords = 6,2
4 at slot 6, 2 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 6,2
8 at slot 6, 2 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 6,2
9 at slot 6, 2 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7, 9], coords = 6,3
4 at slot 6, 3 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 6,3
7 at slot 6, 3 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 6,3
9 at slot 6, 3 didnt work.
Backtracking here...
trying = 4, board-list =[4, 8], coords = 6,4
4 at slot 6, 4 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 6,4
8 at slot 6, 4 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7], coords = 6,5
4 at slot 6, 5 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 6,5
7 at slot 6, 5 didnt work.
Backtracking here...
trying = 6, board-list =[6, 8, 9], coords = 6,8
6 at slot 6, 8 didnt work.
Backtracking here...
trying = 8, board-list =6, coords = 6,8
8 at slot 6, 8 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 6,8
9 at slot 6, 8 didnt work.
Backtracking here...
trying = 2, board-list =[2, 6, 8], coords = 7,0
2 at slot 7, 0 didnt work.
Backtracking here...
trying = 6, board-list =2, coords = 7,0
6 at slot 7, 0 didnt work.
Backtracking here...
trying = 8, board-list =6, coords = 7,0
8 at slot 7, 0 didnt work.
Backtracking here...
trying = 6, board-list =[6, 9], coords = 7,1
6 at slot 7, 1 didnt work.
Backtracking here...
trying = 9, board-list =6, coords = 7,1
9 at slot 7, 1 didnt work.
Backtracking here...
trying = 2, board-list =[2, 8, 9], coords = 7,2
2 at slot 7, 2 didnt work.
Backtracking here...
trying = 8, board-list =2, coords = 7,2
8 at slot 7, 2 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 7,2
9 at slot 7, 2 didnt work.
Backtracking here...
trying = 1, board-list =[1, 3, 9], coords = 7,3
1 at slot 7, 3 didnt work.
Backtracking here...
trying = 3, board-list =1, coords = 7,3
3 at slot 7, 3 didnt work.
Backtracking here...
trying = 9, board-list =3, coords = 7,3
9 at slot 7, 3 didnt work.
Backtracking here...
trying = 3, board-list =[3, 5, 8], coords = 7,4
3 at slot 7, 4 didnt work.
Backtracking here...
trying = 5, board-list =3, coords = 7,4
5 at slot 7, 4 didnt work.
Backtracking here...
trying = 8, board-list =5, coords = 7,4
8 at slot 7, 4 didnt work.
Backtracking here...
trying = 1, board-list =[1, 5], coords = 7,5
1 at slot 7, 5 didnt work.
Backtracking here...
trying = 5, board-list =1, coords = 7,5
5 at slot 7, 5 didnt work.
Backtracking here...
trying = 1, board-list =[1, 8, 9], coords = 7,6
1 at slot 7, 6 didnt work.
Backtracking here...
trying = 8, board-list =1, coords = 7,6
8 at slot 7, 6 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 7,6
9 at slot 7, 6 didnt work.
Backtracking here...
trying = 7, board-list =[7, 8], coords = 8,0
7 at slot 8, 0 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 8,0
8 at slot 8, 0 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7, 9], coords = 8,1
4 at slot 8, 1 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 8,1
7 at slot 8, 1 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 8,1
9 at slot 8, 1 didnt work.
Backtracking here...
trying = 4, board-list =[4, 8], coords = 8,4
4 at slot 8, 4 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 8,4
8 at slot 8, 4 didnt work.
Backtracking here...
trying = 1, board-list =[1, 9], coords = 8,7
1 at slot 8, 7 didnt work.
Backtracking here...
trying = 9, board-list =1, coords = 8,7
9 at slot 8, 7 didnt work.
Backtracking here...
trying = 8, board-list =[8, 9], coords = 8,8
8 at slot 8, 8 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 8,8
9 at slot 8, 8 didnt work.
Backtracking here...
9 at slot 3, 6 didnt work.
Backtracking here...
5 at slot 3, 5 didnt work.
Backtracking here...
trying = 7, board-list =5, coords = 3,5
7 at slot 3, 5 didnt work.
Backtracking here...
7 at slot 3, 3 didnt work.
Backtracking here...
4 at slot 3, 1 didnt work.
Backtracking here...
trying = 6, board-list =4, coords = 3,1
6 at slot 3, 1 didnt work.
Backtracking here...
trying = 7, board-list =6, coords = 3,1
7 at slot 3, 1 didnt work.
Backtracking here...
2 at slot 3, 0 didnt work.
Backtracking here...
trying = 6, board-list =2, coords = 3,0
6 at slot 3, 0 didnt work.
Backtracking here...
trying = 7, board-list =6, coords = 3,0
7 at slot 3, 0 didnt work.
Backtracking here...
8 at slot 1, 8 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 1,8
9 at slot 1, 8 didnt work.
Backtracking here...
6 at slot 1, 7 didnt work.
Backtracking here...
trying = 9, board-list =6, coords = 1,7
9 at slot 1, 7 didnt work.
Backtracking here...
7 at slot 1, 6 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 1,6
8 at slot 1, 6 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 1,6
9 at slot 1, 6 didnt work.
Backtracking here...
4 at slot 1, 5 didnt work.
Backtracking here...
3 at slot 1, 4 didnt work.
Backtracking here...
trying = 4, board-list =3, coords = 1,4
4 at slot 1, 4 didnt work.
Backtracking here...
1 at slot 1, 3 didnt work.
Backtracking here...
trying = 3, board-list =1, coords = 1,3
3 at slot 1, 3 didnt work.
Backtracking here...
trying = 4, board-list =3, coords = 1,3
4 at slot 1, 3 didnt work.
Backtracking here...
9 at slot 1, 2 didnt work.
Backtracking here...
9 at slot 0, 8 didnt work.
Backtracking here...
2 at slot 0, 7 didnt work.
Backtracking here...
trying = 9, board-list =2, coords = 0,7
9 at slot 0, 7 didnt work.
Backtracking here...
1 at slot 0, 1 didnt work.
Backtracking here...
trying = 9, board-list =1, coords = 0,1
9 at slot 0, 1 didnt work.
Backtracking here...
False

更正:3 1 6 5 7 8 4 9 2 5 2 9 1 3 4 7 6 8 4 8 7 6 2 9 5 3 1 2 6 3 4 1 5 9 8 7 9 7 4 8 6 3 1 2 5 8 5 1 7 9 2 6 4 3 1 3 8 9 4 7 2 5 6 6 9 2 3 5 1 8 7 4 7 4 5 2 8 6 3 1 9

以数独格式正确回答:

3 1 6 5 7 8 4 9 2

5 2 9 1 3 4 7 6 8

4 8 7 6 2 9 5 3 1

2 6 3 4 1 5 9 8 7

9 7 4 8 6 3 1 2 5

8 5 1 7 9 2 6 4 3

1 3 8 9 4 7 2 5 6

6 9 2 3 5 1 8 7 4

7 4 5 2 8 6 3 1 9

1 个答案:

答案 0 :(得分:0)

由OP解决。工作代码是:

def make_nodes(board):
    '''
    make_nodes converts a board compiled of 1x9 rows to a board compiled of 3x3 nodes
    :param board:
    :return nodes:
    '''
    nodes = [[board[0][0], board[0][1], board[0][2],
             board[1][0], board[1][1], board[1][2],
             board[2][0], board[2][1], board[2][2]],
             [board[0][3], board[0][4], board[0][5],
              board[1][3], board[1][4], board[1][5],
              board[2][3], board[2][4], board[2][5]],
             [board[0][6], board[0][7], board[0][8],
              board[1][6], board[1][7], board[1][8],
              board[2][6], board[2][7], board[2][8]],
             [board[3][0], board[3][1], board[3][2],
              board[4][0], board[4][1], board[4][2],
              board[5][0], board[5][1], board[5][2]],
             [board[3][3], board[3][4], board[3][5],
              board[4][3], board[4][4], board[4][5],
              board[5][3], board[5][4], board[5][5]],
             [board[3][6], board[3][7], board[3][8],
              board[4][6], board[4][7], board[4][8],
              board[5][6], board[5][7], board[5][8]],
             [board[6][0], board[6][1], board[6][2],
              board[7][0], board[7][1], board[7][2],
              board[8][0], board[8][1], board[8][2]],
             [board[6][3], board[6][4], board[6][5],
              board[7][3], board[7][4], board[7][5],
              board[8][3], board[8][4], board[8][5]],
             [board[6][6], board[6][7], board[6][8],
              board[7][6], board[7][7], board[7][8],
              board[8][6], board[8][7], board[8][8]]
             ]
    return nodes


def fill_zeros(board):
    '''
    fill_zeros replaces every empty 0 with the possible values for that cell based off given values in its node
    :param board:
    :return board:
    '''
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for i in range(9):
        for j in range(9):
            possible = [h for h in allnums if h not in nodes[i]]
            if nodes[i][j] == 0:
                nodes[i][j] = possible
    return nodes


def node_to_board(nodes):
    '''
    node_to_board converts a board compiled of 3x3 nodes to a board of 1x9 rows
    :param nodes:
    :return board:
    '''
    board = []
    for y in range(3):
        for i in range(0,9, 3):
            for node in nodes[(y*3):((y+1)*3)]:
                for x in range(3):
                    board.append(node[i+x])
    board = [board[pos:pos + 9] for pos in range(0, 9 * 9, 9)]
    return board


def refine_empty_by_col(board):
    '''
    refine_empty_by_col takes a board with empty cells, and checks each number in the empty cells. If the number
    is already a definitenumber in its own column, remove that number from the possible values for that cell
    :param board:
    :return board:
    '''
    for col in range(9):
        col_done = []
        for row in range(9):
            if type(board[row][col]) == int:
                col_done.append(board[row][col])
        for row in range(9):
            if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in col_done]
        for row in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board


def refine_empty_by_row(board):
    '''
    refine_empty_by_row takes a board with empty cells, and checks each number in the empty cells. If the number is
    already a definite number in its own row, remove that number from the possible values for that cell
    :param board:
    :return board:
    '''
    for row in range(9):
        row_done = []
        for col in range(9):
            if type(board[row][col]) == int:
                row_done.append(board[row][col])
        for col in range(9):
             if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in row_done]
        for col in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board


def refine_empty_by_node(board):
    '''
    refine_empty_by_node takes a board with empty cells, and checks each number in the empty cells. If the number is
    already a definite number in its own node, remove that number from the possible values for that cell
    :param board:
    :return board:
    '''
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for node in range(9):
        taken = [x for x in allnums if x in nodes[node]]
        for item in range(9):
            if type(nodes[node][item]) == list:
                nodes[node][item] = [x for x in nodes[node][item] if x not in taken]
                if len(nodes[node][item]) == 1:
                    k = nodes[node][item].pop()
                    taken.append(k)
                    nodes[node][item] = k
        node_list_nums = []
        for item in range(9):
            if type(nodes[node][item]) == list:
                node_list_nums += nodes[node][item]
        node_list_nums = [x for x in node_list_nums if node_list_nums.count(x) == 1]
        for item in range(9):
            if type(nodes[node][item]) == list:
                if any(nodes[node][item]) in node_list_nums:
                    for x in node_list_nums:
                        if x in nodes[node][item]:
                            nodes[node][item] = x
                            node_list_nums.remove(x)

    board = node_to_board(nodes)
    return board


def refine_easy_style(board):
    '''
    refine_easy_style takes a "fresh" board and repeatedly calls refine_empty_by_* until no more changes can be made
    using this method.
    :param board:
    :return board:
    '''
    board_after = board
    board_orig = []
    while board_orig != board_after:
        board_orig = board_after
        board_after = refine_empty_by_col(board_orig)
        board_after = refine_empty_by_row(board_after)
        board_after = refine_empty_by_node(board_after)

    return board_after

## above this line works
## below this line is testing


def is_distinct(passed):
    '''
    is_distinct checks to ensure the (node|row|column) is has only unique definite values (True) if not return False
    :param passed:
    :return True if all distinct definites, False otherwise:
    '''
    used = []
    for item in passed:
        if type(item) == list:
            continue
        if item in used:
            return False
        used.append(item)
    return True


def is_valid(board):
    '''
    is_valid ensures the entire board is still valid by checking each row, column and node via is_distinct
    :param board:
    :return True if valid board, False otherwise:
    '''
    for i in range(9):
        row = [board[i][row] for row in range(9)]
        if not is_distinct(row):
            return False

        col = [board[row][i] for row in range(9)]
        if not is_distinct(col):
            return False

    for node in make_nodes(board):
        if not is_distinct(node):
            return False

    return True


def next_empty(board):
    '''
    next_empty finds the next empty cell on the board, based on how many possibilities that empty cell has in
    ascending order
    :param board:
    :return x,y coords:
    '''
    min = [x for x in range(9)]
    row = 0
    col = 0
    for i in range(9):
        for j in range(9):
            if type(board[i][j]) == list:
                if len(board[i][j]) < len(min):
                    min = board[i][j]
                    row = i
                    col = j
    return row, col


def solve_puzzle(board):
    '''
    solve_puzzle recursively calls itself until the board is solved or a solution is not found
    :param board:
    :return True if solved, False if no solution exists:
    '''
    # if there are no empty cells left, ensure the board is valid
    empties = 0
    for row in board:
        for item in row:
            if type(item) == list:
                empties += 1
    if empties == 0:
        return is_valid(board)

    # get the next empty cell coords
    row, col = next_empty(board)
    board2 = board
    possible = board2[row][col]
    # recursive step
    # loop through every possible value until one is valid, backtracking until a valid board is found
    for k in possible:
        board2[row][col] = k
        if is_valid(board2) and solve_puzzle(board2):
            return True
        board2[row][col] = possible
    return False


# read input
inp = [int(x) for x in input().split()]

# make a board from the input (row-format)
board = [inp[pos:pos+9] for pos in range(0, 9*9, 9)]

# fill zeros with possible values, then put it back to row-format
board = node_to_board(fill_zeros(board))

# fill in what is possible without recursion
board = refine_easy_style(board)

# solve the remaining cells with recursion
solve_puzzle(board)
for row in board:
    print(row)

示例: 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

示例:

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