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