数独求解器开发:如何遍历并验证所有3×3宫格?
数独棋盘有效性验证问题
我正在开发一款数独求解器,没怎么查资料,现在写了一个验证数独棋盘有效性的函数,后续会用到循环逻辑里。当前函数代码如下:
def valid(board): s = 0 for row in board: if row.count('1') == 1 and row.count('2') == 1 and row.count('3') == 1 and row.count('4') == 1 and row.count('5') == 1 and row.count('6') == 1 and row.count('7') == 1 and row.count('8') == 1 and row.count('9') == 1: s += 1 for column in range(len(board)): if i[column].count('1') == 1 and i[column].count('2') == 1 and i[column].count('3') == 1 and i[column].count('4') == 1 and i[column].count('5') == 1 and i[column].count('6') == 1 and i[column].count('7') == 1 and i[column].count('8') == 1 and i[column].count('9') == 1: s += 1 for r in range(3): for c in range(3): print(board[r][c], end = '') if s == 18: print('valid') else: print('no')
测试用的有效棋盘是这个二维数组:
example = [['4','3','5','2','6','9','7','8','1'],['6','8','2','5','7','1','4','9','3'],['1','9','7','8','3','4','5','6','2'], ['8','2','6','1','9','5','3','4','7'],['3','7','4','6','8','2','9','1','5'],['9','5','1','7','4','3','6','2','8'], ['5','1','9','3','2','6','8','7','4'],['2','4','8','9','5','7','1','3','6'], ['7','6','3','4','1','8','2','5','9']]
我知道这种实现不是最优的,主要是想先搞懂逻辑:每行包含1-9各一次,s加1;每列符合同样条件,s也加1。所有行和列都符合的话s是18,但这还不够,得验证每个3×3宫格也满足1-9各出现一次,最终s要等于27才代表棋盘有效。
之前代码只能打印第一个3×3宫格,我试过暴力写法遍历所有宫格,但太繁琐,后来找到了更优的遍历方式:
def three(board): for row in range(0, 9, 3): for col in range(0, 9, 3): b = board[row][col] + board[row][col+1] + board[row][col+2] + board[row+1][col] + board[row+1][col+1] + board[row+1][col+2] + board[row+2][col] + board[row+2][col+1] + board[row+2][col+2] print(b) # test if valid...
这段代码能输出所有3×3宫格的内容:
435682197 269571834 781493562 826374951 195682743 347915628 519248763 326957418 874136259
现在需要完成这些3×3宫格的有效性验证,确保能正确判断整个数独棋盘是否有效,求帮助。
解决方案
首先,先优化你的验证逻辑,不管是行、列还是宫格,核心都是判断该区域是否包含1-9每个数字恰好一次,可以用集合来简化判断,比逐个count要简洁高效。另外你原来的列验证代码有错误(i未定义),先修正这部分,再整合宫格验证:
完整修改后的valid函数
def valid(board): s = 0 target = set('123456789') # 目标集合,包含1-9所有数字 # 验证每一行 for row in board: if set(row) == target: s += 1 # 验证每一列 for col in range(9): # 收集当前列的所有元素 column_values = [board[row][col] for row in range(9)] if set(column_values) == target: s += 1 # 验证每个3×3宫格 for row_start in range(0, 9, 3): for col_start in range(0, 9, 3): # 收集当前宫格的所有元素 grid_values = [] for r in range(row_start, row_start + 3): for c in range(col_start, col_start + 3): grid_values.append(board[r][c]) # 验证宫格是否符合要求 if set(grid_values) == target: s += 1 # 判断最终结果 if s == 27: print('valid') return True else: print('no') return False
代码说明
- 行验证:直接把每行转成集合,和包含1-9的目标集合对比,相等则说明该行符合要求。
- 列验证:通过列表推导式收集每一列的所有元素,同样转成集合对比目标集合。
- 宫格验证:用
row_start和col_start遍历每个宫格的左上角坐标(步长为3),然后遍历宫格内的3×3元素收集到列表中,再用集合验证是否符合要求,符合则s加1。 - 结果判断:当
s等于27(9行+9列+9宫格)时,棋盘有效,否则无效。
测试验证
调用valid(example)会输出valid,返回True,符合预期。
如果想保留你原来的count逻辑(为了理解基础逻辑),也可以把集合验证替换成你原来的多个count判断,比如对宫格的grid_values:
if (grid_values.count('1') == 1 and grid_values.count('2') == 1 and grid_values.count('3') == 1 and grid_values.count('4') == 1 and grid_values.count('5') == 1 and grid_values.count('6') == 1 and grid_values.count('7') == 1 and grid_values.count('8') == 1 and grid_values.count('9') == 1): s += 1
这样也能实现同样的效果,只是代码更冗长。
内容的提问来源于stack exchange,提问作者rooknoobski
相关产品推荐
相关产品推荐

