Esempio n. 1
0
def heur(board: ChessState) -> int:
    """Evaluation function for a given ChessState. The upper- and lower-bounds for the value returned are
    10000 and -10000. A value of 0 indicates an equal position."""

    if board.is_checkmate():
        if board.turn:
            #black won
            return -10000
        else:
            #white won
            return 10000
    elif board.is_stalemate() or board.is_insufficient_material():
        return 0

    #get piece positions
    white_pawns = board.pieces(chess.PAWN, chess.WHITE)
    black_pawns = board.pieces(chess.PAWN, chess.BLACK)
    white_knights = board.pieces(chess.KNIGHT, chess.WHITE)
    black_knights = board.pieces(chess.KNIGHT, chess.BLACK)
    white_bishops = board.pieces(chess.BISHOP, chess.WHITE)
    black_bishops = board.pieces(chess.BISHOP, chess.BLACK)
    white_rooks = board.pieces(chess.ROOK, chess.WHITE)
    black_rooks = board.pieces(chess.ROOK, chess.BLACK)
    white_queens = board.pieces(chess.QUEEN, chess.WHITE)
    black_queens = board.pieces(chess.QUEEN, chess.BLACK)
    white_king = board.pieces(chess.KING, chess.WHITE)
    black_king = board.pieces(chess.KING, chess.BLACK)

    num_of_pieces = len(black_knights) + len(black_bishops) + len(black_rooks) +\
                    len(white_knights) + len(white_bishops) + len(white_rooks) + len(white_queens) \
                    + len(black_queens) + len(white_king) + len(black_king) + len(white_pawns) + len(black_pawns)

    #returns number of pinned pieces from piece_set * value_of_pin
    def pinned_eval(piece_set, color, value_of_pin):
        cum_eval = 0
        for piece in piece_set:
            if board.is_pinned(color, piece):
                cum_eval = cum_eval + value_of_pin
        return cum_eval

    pinned_value = pinned_eval(white_pawns, chess.WHITE, -20) + pinned_eval(black_pawns, chess.BLACK, 20) + \
                         pinned_eval(white_knights, chess.WHITE, -30) + pinned_eval(black_knights, chess.BLACK, 30) +\
                         pinned_eval(white_bishops,chess.WHITE, -30) + pinned_eval(black_bishops,chess.BLACK, 30) +\
                         pinned_eval(white_rooks,chess.WHITE, -150) + pinned_eval(black_bishops,chess.BLACK, 150) +\
                         pinned_eval(white_queens,chess.WHITE, -400) + pinned_eval(black_bishops,chess.BLACK, 400)

    #returns value representing how many pieces of any type in list_of_pieces_to_attack are being attacked by any piece in piece_set
    def attacking_eval(piece_set, list_of_pieces_to_attack,
                       list_of_value_of_attack):
        cum_eval = 0
        for piece in piece_set:
            attacked = board.attacks(piece)
            for i in range(0, len(list_of_pieces_to_attack)):
                num_of_attacks_on_piece_type = len(
                    attacked.intersection(list_of_pieces_to_attack[i]))
                cum_eval = cum_eval + num_of_attacks_on_piece_type * list_of_value_of_attack[
                    i]
        return cum_eval

    attacking_value = attacking_eval(white_knights, [black_queens,black_rooks,black_bishops], [20, 10, 5]) + \
      attacking_eval(white_bishops, [black_queens, black_rooks, black_bishops], [20, 10, 2]) + \
      attacking_eval(white_pawns, [black_queens, black_rooks, black_bishops, black_knights], [30, 20, 10, 10]) +\
      attacking_eval(white_rooks, [black_queens], [20]) + \
      attacking_eval(black_knights, [white_queens, white_rooks, white_bishops], [-20, -10, -5]) + \
      attacking_eval(black_bishops, [white_queens, white_rooks, white_bishops], [-20, -10, -2]) + \
      attacking_eval(black_pawns, [white_queens, white_rooks, white_bishops, white_knights], [-30, -20, -10, -10]) + \
      attacking_eval(black_rooks, [white_queens], [-20])

    num_black_minor_pieces = len(black_knights) + len(black_bishops) + len(
        black_rooks)
    num_white_minor_pieces = len(white_knights) + len(white_bishops) + len(
        white_rooks)

    #boolean if board is in endgame
    endgame = (len(white_queens) + len(black_queens) is 0) or (
        len(white_queens) is 1 and len(black_queens) is 1
        and num_black_minor_pieces is 1 and num_white_minor_pieces is 1)

    kingstable = kingstable_endgame if endgame else kingstable_middlegame

    #bishop pair is more valuable
    white_value_of_bishops = 375 if len(white_bishops) >= 2 and len(
        black_bishops) < 2 else 360
    black_value_of_bishops = 375 if len(black_bishops) >= 2 and len(
        white_bishops) < 2 else 360

    #calculates value of material in centipawns with standard valuations from https://en.wikipedia.org/wiki/Chess_piece_relative_value
    white_material = 100 * len(white_pawns) + 350 * len(
        white_knights) + white_value_of_bishops * len(
            white_bishops) + 525 * len(white_rooks) + 900 * len(white_queens)
    black_material = 100 * len(black_pawns) + 350 * len(
        black_knights) + black_value_of_bishops * len(
            black_bishops) + 525 * len(black_rooks) + 900 * len(black_queens)

    #sums values of all the positions of the pieces on the board from the tables
    square_values = sum([pawntable[i] for i in white_pawns]) - sum([pawntable[chess.square_mirror(i)] for i in black_pawns]) +\
                    sum([knightstable[i] for i in white_knights]) - sum([knightstable[chess.square_mirror(i)] for i in black_knights]) +\
                    sum([bishopstable[i] for i in white_bishops]) - sum([bishopstable[chess.square_mirror(i)] for i in black_bishops])+\
                    sum([rookstable[i] for i in white_rooks]) - sum([rookstable[chess.square_mirror(i)] for i in black_rooks])+\
                    sum([queenstable[i] for i in white_queens]) - sum([queenstable[chess.square_mirror(i)] for i in black_queens])+\
                    sum([kingstable[i] for i in white_king]) - sum([kingstable[chess.square_mirror(i)] for i in black_king])

    return white_material - black_material + square_values + pinned_value + attacking_value