1
votes

Automatisez les choses ennuyeuses - Chapitre 5 - Validateur de dictionnaire d'échecs

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:

  1. L'évaluation des clés / valeurs du dictionnaire via ces boucles for + plusieurs instructions if est-elle la «meilleure pratique»? Cela semble beaucoup de code. Le changement pour inclure certains elif provoquait des problèmes s'il était suivi d'une autre instruction if dans la boucle for.
  2. Ligne 23 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"?
  3. Pourquoi ne puis-je pas réduire la ligne 15 en 11 de sorte que j'aie une instruction: 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


4 commentaires

Placez un conditionnel après la boucle for sur la ligne 23, c'est if i: dire if 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()) .


5 Réponses :


0
votes

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))
  1. Voyez comment j'ai refactoré le code

  2. Vérifiez simplement if i != "" Avant d'y accéder

  3. 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.


0 commentaires

0
votes

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

  • Définir l'ensemble de toutes les pièces d'échecs
  • Définir la plage de comptage valide de pièces par type
  • Comptez les pièces sur le plateau
  • Vérifier le nombre de pièces dans une plage valide
  • Vérifiez que les postes sont valides
  • Vérifiez que les noms des pièces sont valides

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


1 commentaires

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.



0
votes

É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))


0 commentaires

0
votes

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


0 commentaires

0
votes

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)


1 commentaires

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 .