Search code examples
pythonchess

My chess-board validation program works, but gives an incorrect result


The program is supposed to print True or False depending on whether an arbitrary dictionary stored in a variable meets the criteria for a chess board. The criteria is as follows : A valid board will have exactly one black king and exactly one white king. Each player can only have at most 16 pieces, at most 8 pawns, and all pieces must be on a valid space from '1a' to '8h'; that is, a piece can’t be on space '9z'. The piece names begin with either a 'w' or 'b' to represent white or black, followed by 'pawn', 'knight', 'bishop', 'rook', 'queen', or 'king'. This function should detect when a bug has resulted in an improper chess board.

My program looks like this :

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))

The dictionary seems to meet the given criteria. However, the program prints ''False'' every time I try to run it.

Is there something that I'm missing here ?

Thank you so much in advance, and I apologize if it is too basic or broad of a question.


Solution

  • The problem is with loops such as:

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

    It is insisting that it starts with all of these digits, rather than with any of them. The loop can be replaced with:

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

    Note that the condition is inverted. If there is a match, then it breaks from the loop. If no matches are found, then the else block will be executed. Note the indentation here: the else relates to the for loop, not the if block, and will execute if the for loop completed without being broken out of.

    There were a couple of places with a similar issue.

    You also had one place where parentheses were needed:

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

    because the original without parentheses was equivalent to:

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

    because not has higher operator precedence than binary boolean operators such as or.

    Putting these fixes together gives:

    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))