首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python中的Sudoku Checker

Python中的Sudoku Checker
EN

Code Review用户
提问于 2021-11-02 22:25:53
回答 1查看 211关注 0票数 1

我用Python编写了以下Sudoku检查器。我觉得这可以写得更短,也许更有效率。尤其是与square_columns有关的部分。

代码语言:javascript
复制
rows = []
columns = []
squares = []
sudoku_sets = []

for i in range(9):
    if i == 0:
        row = input("Input the sudoku values row by row.\n")
    else:
        row = input("")
    while len(row) != 9 or not row.isnumeric():
        row = input(f"Wrong input. Please insert 9 numbers for row number {i+1}.\n")
    rows.append(row)

for i in range(len(rows)):
    column = ''
    for j in range (len(rows)):
        column += rows[j][i]
    columns.append(column)

for i in range(0,7,3):
    square_columns = ["", "", ""]
    for j in range(3):
        square_columns[0] += rows[j+i][:3]
        square_columns[1] += rows[j+i][3:6]
        square_columns[2] += rows[j+i][6:9]
    for square in square_columns:
        squares.append(square)

sudoku_sets.append(rows)
sudoku_sets.append(columns)
sudoku_sets.append(squares)

def check_sudoku(sets):
    for s in sets:
        for item in s:
            if len(item) == len(set(item)):
                continue
            else:
                return "No"
    return "Yes"

print(check_sudoku(sudoku_sets))
EN

回答 1

Code Review用户

回答已采纳

发布于 2021-11-04 17:13:50

你的代码看起来不错。但仍有一些改进的余地。

开头没有在单个块中定义变量

这是古代C的一种风格,现在的规则是声明变量

  • 在尽可能小的范围内
  • 尽可能晚

由于您(当前)有一个全局范围,所以只适用后一条规则。如果你这样做了

代码语言:javascript
复制
sudoku_sets = []
sudoku_sets.append(rows)
sudoku_sets.append(columns)
sudoku_sets.append(squares)

如果sudoku_sets在某个地方被触及,读者不必扫描上面的30行。它所持有的东西是绝对清楚的。

不试图超越语言

代码语言:javascript
复制
for i in range(0,7,3):

有点奇怪。如果你想按3的步骤循环9的范围,就这样写吧。

代码语言:javascript
复制
for i in range(0, 9, 3):

该语言旨在允许以一种不需要容易出错的手工编织和篡改的方式编写代码。

常数

您的检查程序只适用于9的平方大小。这可以在文件的早期说明。虽然您的一些代码试图不确定大小,但是有许多行硬编码数字只适用于大小9。

代码语言:javascript
复制
# rows fixed to nine 
for i in range(9):

# cols agnostic (but fixed to square)
for i in range(len(rows)):

函数

功能是很好的缩小范围和引入更好的可读性。您的代码很好(!)结构成原子任务。但是,我们必须阅读和理解代码才能识别。我们可以对每个块进行改进和注释,也可以通过将块提取到具有良好名称的函数中进行很大的改进。我们做3项功能

代码语言:javascript
复制
def read_rows():
    ...
    return rows
    
def make_cols(rows):
    ...
    return cols

def make_squares(rows):
    ...
    return squares

该函数是独立的,命名为任务并声明依赖项。make_squaresrows做正方形。它不需要columns,也不篡改任何其他变量。当我们使用这些函数时,我们会得到一个可读性很好的顶层代码体。

代码语言:javascript
复制
rows = read_rows()
columns = make_cols(rows)
squares =  make_squares(rows)
check_sudoku_sets([rows, columns, squares])

此外,令人讨厌的列表首字母缩写也已消失。它们位于指定的函数中,不再干扰顶级作用域。

sudoku_sets

..。是个坏名声。它不能解释它持有什么。也没有必要这样做,因为行、科尔和方格在检查中没有不同的处理方式。所有三个地区都有“区域”。所以我们可以

代码语言:javascript
复制
regions = rows + columns + squares

并将检查简化为

代码语言:javascript
复制
def check_sudoku(regions):
    for item in regions:
        if len(item) == len(set(item)):
            continue
        else:
            return "No"
    return "Yes"

在算法中不做I/O

这降低了可用性和可测试性。在没有输出的情况下,您几乎在check_sudoku中正确地做到了这一点。但是,当您返回为输出设计的字符串时,仍然存在到输出的耦合。返回bool并将函数重命名为“谓词样式”。

代码语言:javascript
复制
def is_valid_sudoku(regions):
    for item in regions:
        if len(item) == len(set(item)):
            continue
        else:
            return False
    return True

可以缩短为

代码语言:javascript
复制
def is_valid_sudoku(regions):
    return all((len(item) == len(set(item)) for item in regions))

到字符串的转换应在输出中完成。

结果到目前为止

代码现在看起来像

代码语言:javascript
复制
# this implementation works for size = 9 only

def read_rows():
    rows = []
    for i in range(9):
        if i == 0:
            row = input("Input the sudoku values row by row.\n")
        else:
            row = input("")
        while len(row) != 9 or not row.isnumeric():
            row = input(f"Wrong input. Please insert 9 numbers for row number {i + 1}.\n")
        rows.append(row)
    return rows


def make_cols(rows):
    columns = []
    for i in range(len(rows)):
        column = ''
        for j in range(len(rows)):
            column += rows[j][i]
        columns.append(column)
    return columns


def make_squares(rows):
    squares = []
    for i in range(0, 7, 3):
        square_columns = ["", "", ""]
        for j in range(3):
            square_columns[0] += rows[j + i][:3]
            square_columns[1] += rows[j + i][3:6]
            square_columns[2] += rows[j + i][6:9]
        for square in square_columns:
            squares.append(square)
    return squares


def is_valid_sudoku(regions):
    return all((len(item) == len(set(item)) for item in regions))


rows = read_rows()
columns = make_cols(rows)
squares = make_squares(rows)
regions = rows + columns + squares
text = "Yes" if is_valid_sudoku(regions) else "No"
print(text)

避免循环索引,但循环元素。在make_cols中,不要像

代码语言:javascript
复制
for j in range(len(rows)):
    column += rows[j][i]

但要做

代码语言:javascript
复制
for row in rows:
    column += row[i]

如果您需要索引以及循环,如

代码语言:javascript
复制
for i, e in enumerate(some_list):

算法

你关心的是make_squares。一个更简单的实现是按索引遍历所有单元格,并将找到的数字追加到相应的平方。

代码语言:javascript
复制
def make_squares(rows):
    squares = ["" for _ in range(9)]
    for y, r in enumerate(rows):
        for x, e in enumerate(r):
            squares[(y//3)*3 + x//3] += e
    return squares

更挑剔的

在您的输入函数中,有第一个输入行的特例--将其从循环中取出,如下所示

代码语言:javascript
复制
def read_rows():
    print("Input the sudoku values row by row")
    rows = []
    for i in range(9):
        row = input("")
        ...

此外,您不检查有效的符号完全,你也接受数字'0‘。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/269669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档