Skip to content Skip to sidebar Skip to footer

Can I Use A Nested For Loop For An If-else Statement With Multiple Conditions In Python?

I have written a program that checks if a chess board is valid. In one part of my code I test, if the amounts of the pieces are correct. count is dictionary, which is an inventory

Solution 1:

First, I would recommend outsourcing this check to a dedicated function.

Second, you can use a dict with your expected max values, and use a comprehension with all() to perform the check more concisely.

max_counts = {
    'bking': 1,
    'bqueen': 1,
    'brook': 2,
    'bknight': 2,
    'bbishop': 2,
    'bpawn': 8,
    'wking': 1,
    'wqueen': 1,
    'wrook': 2,
    'wknight': 2,
    'wbishop': 2,
    'wpawn': 8
}

defboard_is_valid(count, board):
    returnlen(board) <= 32andall(
               count[piece] <= ct 
               for (piece, ct) in max_counts.items()
           )

If you want to be slightly less verbose with max_counts, you could try creating a dummy dict with the basic counts for king, queen, rook, etc., and make max_counts the result of adding two copies of that list, one with 'b' prefixed to each key and the other with 'w'. But I don't think thats necessary if this is the entire set of pieces.


Also consider that this may not be a foolproof method of validation for your chessboard. Pawns may promote into any other type of piece besides king, so having more than one queen or more than two rooks is technically possible.

Solution 2:

A simple way would be to encode the maxima for each category. The only special case is that there must be one king. Instead of having pieces as a list, make it a dict that maps the piece to the number of instances at the start of the game:

pieces = {'queen': 1, 'rook': 2, 'knight': 2, 'bishop': 2, 'pawn': 8, 'king': 1}

Second, by concatenating keys, you make your life more complicated. I would recommend making a nested dictionary, or a list with two dictionaries in it to contain black and white pieces separately:

count = {'b': {'king': 1, 'pawn': 3, 'bishop': 1},
         'w': {'king': 1, 'rook': 1, 'queen': 1}}

Checking is now much easier. First, verify that the keys of each dictionary in count is a subset of the allowed keys. You can do this using the fact that dict.keys returns a set-like object:

count['b'].keys() < pieces.keys()

Next, check that the values for corresponding keys are within the allowed range:

all(pieces[k] >= v for k, v in count['b'].items())

And finally, check that there is a king on the board:

count['b'].get('king') == 1

You should not use count['b']['king'] because that will raise a KeyError when there is no king on the board. It's much more consistent to return False, as you do for all other invalid boards.

Assuming you go with the structure of count I propose, here is how I would write the check:

def validate(count):
    def check_side(side):
        return side.keys() < pieces.keys() and all(pieces[k] >= v for k, v in side.items()) and side.get('king') == 1
    return all(check(v) for v in count.values())

The operators and and all are short-circuiting, so if the answer is False, this will return as early as possible.

Notice also that with this approach you no longer need colors. The information is stored in count.keys(). Redundancy of information is usually not a great idea.

Post a Comment for "Can I Use A Nested For Loop For An If-else Statement With Multiple Conditions In Python?"