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 of the board I want to check. For example (b stands for black, w fo white):
count = {'bking': 1, 'wking': 1, 'bpawn': 3, 'bbishop': 1, 'wrook': 1, 'wqueen': 1}
the possible colors and pieces are available in lists:
colors = ['b', 'w']
pieces = ['queen', 'rook', 'knight', 'bishop', 'pawn']
I have the following ugly if-else statement with multiple conditions:
if count['bking'] == 1 and \
count['wking'] == 1 and \
count.get('bqueen', 0) <= 2 and \
count.get('wqueen', 0) <= 2 and \
count.get('bpawn', 0) <= 8 and \
count.get('wpawn', 0) <= 8 and \
count.get('brook', 0) <= 2 and \
count.get('wrook', 0) <= 2 and \
count.get('bknight', 0) <= 2 and \
count.get('wknight', 0) <= 2 and \
count.get('bbishop', 0) <= 2 and \
count.get('wbishop', 0) <= 2 and \
len(board) <= 32:
return True
else:
return False
Is there a way to simplify this if-else structure with a nested for loop? I realized that the lines with the get() method are very repetitive. My idea was to make an outer for loop that iterates over the colors and an inner loop that iterates over the pieces. The first argument in the get() call is a concatenation of an item in the colors list with an item in the pieces list. Is there a way to do that?
Is there another way to make this if-else statement more pythonic?
This is my first attempt:
for c in colors:
for p in pieces[:4]:
if count.get(c + p, 0) <= 2:
if count.get(c + pieces[-1], 0) <= 8:
return = True
else:
return = False
But that does not work, I get a SyntaxError or an IndentationError.
My original code that seems to work is the following:
# chessDictValidator.py
def boardInventory(board):
# Makes an inventory of the board to be evaluated.
count = {}
for value in board.values():
count.setdefault(value, 0)
count[value] += 1
return count
def boardCounter(board):
# Checks if amounts of pieces are valid.
count = boardInventory(board)
if count['bking'] == 1 and \
count['wking'] == 1 and \
count.get('bqueen', 0) <= 2 and \
count.get('wqueen', 0) <= 2 and \
count.get('bpawn', 0) <= 8 and \
count.get('wpawn', 0) <= 8 and \
count.get('brook', 0) <= 2 and \
count.get('wrook', 0) <= 2 and \
count.get('bknight', 0) <= 2 and \
count.get('wknight', 0) <= 2 and \
count.get('bbishop', 0) <= 2 and \
count.get('wbishop', 0) <= 2 and \
len(board) <= 32:
return True
else:
return False
def fieldValidator(board):
# Checks if the board contains valid fields.
fieldOK = 0
for key in board.keys():
if key[0] in fieldInt and key[1] in fieldChar:
fieldOK += 1
else:
return False
if fieldOK == len(board):
return True
def pieceValidator(board):
# Checks if the pieces are spelled correctly.
pieceOK = 0
for value in board.values():
if value[0] in pieceColor and value[1:] in pieces:
pieceOK += 1
else:
return False
if pieceOK == len(board):
return True
def boardValidator(board):
# Checks if the board is valid, depending on the tests above. Prints an error message when board is invalid.
valid = 'This is a valid chess board!'
invalid = 'Invalid chess board!'
wrong = 'There is a wrong {0} in your board!'
numPieces = 'There is something wrong with the allowed amount of pieces!'
if fieldValidator(board) and pieceValidator(board) and boardCounter(board):
print(valid)
elif fieldValidator(board) == False:
print(invalid, wrong.format('field'))
elif pieceValidator(board) == False:
print(invalid, wrong.format('piece'))
elif boardCounter(board) == False:
print(invalid, numPieces)
board = {
'1b': 'bking',
'6a': 'wqueen',
'3f': 'brook',
'4h': 'bknight',
'3e': 'wking',
'6d': 'wbishop',
'2g': 'wbishop',
'5c': 'bpawn',
'8g': 'bpawn',
'7b': 'bpawn',
}
fieldInt = ['1', '2', '3', '4', '5', '6', '7', '8']
fieldChar = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
pieceColor = ['b', 'w']
pieces = ['king', 'queen', 'knight', 'rook', 'bishop', 'pawn']
boardValidator(board)