|
1 | 1 | #include "eval.h" |
2 | 2 | #include "tune.h" |
3 | 3 | #include <position.h> |
| 4 | +#include <iostream> |
4 | 5 | using namespace chess; |
5 | 6 | using namespace engine::eval; |
| 7 | + |
6 | 8 | namespace engine::eval { |
7 | 9 | Value PawnValue = 100, KnightValue = 325, BishopValue = 350, RookValue = 500, |
8 | | - QueenValue = 900; |
| 10 | + QueenValue = 900, KingValue = 0; |
9 | 11 | Value mg_pawn_table[64] = { |
10 | 12 | 0, 0, 0, 0, 0, 0, 0, 0, 98, 134, 61, 95, 68, 126, 34, -11, |
11 | 13 | -6, 7, 26, 31, 65, 56, 25, -20, -14, 13, 6, 21, 23, 12, 17, -23, |
@@ -101,56 +103,223 @@ Value *mg_pesto_table[] = {nullptr, mg_pawn_table, mg_knight_table, |
101 | 103 | Value *eg_pesto_table[] = {nullptr, eg_pawn_table, eg_knight_table, |
102 | 104 | eg_bishop_table, eg_rook_table, eg_queen_table, |
103 | 105 | eg_king_table}; |
| 106 | +Value mgMobility[] = { |
| 107 | + 0, // none |
| 108 | + 0, // pawn |
| 109 | + 3, // knight |
| 110 | + 5, // bishop |
| 111 | + 2, // rook |
| 112 | + 1, // queen |
| 113 | + 0 // king |
| 114 | +}; |
| 115 | + |
| 116 | +Value egMobility[] = {0, 0, 2, 5, 3, 2, 0}; |
| 117 | +Value spaceWeight=28; |
104 | 118 | // tuning slop here |
105 | 119 | Value eval(const chess::Board &board) { |
106 | | - int pieceCount[10] = { |
107 | | - board.count<PAWN, WHITE>(), board.count<KNIGHT, WHITE>(), |
108 | | - board.count<BISHOP, WHITE>(), board.count<ROOK, WHITE>(), |
109 | | - board.count<QUEEN, WHITE>(), board.count<PAWN, BLACK>(), |
110 | | - board.count<KNIGHT, BLACK>(), board.count<BISHOP, BLACK>(), |
111 | | - board.count<ROOK, BLACK>(), board.count<QUEEN, BLACK>(), |
112 | | - }; |
113 | | - Value material = (pieceCount[0] * PawnValue + pieceCount[1] * KnightValue + |
114 | | - pieceCount[2] * BishopValue + pieceCount[3] * RookValue + |
115 | | - pieceCount[4] * QueenValue) - |
116 | | - (pieceCount[5] * PawnValue + pieceCount[6] * KnightValue + |
117 | | - pieceCount[7] * BishopValue + pieceCount[8] * RookValue + |
118 | | - pieceCount[9] * QueenValue); |
119 | 120 | constexpr int KnightPhase = 1; |
120 | 121 | constexpr int BishopPhase = 1; |
121 | 122 | constexpr int RookPhase = 2; |
122 | 123 | constexpr int QueenPhase = 4; |
123 | 124 | constexpr int TotalPhase = |
124 | 125 | KnightPhase * 4 + BishopPhase * 4 + RookPhase * 4 + QueenPhase * 2; |
125 | | - int phase = (pieceCount[1] + pieceCount[6]) * KnightPhase + |
126 | | - (pieceCount[2] + pieceCount[7]) * BishopPhase + |
127 | | - (pieceCount[3] + pieceCount[8]) * RookPhase + |
128 | | - (pieceCount[4] + pieceCount[9]) * QueenPhase; |
129 | | - phase = (phase * 256 + TotalPhase / 2) / TotalPhase; |
130 | 126 | const int sign = board.sideToMove() == chess::Color::WHITE ? 1 : -1; |
131 | | - int mgScore = material; |
132 | | - int egScore = material; |
| 127 | + int mgScore = 0; |
| 128 | + int egScore = 0; |
| 129 | + int phase = 0; |
133 | 130 | { |
134 | | - Bitboard occ = board.occ(); |
| 131 | + mgScore=egScore=board.sideToMove() == WHITE?spaceWeight:0; |
| 132 | + Bitboard occ = board.occ(), occ2=occ; |
135 | 133 | while (occ) { |
136 | | - Square i = (Square)pop_lsb(occ); |
137 | | - auto p = board.at(i); |
| 134 | + Square sq = (Square)pop_lsb(occ),_sq=sq; |
| 135 | + auto p = board.at(sq); |
138 | 136 | int _sign = 1; |
139 | 137 | if (color_of(p) == BLACK) { |
140 | 138 | _sign = -1; |
141 | | - i = square_mirror(i); |
| 139 | + _sq = square_mirror(sq); |
| 140 | + } |
| 141 | + auto pt = piece_of(p); |
| 142 | + if (pt == NO_PIECE_TYPE) |
| 143 | + continue; |
| 144 | + mgScore += _sign * mg_pesto_table[pt][_sq]; |
| 145 | + egScore += _sign * eg_pesto_table[pt][_sq]; |
| 146 | + mgScore += _sign * piece_value(pt); |
| 147 | + egScore += _sign * piece_value(pt); |
| 148 | + switch (pt) { |
| 149 | + case KNIGHT: |
| 150 | + phase += KnightPhase; |
| 151 | + break; |
| 152 | + case BISHOP: |
| 153 | + phase += BishopPhase; |
| 154 | + break; |
| 155 | + case ROOK: |
| 156 | + phase += RookPhase; |
| 157 | + break; |
| 158 | + case QUEEN: |
| 159 | + phase += QueenPhase; |
| 160 | + break; |
| 161 | + case PAWN: |
| 162 | + break; |
| 163 | + case KING: |
| 164 | + break; |
| 165 | + default: |
| 166 | + break; |
| 167 | + } |
| 168 | + Bitboard attacks = 0; |
| 169 | + |
| 170 | + switch (pt) { |
| 171 | + case KNIGHT: |
| 172 | + attacks = chess::attacks::knight(sq); |
| 173 | + break; |
| 174 | + |
| 175 | + case BISHOP: |
| 176 | + attacks = chess::attacks::bishop(sq, occ2); |
| 177 | + break; |
| 178 | + |
| 179 | + case ROOK: |
| 180 | + attacks = chess::attacks::rook(sq, occ2); |
| 181 | + break; |
| 182 | + |
| 183 | + case QUEEN: |
| 184 | + attacks = chess::attacks::queen(sq, occ2); |
| 185 | + break; |
| 186 | + |
| 187 | + default: |
| 188 | + break; |
| 189 | + } |
| 190 | + attacks &= ~board.us(color_of(p)); |
| 191 | + int mobility = popcount(attacks); |
| 192 | + mgScore += _sign * mobility * mgMobility[pt]; |
| 193 | + egScore += _sign * mobility * egMobility[pt]; |
| 194 | + } |
| 195 | + } |
| 196 | + // Bishop pair bonus |
| 197 | + for (Color c : {WHITE, BLACK}) { |
| 198 | + if (board.count(BISHOP, c) >= 2) { |
| 199 | + int s = (c == WHITE) ? 1 : -1; |
| 200 | + mgScore += s * 30; |
| 201 | + egScore += s * 10; |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + // Rook on open/semi-open file |
| 206 | + for (Color c : {WHITE, BLACK}) { |
| 207 | + int s = (c == WHITE) ? 1 : -1; |
| 208 | + Bitboard rooks = board.pieces(ROOK, c); |
| 209 | + while (rooks) { |
| 210 | + Square sq = Square(pop_lsb(rooks)); |
| 211 | + File f = file_of(sq); |
| 212 | + Bitboard fileMask = attacks::MASK_FILE[f]; |
| 213 | + bool hasOwnPawn = (board.pieces(PAWN, c) & fileMask) != 0; |
| 214 | + bool hasEnemyPawn = (board.pieces(PAWN, ~c) & fileMask) != 0; |
| 215 | + if (!hasOwnPawn && !hasEnemyPawn) { |
| 216 | + mgScore += s * 25; |
| 217 | + egScore += s * 10; |
| 218 | + } else if (!hasOwnPawn) { |
| 219 | + mgScore += s * 15; |
| 220 | + egScore += s * 5; |
| 221 | + } |
| 222 | + } |
| 223 | + } |
| 224 | + |
| 225 | + // Doubled pawn penalty |
| 226 | + for (Color c : {WHITE, BLACK}) { |
| 227 | + int s = (c == WHITE) ? 1 : -1; |
| 228 | + for (int f = 0; f < 8; f++) { |
| 229 | + int cnt = popcount(board.pieces(PAWN, c) & attacks::MASK_FILE[f]); |
| 230 | + if (cnt >= 2) { |
| 231 | + mgScore += s * -(cnt - 1) * 15; |
| 232 | + egScore += s * -(cnt - 1) * 20; |
| 233 | + } |
| 234 | + } |
| 235 | + } |
| 236 | + |
| 237 | + // Isolated pawn penalty |
| 238 | + for (Color c : {WHITE, BLACK}) { |
| 239 | + int s = (c == WHITE) ? 1 : -1; |
| 240 | + Bitboard pawns = board.pieces(PAWN, c); |
| 241 | + while (pawns) { |
| 242 | + Square sq = Square(pop_lsb(pawns)); |
| 243 | + File f = file_of(sq); |
| 244 | + bool isolated = true; |
| 245 | + if (f > FILE_A && (board.pieces(PAWN, c) & attacks::MASK_FILE[f - 1])) |
| 246 | + isolated = false; |
| 247 | + if (f < FILE_H && (board.pieces(PAWN, c) & attacks::MASK_FILE[f + 1])) |
| 248 | + isolated = false; |
| 249 | + if (isolated) { |
| 250 | + mgScore += s * -20; |
| 251 | + egScore += s * -15; |
| 252 | + } |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + // Passed pawn bonus |
| 257 | + for (Color c : {WHITE, BLACK}) { |
| 258 | + int s = (c == WHITE) ? 1 : -1; |
| 259 | + Bitboard pawns = board.pieces(PAWN, c); |
| 260 | + Bitboard enemyPawns = board.pieces(PAWN, ~c); |
| 261 | + while (pawns) { |
| 262 | + Square sq = Square(pop_lsb(pawns)); |
| 263 | + Rank relRank = relative_rank(c, sq); |
| 264 | + if (relRank < RANK_2) |
| 265 | + continue; |
| 266 | + File f = file_of(sq); |
| 267 | + Bitboard passedMask = 0; |
| 268 | + int startF = std::max(0, (int)f - 1); |
| 269 | + int endF = std::min(7, (int)f + 1); |
| 270 | + for (int adjF = startF; adjF <= endF; adjF++) { |
| 271 | + if (c == WHITE) { |
| 272 | + for (int r = rank_of(sq) + 1; r <= 7; r++) |
| 273 | + passedMask |= attacks::MASK_FILE[adjF] & attacks::MASK_RANK[r]; |
| 274 | + } else { |
| 275 | + for (int r = rank_of(sq) - 1; r >= 0; r--) |
| 276 | + passedMask |= attacks::MASK_FILE[adjF] & attacks::MASK_RANK[r]; |
| 277 | + } |
| 278 | + } |
| 279 | + if ((passedMask & enemyPawns) == 0) { |
| 280 | + static const Value passedBonus[] = {0, 0, 10, 20, 40, 80, 160, 200}; |
| 281 | + Value bonus = passedBonus[relRank]; |
| 282 | + mgScore += s * bonus; |
| 283 | + egScore += s * bonus; |
142 | 284 | } |
143 | | - mgScore += _sign * mg_pesto_table[piece_of(p)][i]; |
144 | | - egScore += _sign * eg_pesto_table[piece_of(p)][i]; |
145 | 285 | } |
146 | 286 | } |
| 287 | + |
| 288 | + // King safety: pawn shelter |
| 289 | + for (Color c : {WHITE, BLACK}) { |
| 290 | + int s = (c == WHITE) ? 1 : -1; |
| 291 | + Square kingSq = board.kingSq(c); |
| 292 | + File kf = file_of(kingSq); |
| 293 | + Bitboard pawns = board.pieces(PAWN, c); |
| 294 | + int shelter = 0; |
| 295 | + int startF = std::max(0, (int)kf - 1); |
| 296 | + int endF = std::min(7, (int)kf + 1); |
| 297 | + for (int adjF = startF; adjF <= endF; adjF++) { |
| 298 | + if (c == WHITE) { |
| 299 | + for (int r = rank_of(kingSq) + 1; r <= std::min(7, rank_of(kingSq) + 3); r++) { |
| 300 | + if (pawns & (Bitboard(1) << make_sq((File)adjF, (Rank)r))) |
| 301 | + shelter += 10 - (r - rank_of(kingSq) - 1) * 3; |
| 302 | + } |
| 303 | + } else { |
| 304 | + for (int r = rank_of(kingSq) - 1; r >= std::max(0, rank_of(kingSq) - 3); r--) { |
| 305 | + if (pawns & (Bitboard(1) << make_sq((File)adjF, (Rank)r))) |
| 306 | + shelter += 10 - (rank_of(kingSq) - r - 1) * 3; |
| 307 | + } |
| 308 | + } |
| 309 | + } |
| 310 | + mgScore += s * shelter; |
| 311 | + egScore += s * shelter / 2; |
| 312 | + } |
| 313 | + |
| 314 | + phase = (phase * 256 + TotalPhase / 2) / TotalPhase; |
147 | 315 | Value finalScore = |
148 | | - ((mgScore * phase) + (egScore * (256 - phase))) / 256 * sign; |
| 316 | + (((mgScore * phase) + (egScore * (256 - phase))) * sign) / 256; |
149 | 317 | return finalScore; |
150 | 318 | } |
151 | 319 | Value piece_value(PieceType pt) { |
152 | | - Value pieces[] = {0, PawnValue, KnightValue, |
153 | | - BishopValue, RookValue, QueenValue}; |
| 320 | + Value pieces[] = {0, PawnValue, KnightValue, |
| 321 | + BishopValue, RookValue, QueenValue, |
| 322 | + KingValue}; |
154 | 323 | return pieces[pt]; |
155 | 324 | } |
156 | 325 | } // namespace engine::eval |
0 commit comments