You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python递归实现数独求解的代码调试求助

数独求解代码调试求助

我学习Python已有数月,尝试独立实现数独(Sudoku)求解功能,未先参考YouTube相关教程,而是自主思考编写代码,但目前陷入完全停滞的状态。查阅网上相关解决方案后,发现部分代码逻辑与我的相似,但我的代码始终无法正常运行。现寻求帮助,希望能判断是否可通过调整现有代码使其正常工作,还是我的实现思路完全偏离方向。

以下是我的代码:

# FUNCTIONS
def exclude_used_numbers():
    # exclude numbers already used in the same column
    for ii in range(1, sudoku + 1):
        for jj in range(sudoku):
            if globals()["row_" + str(ii)][jj] == 0:
                continue
            else:
                value_to_remove = globals()["row_" + str(ii)][jj]
                try:
                    globals()["available_numbers_for_index_" + str(jj)].remove(value_to_remove)
                except ValueError:
                    continue

    # exclude numbers already used in the same row
    for iii in range(1, sudoku + 1):
        for jjj in range(sudoku):
            if globals()["row_" + str(iii)][jjj] != 0:
                value_to_remove = globals()["row_" + str(iii)][jjj]
                try:
                    globals()["available_numbers_for_row_" + str(iii)].remove(value_to_remove)
                except ValueError:
                    continue

    # exclude numbers already used in the same square
    for iiii in range(1, sudoku + 1):
        for jjjj in range(squares_per_row):
            for k in range(globals()["square_" + str(jjjj + 1)][0], globals()["square_" + str(jjjj + 1)][1]):
                if globals()["row_" + str(iiii)][k] != 0:
                    value_to_remove = globals()["row_" + str(iiii)][k]
                    multiplier = ((iiii - 1) // 3) * squares_per_row
                    try:
                        globals()["available_numbers_for_square_" + str(jjjj + 1 + multiplier)].remove(value_to_remove)
                    except ValueError:
                        continue


def list_of_available_nums():
    # intersection of available numbers for columns and rows
    for a in range(1, sudoku + 1):
        for b in range(sudoku):
            if globals()["row_" + str(a)][b] == 0:
                temp_list = list(set(globals()["available_numbers_for_row_" + str(a)]).intersection(globals()["available_numbers_for_index_" + str(b)]))
                globals()["row_" + str(a)][b] = list(set(temp_list).intersection(globals()["available_numbers_for_square_" + str(b + 1)]))





sudoku = 9
rows = []


# create square ranges
squares = int((sudoku / 3) ** 2)
squares_per_row = int(sudoku / 3)
for i in range(squares_per_row):
    locals()["square_" + str(i+1)] = [i*3, (i*3)+3]


# create row lists
for i in range(1, sudoku+1):
    locals()["row_" + str(i)] = []
    for j in range(1, sudoku+1):
        locals()["row_" + str(i)].append(0)
    rows.append(locals()["row_" + str(i)])


# create available numbers for columns
for i in range(sudoku):
    locals()["available_numbers_for_index_" + str(i)] = []
    for j in range(1, sudoku+1):
        locals()["available_numbers_for_index_" + str(i)].append(j)


# create available numbers for rows
for i in range(1, sudoku+1):
    locals()["available_numbers_for_row_" + str(i)] = []
    for j in range(1, sudoku+1):
        locals()["available_numbers_for_row_" + str(i)].append(j)


# create available numbers for squares
for i in range(1, squares+1):
    locals()["available_numbers_for_square_" + str(i)] = []
    for j in range(1, 10):
        locals()["available_numbers_for_square_" + str(i)].append(j)


row_1[0] = 2
row_2[1] = 1
row_3[2] = 5
row_4[3] = 4
row_5[4] = 5
row_6[5] = 6


def solve():

    exclude_used_numbers()
    list_of_available_nums()

    for i in range(1, sudoku+1):
        for j in range(sudoku):

            if isinstance(globals()["row_" + str(i)][j], int):
                continue

            elif isinstance(globals()["row_" + str(i)][j], list) and globals()["row_" + str(i)][j]:

                for n in globals()["row_" + str(i)][j]:
                    globals()["row_" + str(i)][j] = n

                    for k in range(1, sudoku + 1):
                        for y in range(sudoku):
                            if isinstance(globals()["row_" + str(k)][y], list):
                                globals()["row_" + str(k)][y] = 0

                    print("=== GAME ===")
                    for z in range(1, sudoku + 1):
                        print(f"row_{z} :", end="")
                        print(globals()["row_" + str(z)])

                    solve()



if __name__ == '__main__':
    solve()

问题分析与调整建议

你的核心思路是对的:通过排除已用数字生成候选数,再用回溯法尝试填充,这是数独求解的经典路径,但代码存在几个关键问题导致无法正常运行:

1. 数据管理方式严重不合理

你用globals()/locals()动态生成变量(如row_1、available_numbers_for_index_0)来存储数独状态和候选数,这种方式不仅可读性极差,还会导致数据同步混乱——回溯修改状态后,候选数无法正确重置,后续递归会基于错误数据计算。

2. 回溯逻辑存在致命缺陷

  • 填充数字后,直接将其他位置的候选数列表设为0,彻底丢失了候选数信息,递归返回后无法恢复之前的状态。
  • 没有设置数独完成的终止条件,递归会无限执行。
  • 尝试候选数时,未验证填充的数字是否会导致行/列/宫的冲突。

3. 宫候选数计算错误

list_of_available_nums()中用b + 1获取宫编号是错误的,单元格所在的宫应该根据行和列的位置计算,比如对于行r、列c,宫的索引应为(r//3)*3 + c//3(从0开始计数)。

4. 候选数未实时更新

exclude_used_numbers()是一次性计算候选数,但回溯过程中每次填充数字后,候选数需要重新计算,你的代码没有处理这个同步逻辑。


可落地的调整方案

无需完全重构,按以下步骤修改即可让代码正常运行:

  1. 改用二维列表存储数独状态:把分散的row_1到row_9换成一个9x9的二维列表,操作更直观。
  2. 用三维列表存储候选数:每个单元格对应自己的候选数列表,避免分散变量的同步问题。
  3. 修复回溯的状态恢复:递归尝试填充数字前保存当前状态,递归返回后恢复(比如用临时变量存储,或复制候选数列表)。
  4. 添加终止条件:遍历数独,当所有单元格都不为0时,打印解并终止递归。
  5. 修正宫的索引计算:根据单元格的行和列确定所在宫的范围,正确排除已用数字。

简化修复示例

# 初始化数独棋盘
sudoku_board = [
    [2,0,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0,0],
    [0,0,5,0,0,0,0,0,0],
    [0,0,0,4,0,0,0,0,0],
    [0,0,0,0,5,0,0,0,0],
    [0,0,0,0,0,6,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0]
]

def is_valid(r, c, num):
    # 检查行是否重复
    if num in sudoku_board[r]:
        return False
    # 检查列是否重复
    if num in [sudoku_board[i][c] for i in range(9)]:
        return False
    # 检查3x3宫是否重复
    start_r = (r // 3) * 3
    start_c = (c // 3) * 3
    for i in range(3):
        for j in range(3):
            if sudoku_board[start_r+i][start_c+j] == num:
                return False
    return True

def solve():
    for r in range(9):
        for c in range(9):
            if sudoku_board[r][c] == 0:
                # 尝试所有可能的数字
                for num in range(1, 10):
                    if is_valid(r, c, num):
                        sudoku_board[r][c] = num
                        # 递归求解,成功则返回True
                        if solve():
                            return True
                        # 回溯,恢复当前单元格为0
                        sudoku_board[r][c] = 0
                # 无可用数字,回溯
                return False
    # 所有单元格填满,打印解
    print("=== 数独解 ===")
    for row in sudoku_board:
        print(row)
    return True

if __name__ == "__main__":
    solve()

内容的提问来源于stack exchange,提问作者64rl0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 02:07:06