【问题标题】:My chess-board validation program works, but gives an incorrect result我的棋盘验证程序有效,但结果不正确
【发布时间】:2020-10-03 08:27:33
【问题描述】:

程序应该根据存储在变量中的任意字典是否满足棋盘标准来打印 True 或 False。标准如下: 一个有效的棋盘只有一个黑王和一个白王。每个玩家最多只能有16个棋子,最多8个棋子,并且所有棋子必须在'1a'到'8h'的有效空间上;也就是说,一块不能在空间“9z”上。棋子名称以“w”或“b”开头,表示白色或黑色,然后是“pawn”、“knight”、“bishop”、“rook”、“queen”或“king”。当错误导致棋盘不正确时,此函数应进行检测。

我的程序如下所示:

board = {'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop',\
'5h': 'bqueen', '3e': 'wking'}
def isValidChessBoard(_board_):
    gen_num=0
    pawn_num=0
    wking_num=0
    bking_num=0
    letters=['a','b','c','d','e','f','g','h']
    pieces=['pawn','knight','bishop','rook','king','queen']
    for v in _board_.values():
        gen_num+=1
    if gen_num > 16:
        return False
    for v in _board_.values():
        if v.endswith('pawn'):
            pawn_num+=1
    if pawn_num > 8:
        return False
    for v in _board_.values():
        if v =='wking':
            wking_num+=1
        if v =='bking':
            bking_num+=1
    if wking_num!=1 or bking_num!=1:
        return False
    for k in _board_.keys():
        for i in range(1,9):
            if not k.startswith(str(i)):
                return False
    for k in _board_.keys():
        for i in letters:
            if not k.endswith(i):
                return False
    for v in _board_.values():
        if not v.startswith('b') or v.startswith('w'):
            return False
    for v in _board_.values():
        for i in pieces:
            if not v.endswith(i):
                return False
    return True

print(isValidChessBoard(board))

字典似乎符合给定的标准。但是,每次我尝试运行它时,程序都会打印“False”。

这里有什么我遗漏的吗?

非常感谢您,如果问题太基本或太宽泛,我深表歉意。

