Premier article, nouveau dans la programmation et s'amuser! Tous les commentaires sur ce post et mes questions sont les bienvenus.
Je travaille sur Automate the Boring Stuff et j'attaque le premier problème du chapitre 5 Chess Dictionary Validator .
Dans ce chapitre, nous avons utilisé la valeur du dictionnaire {'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'} pour représenter un échiquier. Ecrivez une fonction nommée isValidChessBoard () qui prend un argument de dictionnaire et retourne True ou False selon que la carte est valide.
Un plateau valide aura exactement un roi noir et exactement un roi blanc. Chaque joueur ne peut avoir au maximum que 16 pièces, au plus 8 pions, et toutes les pièces doivent être sur une case valide de «1a» à «8h»; c'est-à-dire qu'une pièce ne peut pas être sur l'espace «9z». Les noms des pièces commencent par un «w» ou «b» pour représenter le blanc ou le noir, suivi de «pion», «chevalier», «évêque», «tour», «reine» ou «roi». Cette fonction devrait détecter lorsqu'un bug a entraîné un échiquier incorrect.
mes questions et mon code:
if i[0] == 'b': erreur parce que les espaces d'échecs qui sont des valeurs de chaîne vides n'ont pas de caractère à i [0]. Quelle est la meilleure façon d'exprimer / d'évaluer des valeurs vides? Si c'est avec "", dois-je ajouter une condition de tête dans la boucle qui évalue la valeur == "", puis "continuer"?if 'bking' or 'wking' not in board.values(): Si j'essaye cela, le résultat de l'instruction est True; Cependant, le dictionnaire contient les deux valeurs, alors ne devrait-il pas être évalué à False et maintenir le code en cours d'exécution?def isValidChessBoard(board):
while True:
blackPieces = 0
whitePieces = 0
wpawn = 0
bpawn = 0
letterAxis = ('a','b','c','d','e','f','g','h')
pieceColour = ('b','w')
pieceType = ('pawn','knight','bishop','rook','queen','king')
#one black king and one white king
if 'bking' not in board.values():
print('KingError')
return False
break
if 'wking' not in board.values():
print('KingError')
return False
break
#each player has <= 16 pieces
for i in board.values():
if i[0] == 'b':
blackPieces+=1
if i[0] == 'w':
whitePieces+=1
if whitePieces >= 17:
print('TotalPieceError')
return False
break
if blackPieces >= 17:
print('TotalPieceError')
return False
break
#each player has <= 8 pawns
for i in board.values():
if i == 'wpawn':
wpawn+=1
elif i == 'bpawn':
bpawn+=1
if wpawn or bpawn >= 9:
print('PawnError')
return False
break
#all pieces must be on valid space from '1a' to '8h'
for i in board.keys():
if int(i[0]) >= 9:
print('SpacesError')
return False
break
if i[1] not in letterAxis:
print('yAxisError')
return False
break
#piece names begin with 'w' or 'b'
for i in board.values():
if i[0] not in pieceColour:
print('WhiteOrBlackError')
return False
break
#piece names must follow with 'pawn', 'knight', 'bishop', 'rook', 'queen', 'king'
for i in board.values():
if i[1:] not in pieceType:
print('PieceTypeError')
return False
return 'This board checks out'
board = {'1a': 'bking','2a': 'bqueen','3a': 'brook','4a': 'brook',
'5a': 'bknight','6a': 'bknight','7a':'bbishop','8a': 'bbishop',
'1b': 'bpawn','2b': 'bpawn','3b': 'bpawn','4b':'bpawn',
'5b': 'bpawn','6b': 'bpawn','7b': 'bpawn','8b': 'bpawn',
'1c': 'wking','2c': 'wqueen','3c': 'wrook','4c': 'wrook',
'5c': 'wbishop','6c': 'wbishop','7c': 'wknight','8c':'wknight',
'1e': 'wpawn','2e': 'wpawn','3e': 'wpawn','4e': 'wpawn',
'5e': 'wpawn','6e': 'wpawn','7e': 'wpawn','8e': 'wpawn',
'1f': '','2f': '','3f': '','4f': '','5f': '','6f': '','7f': '','8f': '',
'1g': '','2g': '','3g': '','4g': '','5g': '','6g': '','7g': '','8g': '',
'1h': '','2h': '','3h': '','4h': '','5h': '','6h': '','7h': '','8h': '',}
print(isValidChessBoard(board))
Error:
Traceback (most recent call last):
line 23, in isValidChessBoard
if i[0] == 'b':
IndexError: string index out of range
5 Réponses :
Voici ma version:
Retirez votre while True: boucle et toute votre break
Utilisez le dictionnaire pour traiter plus facilement les chèques en noir et blanc (pas besoin de plus de deux si pour chaque couleur)
Vérifier la valeur de position dans la même pièce de contrôle de boucle
Ajout d'un chèque pour un seul roi de chaque couleur
Vous pouvez également vérifier facilement chaque nombre de types de pièces à l'aide d'un dictionnaire avec le type de pièce comme clé.
def isValidChessBoard(board):
piecesCount = {'b': 0, 'w': 0}
pawnCount = {'b': 0, 'w': 0}
hasKing = {'b': False, 'w': False}
letterAxis = ('a','b','c','d','e','f','g','h')
pieceColour = ('b','w')
pieceType = ('pawn','knight','bishop','rook','queen','king')
#each player has <= 16 pieces
for pos, i in board.items():
# check position value
#all pieces must be on valid space from '1a' to '8h'
if int(pos[0]) >= 9:
print('SpacesError')
return False
if pos[1] not in letterAxis:
print('yAxisError')
return False
# check piece data
if i != "":
#piece names begin with 'w' or 'b'
if i[0] not in pieceColour:
print('WhiteOrBlackError')
return False
thisPieceColour = i[0]
piecesCount[thisPieceColour] += 1
if piecesCount[thisPieceColour] >= 17:
print('TotalPieceError')
return False
#piece names must follow with 'pawn', 'knight', 'bishop', 'rook', 'queen', 'king'
thisPieceType = i[1:]
if thisPieceType not in pieceType:
print('PieceTypeError')
return False
elif thisPieceType == 'pawn':
pawnCount[thisPieceColour] += 1
#each player has <= 8 pawns
if pawnCount[thisPieceColour] >= 9:
print('PawnError')
return False
elif thisPieceType == 'king':
# one black king and one white king
if hasKing[thisPieceColour] == True:
print("AlreadyHasKingError")
hasKing[thisPieceColour] = True
if list(hasKing.values()) != [True, True]:
print("MissingKingError")
return False
return 'This board checks out'
board = {'1a': 'bking','2a': 'bqueen','3a': 'brook','4a': 'brook',
'5a': 'bknight','6a': 'bknight','7a':'bbishop','8a': 'bbishop',
'1b': 'bpawn','2b': 'bpawn','3b': 'bpawn','4b':'bpawn',
'5b': 'bpawn','6b': 'bpawn','7b': 'bpawn','8b': 'bpawn',
'1c': 'wking','2c': 'wqueen','3c': 'wrook','4c': 'wrook',
'5c': 'wbishop','6c': 'wbishop','7c': 'wknight','8c':'wknight',
'1e': 'wpawn','2e': 'wpawn','3e': 'wpawn','4e': 'wpawn',
'5e': 'wpawn','6e': 'wpawn','7e': 'wpawn','8e': 'wpawn',
'1f': '','2f': '','3f': '','4f': '','5f': '','6f': '','7f': '','8f': '',
'1g': '','2g': '','3g': '','4g': '','5g': '','6g': '','7g': '','8g': '',
'1h': '','2h': '','3h': '','4h': '','5h': '','6h': '','7h': '','8h': '',}
print(isValidChessBoard(board))
Voyez comment j'ai refactoré le code
Vérifiez simplement if i != "" Avant d'y accéder
Eh bien, vous ne pouvez pas le faire comme ça parce que vous voulez comparer deux valeurs à plusieurs autres. C'est possible, comme par exemple en utilisant set.intersection, mais semble exagéré dans votre cas.
Edit: Lorsque vous définissez un nombre valide, cela ne prend pas en compte le fait que vous pourriez obtenir un pion à l'autre extrémité du plateau et vous retrouver avec deux reines, bien que je ne sache pas comment vous pouvez résoudre ce problème sans provoquer le programme pour accepter des réponses bancales (comme deux reines au début d'une partie par exemple). Toute aide ici serait appréciée!
Puisque vous avez demandé s'il y avait une alternative, je vous présente ce qui suit.
Pas
Code
def isValidChessBoard(board):
"""Validate counts and location of pieces on board"""
# Define pieces and colors
pieces = ['king','queen','rook', 'knight','bishop', 'pawn']
colors = ['b', 'w']
# Set of all chess pieces
all_pieces = set(color+piece for piece in pieces for color in colors)
# Define valid range for count of chess pieces by type (low, high) tuples
valid_counts = {'king': (1, 1),
'queen': (0, 1),
'rook': (0, 2),
'bishop': (0, 2),
'knight': (0, 2),
'pawn': (0, 8)}
# Get count of pieces on the board
piece_cnt = {}
for v in board.values():
if v in all_pieces:
piece_cnt.setdefault(v, 0)
piece_cnt[v] += 1
# Check if there are a valid number of pieces
for piece in all_pieces:
cnt = piece_cnt.get(piece, 0)
lo, hi = valid_counts[piece[1:]]
if not lo <= cnt <= hi: # Count needs to be between lo and hi
if lo != hi:
print(f"There should between {lo} and {hi} {piece} but there are {cnt}")
else:
print(f"There should be {lo} {piece} but there are {cnt})")
return False
# Check if locations are valid
for location in board.keys():
row = int(location[:1])
column = location[1:]
if not ((1 <= row <= 8) and ('a' <= column <= "h")):
print(f"Invaid to have {board[location]} at postion {location}")
return False
# Check if all pieces have valid names
for loc, piece in board.items():
if piece:
if not piece in all_pieces:
print(f"{piece} is not a valid chess piece at postion {loc}")
return False
return True
Les seules choses à comparer sont: A. Le nombre de pions (doit être <= 8) B. Le nombre de rois (doit être == 2) C. Les clés dans le dictionnaire D. Le nombre total de pièces (doit être <= 16). Cela couvre tous les échiquiers possibles, puis certains qui seront limités par le jeu.
Étant donné que la question du validateur de dictionnaire d'échecs ne nécessite pas d'indiquer l'emplacement de l'erreur sur l'échiquier, voici ma réponse:
def valid_chess_board(board):
bpieces, wpieces = 0, 0
pieces = ("king", "queen", "rook", "bishop", "knight", "pawn")
board_pieces = list(board.values())
# Checking the kings
if board_pieces.count("bking") != 1 or board_pieces.count("wking") != 1:
return False
# Checking the pawns
if board_pieces.count("bpawn") > 8 or board_pieces.count("wpawn") > 8:
return False
# Checking the colors
for p in board_pieces:
if p[0] == "b" and p[1:] in pieces:
bpieces += 1
elif p[0] == "w" and p[1:] in pieces:
wpieces += 1
else:
return False
# Checking the pieces
if bpieces > 16 or wpieces > 16:
return False
# Checking the spaces
for s in board:
if s[0] not in "12345678" or s[1] not in "abcdefgh":
return False
return True
chess_board = {
"1a": "wrook",
"2a": "wpawn",
"6a": "bpawn",
"8a": "brook",
"2b": "wpawn",
"5b": "bpawn",
"1c": "wbishop",
"2c": "wbishop",
"3c": "wpawn",
"6c": "bknight",
"7c": "bpawn",
"1d": "wqueen",
"2d": "wknight",
"5d": "bpawn",
"8d": "bqueen",
"6e": "bbishop",
"7e": "bbishop",
"1f": "wrook",
"2f": "wpawn",
"3f": "wknight",
"6f": "bknight",
"8f": "brook",
"1g": "wking",
"2g": "wpawn",
"7g": "bpawn",
"8g": "bking",
"2h": "wpawn",
"7h": "bpawn",
}
print(valid_chess_board(chess_board))
Ma solution - J'ai utilisé des ensembles pour vérifier les espaces valides, mais cela pourrait également être réalisé avec des listes.
board = {'1a': 'wrook', '1b': 'wknight', '1c': 'wbishop', '1d': 'wqueen', '1e': 'wking', '1f': 'wbishop',
'1g': 'wknight', '1h': 'wrook','2a': 'wpawn', '2b': 'wpawn', '2c': 'wpawn', '2d': 'wpawn', '2e': 'wpawn',
'2f': 'wpawn', '2g': 'wpawn', '2h': 'wpawn', '3a': '', '3b': '', '3c': '', '3d': '', '3e': '', '3f': '',
'3g': '', '3h': '', '4a': '', '4b': '', '4c': '', '4d': '', '4e': '', '4f': '', '4g': '', '4h': '',
'5a': '', '5b': '', '5c': '', '5d': '', '5e': '', '5f': '', '5g': '', '5h': '',
'6a': '', '6b': '', '6c': '', '6d': '', '6e': '', '6f': '', '6g': '', '6h': '',
'7a': 'bpawn', '7b': 'bpawn', '7c': 'bpawn', '7d': 'bpawn', '7e': 'bpawn', '7f': 'bpawn', '7g': 'bpawn', '7h': 'bpawn',
'8a': 'brook', '8b': 'bknight', '8c': 'bbishop' , '8d': 'bqueen', '8e': 'bking', '8f': 'bbishop',
'8g': 'bknight','8h': 'brook'}
def isValidChessBoard(board_dict):
#check for 1 black king and 1 white king
bking=0
wking=0
for king in board_dict.values():
if king == 'bking':
bking += 1
if king == 'wking':
wking += 1
if bking != 1 or wking != 1:
return False
# check for 8 black pawns and 8 white pawns
bpawn = 0
wpawn = 0
for pawn in board_dict.values():
if pawn == 'bpawn':
bpawn += 1
if pawn == 'wpawn':
wpawn += 1
if wpawn != 8 or wpawn != 8:
return False
#check for valid spaces
valid_spaces = {'1a', '1b', '1c', '1d', '1e', '1f', '1g', '1h','2a', '2b', '2c', '2d', '2e', '2f', '2g', '2h',
'3a', '3b', '3c', '3d', '3e', '3f', '3g', '3h','4a', '4b', '4c', '4d', '4e', '4f', '4g', '4h',
'5a', '5b', '5c', '5d', '5e', '5f', '5g', '5h','6a', '6b', '6c', '6d', '6e', '6f', '6g', '6h',
'7a', '7b', '7c', '7d', '7e', '7f', '7g', '7h','8a', '8b', '8c', '8d', '8e', '8f', '8g', '8h'}
spaces = set()
for i in board_dict.keys():
spaces.add(i) # use set add method (like append for lists)
if spaces != valid_spaces:
return False
#check for 16 pieces per player
piece_count = 0
for piece in board_dict.values():
if piece != '': # don't count the empty spaces (no pieces)
piece_count += 1
if piece_count != 32: # 16 x 2 = 32 total pieces
return False
return 'This is a valid board'
print(isValidChessBoard(board))
Voici ma tentative. J'aimerais recevoir des commentaires de personnes plus expérimentées.
board_width = ['1', '2', '3', '4', '5', '6', '7', '8']
board_height = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
board = []
for x in board_width: #create a list of possible board positions
for y in board_height:
board.append(x + y)
pieces = ['king', 'queen', 'rook', 'rook',
'bishop', 'bishop', 'knight', 'knight',
'pawn', 'pawn', 'pawn', 'pawn', 'pawn',
'pawn', 'pawn', 'pawn'] #list of all pieces for each player
white_pieces = pieces.copy()
black_pieces = pieces.copy()
def is_valid_chess_board(chess_dict):
if 'wking' and 'bking' in chess_dict.values():
for key, value in chess_dict.items(): #iterate each dict elements
if value == '':
board.remove(key)
elif value.startswith('w') and key in board:
lis_val = list(value)
lis_val.remove('w')
val_str = "".join(lis_val)
if val_str in white_pieces:
white_pieces.remove(val_str)
board.remove(key)
print(f"The White {val_str} was placed at {key}")
else:
print(f"This {val_str} is not a proper Chess piece")
elif value.startswith('b') and key in board:
lis_val = list(value)
lis_val.remove('b')
val_str = "".join(lis_val)
if val_str in black_pieces:
black_pieces.remove(val_str)
board.remove(key)
print(f"The Black {val_str} was placed at {key}")
else:
print(f"This {val_str} is not a proper Chess piece")
else:
print("You have an incomplete Chess board")
break
else:
print("You have an incomplete Chess board!")
print(board)
Bienvenue à SO! Ce n'est pas une réponse à la question. L'OP n'a pas demandé d'autres versions. Ils demandaient des conseils sur des parties spécifiques de leur version. Commencez une nouvelle question avec des points spécifiques si vous voulez que d'autres personnes regardent votre version. Ou essayez-le sur Code Review .
Placez un conditionnel après la boucle for sur la ligne 23, c'est
if i:direif i:autour des autres conditions. Cela supprime l'erreur d'index hors plage.jetez un coup d'œil et il y a une chose que vous pouvez supprimer de votre code, l'instruction BREAK juste après l'instruction RETURN. Celles-ci ne sont pas nécessaires, si une fonction atteint une instruction RETURN, elle s'arrête automatiquement, il n'est donc pas nécessaire d'utiliser une instruction BREAK.
Vous pouvez également utiliser $$ si 'bking' n'est pas dans board.values () ou 'wking' pas dans board.values (): $$
'bking' or 'wking' not in board.values()équivaut à( 'bking' ) or ( 'wking' not in board.values() )qui s'évalue toujours à juste'bking'ce qui est vrai. La version correcte serait'bking' not in board.values() or 'wking' not in board.values()mais une version plus courte utilise des sets:not {'bking', 'wking'}.issubset(board.values()).