Chess Dictionary Validator (Python) (Automate The Boring Stuff) This is an exercise in the Automate The Boring Stuff book. I am supposed to create a function  that takes a dictionary argument that represents a chess board (ex: {'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', etc.}) and returns True or False depending on if the board is valid.
A valid board will have (A) exactly one black king and exactly one white king. (B) Each player can only have at most 16 pieces, (C) at most 8 pawns, and (D) all pieces must be on a valid space from '1a' to '8h'; that is, a piece can’t be on space '9z'. (E) 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.
#Example dictionary of coordinates (keys) and pieces (values)
#my_board = {&quot;1a&quot;:&quot;wking&quot;, &quot;2a&quot;:&quot;bking&quot;, &quot;8b&quot;:&quot;wpawn&quot;, &quot;3a&quot;:&quot;wpawn&quot;}

def isValidChessBoard(board):
    #Creating a dictionary of pieces (keys) and the number of pieces (values) 
    num_pieces = {}
    list_pieces = [&quot;bpawn&quot;, &quot;bking&quot;, &quot;bqueen&quot;, &quot;brook&quot;, &quot;bbishop&quot;, &quot;bknight&quot;, &quot;wpawn&quot;, &quot;wking&quot;, &quot;wqueen&quot;, &quot;wrook&quot;, &quot;wbishop&quot;, &quot;wknight&quot;]
    for v in board.values():
        num_pieces.setdefault(v, 0)
        num_pieces[v] = num_pieces[v] + 1
    for i in list_pieces:
        if i not in num_pieces:
            num_pieces.setdefault(i, 0)
    #Making sure there is exactly one king on each side
    if (num_pieces[&quot;wking&quot;] != 1) or (num_pieces[&quot;bking&quot;] != 1):
        return False
    #Making sure there are no more than 8 pawns on each side
    if (&quot;bpawn&quot; or &quot;wpawn&quot; in num_pieces) and (num_pieces[&quot;bpawn&quot;] or num_pieces[&quot;wpawn&quot;]) &gt; 8:
        return False
    #Making sure every piece is apprpriately named (b/w + king/queen/rook/pawn/knight/bishop)
    for j in num_pieces:
        if j not in list_pieces:
            return False
    #Making sure there are no more than 16 pieces on each side
    if num_pieces[&quot;bpawn&quot;] + num_pieces[&quot;bking&quot;]  + num_pieces[&quot;bqueen&quot;] +  num_pieces[&quot;brook&quot;] +  num_pieces[&quot;bbishop&quot;]  + num_pieces[&quot;bknight&quot;] &gt; 16:
        return False
    if num_pieces[&quot;wpawn&quot;] + num_pieces[&quot;wking&quot;]  + num_pieces[&quot;wqueen&quot;] +  num_pieces[&quot;wrook&quot;] +  num_pieces[&quot;wbishop&quot;]  + num_pieces[&quot;wknight&quot;] &gt; 16:
        return False
    #Making sure that the board coordinates are all between (a-h, and 1-8)
    in_range = 0
    possible_coordinates = []
    for i in range(1, 9):
        for j in [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;, &quot;f&quot;, &quot;g&quot;, &quot;h&quot;]:
            possible_coordinates.append(str(i)+str(j))
    for k in board.keys():
        if k in possible_coordinates:
            in_range = in_range + 1      
    if len(board) != in_range:
        return False
    return True

if isValidChessBoard(my_board) == True:
    print(&quot;Valid Board&quot;)
else:
    print(&quot;Invalid Board&quot;)


I know that the code works, but I was wondering if there were any faux-pas that I am implementing, or if there is anything I could obviously do to make it cleaner. Thanks!
As you said the code works - there might be additional conditions for a valid board, that you are not checking for which you will be able to expand on using the same structure. I looked up the chapter from the book you mention and your implementation meets the requirements outlined there.
Since this is Python, there are more than one way to implement the requirements, at a minimum I'd recommend refactoring the code to be self documenting instead of relying on comments. This will require only minor refactoring of your code.
Then building on that may be consider taking a functional approach and utilizing python builtins. YMMV - here is my implementation, it is not perfect, but that is not the intent here.
def checkCriteria(pieces, fn, cnt):
    if len(list(filter(fn, pieces))) &gt; cnt:
        return False
    
    return True

def checkValidPositions(input_pos):
    positions = set()
    for col in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']:
        for row in range(1, 9):
            positions.add(str(row) + col)

    return all(pos in positions for pos in input_pos)

def checkMaxPiecesByColor(pieces):
    return all(checkCriteria(pieces, lambda piece: len(piece) &gt; 0 and piece[0] == ch, 16) for ch in ['w', 'b'])

def checkKingCount(pieces):
    return all(checkCriteria(pieces, lambda piece: piece == king, 1) for king in ['bking', 'wking'])

def checkPawnCount(pieces):
    return all(checkCriteria(pieces, lambda piece: piece == pawn, 8) for pawn in ['bpawn', 'wpawn'])

def checkValidPieces(pieces):
    valid_pieces = set()
    for color in ['w', 'b']:
        for piece in ['pawn', 'knight', 'bishop', 'rook', 'queen', 'king']:
            valid_pieces.add(color + piece)

    return len(pieces - valid_pieces) == 0

def isValidChessBoard(board):
    pieces = board.values()
    positions = board.keys()

    if not checkValidPositions(positions):
        return False
        
    if not checkMaxPiecesByColor(pieces):
        return False
    
    if not checkKingCount(pieces):
        return False
        
    if not checkPawnCount(pieces):
        return False
    
    if not checkValidPieces(set(pieces) - set([''])):
        return False
    
    return True