【问题讨论】:

    标签: python chess


    【解决方案1】:

    如果您暂时将所有 return False 替换为 raise Exception,则很容易看出哪个部分返回 False。

    这样做之后,我们可以看到这部分是问题:

    for k in _board_.keys():
        for i in range(1,9):
            if not k.startswith(str(i)):
                return False
    

    不确定您要在那里做什么,我猜您是在尝试检查棋子的数量是否在 1 到 8 之间?进行这项工作的一个小改动是:

    for k in _board_.keys():
        for i in range(1,9):
            if k.startswith(str(i)):
                break
        else:
            return False
    

    如果我们找到匹配项,我们会在哪里中断,但如果没有中断,则返回 false。继续前进,我们发现您在另外两个地方犯了这个错误。

    我们也可以看到这里的逻辑不太好:

    if not v.startswith('b') or v.startswith('w'):
    

    应该是这样的:

    if not v.startswith('b') and not v.startswith('w'):
    

    把所有这些放在一起你会得到这个:

    board = {'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop',\
    '5h': 'bqueen', '3e': 'wking'}
    def isValidChessBoard(_board_):
        gen_num=0
        pawn_num=0
        wking_num=0
        bking_num=0
        letters=['a','b','c','d','e','f','g','h']
        pieces=['pawn','knight','bishop','rook','king','queen']
        for v in _board_.values():
            gen_num+=1
        if gen_num > 16:
            raise Exception
        for v in _board_.values():
            if v.endswith('pawn'):
                pawn_num+=1
        if pawn_num > 8:
            raise Exception
        for v in _board_.values():
            if v =='wking':
                wking_num+=1
            if v =='bking':
                bking_num+=1
        if wking_num!=1 or bking_num!=1:
            raise Exception
        for k in _board_.keys():
            for i in range(1,9):
                if k.startswith(str(i)):
                    break
            else:
                raise Exception
        for k in _board_.keys():
            for i in letters:
                if k.endswith(i):
                    break
            else:
                raise Exception
    
        for v in _board_.values():
            if not v.startswith('b') and not v.startswith('w'):
                raise Exception
    
        for v in _board_.values():
            for i in pieces:
                if v.endswith(i):
                    break
            else:
                raise Exception
        return True
    
    print(isValidChessBoard(board))
    

    我建议保留 raise Exceptions 直到它完成,此时您只需将它们替换为 return False

    【讨论】:

    • 这正是我想要完成的,是的。我还是不太明白它有什么问题?我第一次运行程序时,同一个块给出了一条错误消息,但那是因为我没有将“i”传递给字符串函数。在我这样做之后,程序运行但打印了 False...
    • 我扩展了我的答案。如果您不断收到错误,则需要练习调试。将print() 语句放在任何地方或提高Exceptions 以便您可以跟踪代码跟踪
    • @Mandera 例外是一个非常好的建议。我已经努力在每个返回语句之前放置不同的“打印”语句(在得出与您关于代码本身相同的结论之前),但是快速搜索和替换 raise Exception 肯定更快更容易。
    • @alaniwi 哈哈,我也在做同样的事情,但是谢谢!
    【解决方案2】:

    问题在于循环,例如:

            for i in range(1,9):
                if not k.startswith(str(i)):
                    return False
    

    它坚持它以 all 这些数字开头,而不是以 any 开头。循环可以替换为:

            for i in range(1,9):
                if k.startswith(str(i)):
                    break
            else:
                return False
    

    请注意,条件是相反的。如果有 is 匹配,则它会从循环中中断。如果找到 no 匹配项,则将执行 else 块。注意这里的缩进:elsefor 循环相关,不是if 块,如果 for 循环完成而没有被中断,则将执行。

    有几个地方有类似的问题。

    你还有一个地方需要括号:

            if not (v.startswith('b') or v.startswith('w')):
    

    因为不带括号的原文等价于:

            if (not v.startswith('b')) or v.startswith('w'):
    

    因为not 的运算符优先级高于or 等二元布尔运算符。

    将这些修复放在一起给出:

    board = {'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop',\
    '5h': 'bqueen', '3e': 'wking'}
    def isValidChessBoard(_board_):
        gen_num=0
        pawn_num=0
        wking_num=0
        bking_num=0
        letters=['a','b','c','d','e','f','g','h']
        pieces=['pawn','knight','bishop','rook','king','queen']
        for v in _board_.values():
            gen_num+=1
        if gen_num > 16:
            return False
        for v in _board_.values():
            if v.endswith('pawn'):
                pawn_num+=1
        if pawn_num > 8:
            return False
        for v in _board_.values():
            if v =='wking':
                wking_num+=1
            if v =='bking':
                bking_num+=1
        if wking_num!=1 or bking_num!=1:
            return False
        for k in _board_.keys():
            for i in range(1,9):
                if k.startswith(str(i)):
                    break
            else:
                return False
        for k in _board_.keys():
            for i in letters:
                if k.endswith(i):
                    break
            else:
                return False
        for v in _board_.values():
            if not (v.startswith('b') or v.startswith('w')):
                return False
        for v in _board_.values():
            for i in pieces:
                if v.endswith(i):
                    break
            else:
                return False
        return True
    
    print(isValidChessBoard(board))
    

    【讨论】:

    • 为什么 'if not v/k.ends/startswith(i)' 不起作用?或者更准确地说,为什么它会给出一个错误的值?
    • @WilliamFrog8 问题在于,当它遍历所有数字时,它会在找到第一个 not 开头的数字时立即返回 False(其中有七个),即使它确实以八个数字之一开头。
    • @WilliamFrog8 因此,修改后的版本循环测试它是否确实以数字开头,如果没有找到它只返回False。
    • @WilliamFrog8 和你测试字母和碎片的问题完全相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多