stellar

UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE |

evaluate.cpp (6530B)


1 #include "evaluate.hpp" 2 #include "bit.hpp" 3 #include "bitboard.hpp" 4 #include "piece.hpp" 5 #include "score.hpp" 6 #include "square.hpp" 7 #include "utils.hpp" 8 9 #include <array> 10 11 namespace evaluate { 12 13 typedef std::array<U64, 8> mask_fr_array; 14 inline constexpr const mask_fr_array mask_rank = []() constexpr -> mask_fr_array { 15 mask_fr_array mask_rank; 16 U64 mask = 0xFF; 17 for (uint8_t rank = 0; rank < 8; rank++) { 18 mask_rank[rank] = mask; 19 mask = bitboard::nortOne(mask); 20 } 21 return mask_rank; 22 }(); 23 24 inline constexpr const mask_fr_array mask_file = []() constexpr -> mask_fr_array { 25 mask_fr_array mask_file; 26 U64 mask = 0x0101010101010101; 27 for (uint8_t file = 0; file < 8; file++) { 28 mask_file[file] = mask; 29 mask = bitboard::eastOne(mask); 30 } 31 return mask_file; 32 }(); 33 34 inline constexpr const mask_fr_array mask_isolated = []() constexpr -> mask_fr_array { 35 mask_fr_array mask_isolated; 36 37 mask_isolated[0] = 0x0202020202020202; 38 39 U64 mask = 0x0505050505050505; 40 for (uint8_t file = 1; file < 8; file++) { 41 mask_isolated[file] = mask; 42 mask = bitboard::eastOne(mask); 43 } 44 45 return mask_isolated; 46 }(); 47 48 typedef std::array<std::array<U64, 64>, 2> mask_passed_array; 49 inline constexpr const mask_passed_array mask_passed = []() constexpr -> mask_passed_array { 50 mask_passed_array mask_passed; 51 52 U64 maskW, maskB; 53 for (uint8_t file = 0; file < 8; file++) { 54 maskW = maskB = mask_file[file] | mask_isolated[file]; 55 for (uint8_t rank = 0; rank < 8; rank++) { 56 maskW = bitboard::nortOne(maskW); 57 mask_passed[0][rank * 8 + file] = maskW; 58 59 maskB = bitboard::soutOne(maskB); 60 mask_passed[1][(7 - rank) * 8 + file] = maskB; 61 } 62 } 63 64 return mask_passed; 65 }(); 66 67 using piece::Type::BISHOP; 68 using piece::Type::KING; 69 using piece::Type::KNIGHT; 70 using piece::Type::PAWN; 71 using piece::Type::QUEEN; 72 using piece::Type::ROOK; 73 74 using score::Phase::ENDGAME; 75 using score::Phase::OPENING; 76 77 uint16_t score_game_phase(const Board &board) { 78 int16_t total = 0; 79 for (int type_i = KNIGHT; type_i < KING; type_i++) { 80 const piece::Type type = static_cast<piece::Type>(type_i); 81 total += bit::count(board.get_bitboard_piece(type)) * score::get(type); 82 } 83 return total; 84 } 85 86 int16_t score_position_side(const Board &board, const color::Color side, const uint16_t phase_score) { 87 U64 bitboard; 88 89 int16_t total = 0, opening = 0, endgame = 0; 90 int8_t square_i; 91 92 const uint8_t side_i = to_underlying(side); 93 const U64 pawns = board.get_bitboard_piece(PAWN); 94 const U64 pawnsS = board.get_bitboard_piece(PAWN, side); 95 const U64 pawnsO = pawns & ~pawnsS; 96 97 bitboard = board.get_bitboard_piece(PAWN, side); 98 bitboard_for_each_bit(square_i, bitboard) { 99 const square::Square square = static_cast<square::Square>(square_i); 100 opening += score::get(PAWN, side, square, OPENING) + score::get(PAWN, OPENING); 101 endgame += score::get(PAWN, side, square, ENDGAME) + score::get(PAWN, ENDGAME); 102 103 // check isolated, doubled and passed pawns 104 const uint8_t file = square::file(square), rank = square::rank(square); 105 if (!(mask_isolated[file] & pawnsS)) { 106 opening -= score::pawn_isolated_opening; 107 endgame -= score::pawn_isolated_endgame; 108 } 109 110 if (bit::count(pawnsS & mask_file[file]) > 1) { 111 opening -= score::pawn_double_opening; 112 endgame -= score::pawn_double_endgame; 113 } 114 115 if (!(pawnsO & mask_passed[side_i][square_i])) total += score::pawn_passed[side_i][rank]; 116 } 117 118 bitboard = board.get_bitboard_piece(KNIGHT, side); 119 bitboard_for_each_bit(square_i, bitboard) { 120 const square::Square square = static_cast<square::Square>(square_i); 121 opening += score::get(KNIGHT, side, square, OPENING) + score::get(KNIGHT, OPENING); 122 endgame += score::get(KNIGHT, side, square, ENDGAME) + score::get(KNIGHT, ENDGAME); 123 } 124 125 bitboard = board.get_bitboard_piece(BISHOP, side); 126 bitboard_for_each_bit(square_i, bitboard) { 127 const square::Square square = static_cast<square::Square>(square_i); 128 opening += score::get(BISHOP, side, square, OPENING) + score::get(BISHOP, OPENING); 129 endgame += score::get(BISHOP, side, square, ENDGAME) + score::get(BISHOP, ENDGAME); 130 } 131 132 bitboard = board.get_bitboard_piece(ROOK, side); 133 bitboard_for_each_bit(square_i, bitboard) { 134 const square::Square square = static_cast<square::Square>(square_i); 135 opening += score::get(ROOK, side, square, OPENING) + score::get(ROOK, OPENING); 136 endgame += score::get(ROOK, side, square, ENDGAME) + score::get(ROOK, ENDGAME); 137 138 // rook on open and semi-open files 139 const uint8_t file = square::file(square); 140 if (!(pawns & mask_file[file])) total += score::file_open; 141 if (!(pawnsS & mask_file[file])) total += score::file_open_semi; 142 } 143 144 bitboard = board.get_bitboard_piece(QUEEN, side); 145 bitboard_for_each_bit(square_i, bitboard) { 146 const square::Square square = static_cast<square::Square>(square_i); 147 opening += score::get(QUEEN, side, square, OPENING) + score::get(QUEEN, OPENING); 148 endgame += score::get(QUEEN, side, square, ENDGAME) + score::get(QUEEN, ENDGAME); 149 } 150 151 bitboard = board.get_bitboard_piece(KING, side); 152 bitboard_for_each_bit(square_i, bitboard) { 153 const square::Square square = static_cast<square::Square>(square_i); 154 opening += score::get(KING, side, square, OPENING) + score::get(KING, OPENING); 155 endgame += score::get(KING, side, square, ENDGAME) + score::get(KING, ENDGAME); 156 157 // king on open and semi-open files 158 const uint8_t file = square::file(square); 159 if (!(pawns & mask_file[file])) total -= score::file_open; 160 if (!(pawnsS & mask_file[file])) total -= score::file_open_semi; 161 } 162 163 opening += total, endgame += total; 164 if (phase_score > score::phase_opening) return opening; 165 if (phase_score < score::phase_endgame) return endgame; 166 return score::interpolate(phase_score, opening, endgame); 167 } 168 169 int16_t score_position(const Board &board) { 170 const uint16_t phase_score = score_game_phase(board); 171 const int16_t score = score_position_side(board, color::WHITE, phase_score) - 172 score_position_side(board, color::BLACK, phase_score); 173 return board.get_side() == color::WHITE ? score : -score; 174 } 175 176 } // namespace evaluate