bitchess/src/evaluation.c
2025-11-08 20:03:35 +05:30

245 lines
No EOL
6.7 KiB
C

#include "evaluation.h"
#include "movegen.h"
#include "repetition.h"
// Material values
const int piece_value[12] = {100, 320, 330, 500, 900, 20000,
-100, -320, -330, -500, -900, -20000};
// Piece-square tables for evaluation
const int pst_pawn[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
50, 50, 50, 50, 50, 50, 50, 50,
10, 10, 20, 30, 30, 20, 10, 10,
5, 5, 10, 25, 25, 10, 5, 5,
0, 0, 0, 20, 20, 0, 0, 0,
5, -5,-10, 0, 0,-10, -5, 5,
5, 10, 10,-20,-20, 10, 10, 5,
0, 0, 0, 0, 0, 0, 0, 0
};
const int pst_knight[64] = {
-50,-40,-30,-30,-30,-30,-40,-50,
-40,-20, 0, 0, 0, 0,-20,-40,
-30, 0, 10, 15, 15, 10, 0,-30,
-30, 5, 15, 20, 20, 15, 5,-30,
-30, 0, 15, 20, 20, 15, 0,-30,
-30, 5, 10, 15, 15, 10, 5,-30,
-40,-20, 0, 5, 5, 0,-20,-40,
-50,-40,-30,-30,-30,-30,-40,-50
};
const int pst_bishop[64] = {
-20,-10,-10,-10,-10,-10,-10,-20,
-10, 0, 0, 0, 0, 0, 0,-10,
-10, 0, 10, 10, 10, 10, 0,-10,
-10, 5, 5, 10, 10, 5, 5,-10,
-10, 0, 5, 10, 10, 5, 0,-10,
-10, 5, 5, 5, 5, 5, 5,-10,
-10, 0, 5, 0, 0, 5, 0,-10,
-20,-10,-10,-10,-10,-10,-10,-20
};
const int pst_rook[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, 10, 10, 10, 10, 5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
0, 0, 0, 5, 5, 0, 0, 0
};
const int pst_queen[64] = {
-20,-10,-10, -5, -5,-10,-10,-20,
-10, 0, 0, 0, 0, 0, 0,-10,
-10, 0, 5, 5, 5, 5, 0,-10,
-5, 0, 5, 5, 5, 5, 0, -5,
0, 0, 5, 5, 5, 5, 0, -5,
-10, 5, 5, 5, 5, 5, 0,-10,
-10, 0, 5, 0, 0, 0, 0,-10,
-20,-10,-10, -5, -5,-10,-10,-20
};
const int pst_king_mid[64] = {
-30,-40,-40,-50,-50,-40,-40,-30,
-30,-40,-40,-50,-50,-40,-40,-30,
-30,-40,-40,-50,-50,-40,-40,-30,
-30,-40,-40,-50,-50,-40,-40,-30,
-20,-30,-30,-40,-40,-30,-30,-20,
-10,-20,-20,-20,-20,-20,-20,-10,
20, 20, 0, 0, 0, 0, 20, 20,
20, 30, 10, 0, 0, 10, 30, 20
};
const int pst_king_end[64] = {
-50,-40,-30,-20,-20,-30,-40,-50,
-30,-20,-10, 0, 0,-10,-20,-30,
-30,-10, 20, 30, 30, 20,-10,-30,
-30,-10, 30, 40, 40, 30,-10,-30,
-30,-10, 30, 40, 40, 30,-10,-30,
-30,-10, 20, 30, 30, 20,-10,-30,
-30,-30, 0, 0, 0, 0,-30,-30,
-50,-30,-30,-30,-30,-30,-30,-50
};
// Evaluate material balance
int evaluate_material(const GameState *state) {
int score = 0;
// Material balance
for (int pc = P; pc <= K; pc++) {
score += piece_value[pc] * __builtin_popcountll(state->bitboards[pc]);
}
for (int pc = p; pc <= k; pc++) {
score += piece_value[pc] * __builtin_popcountll(state->bitboards[pc]);
}
return score;
}
// Evaluate positional factors
int evaluate_position(const GameState *state) {
int score = 0;
int sq;
// Piece-square tables for positional evaluation
// White pawns
U64 wp = state->bitboards[P];
while (wp) {
sq = __builtin_ctzll(wp);
score += pst_pawn[sq];
CLEAR_BIT(wp, sq);
}
// Black pawns
U64 bp = state->bitboards[p];
while (bp) {
sq = __builtin_ctzll(bp);
score -= pst_pawn[63 - sq]; // Flip for black
CLEAR_BIT(bp, sq);
}
// White knights
U64 wn = state->bitboards[N];
while (wn) {
sq = __builtin_ctzll(wn);
score += pst_knight[sq];
CLEAR_BIT(wn, sq);
}
// Black knights
U64 bn = state->bitboards[n];
while (bn) {
sq = __builtin_ctzll(bn);
score -= pst_knight[63 - sq];
CLEAR_BIT(bn, sq);
}
// White bishops
U64 wb = state->bitboards[B];
while (wb) {
sq = __builtin_ctzll(wb);
score += pst_bishop[sq];
CLEAR_BIT(wb, sq);
}
// Black bishops
U64 bb = state->bitboards[b];
while (bb) {
sq = __builtin_ctzll(bb);
score -= pst_bishop[63 - sq];
CLEAR_BIT(bb, sq);
}
// White rooks
U64 wr = state->bitboards[R];
while (wr) {
sq = __builtin_ctzll(wr);
score += pst_rook[sq];
CLEAR_BIT(wr, sq);
}
// Black rooks
U64 br = state->bitboards[r];
while (br) {
sq = __builtin_ctzll(br);
score -= pst_rook[63 - sq];
CLEAR_BIT(br, sq);
}
// White queens
U64 wq = state->bitboards[Q];
while (wq) {
sq = __builtin_ctzll(wq);
score += pst_queen[sq];
CLEAR_BIT(wq, sq);
}
// Black queens
U64 bq = state->bitboards[q];
while (bq) {
sq = __builtin_ctzll(bq);
score -= pst_queen[63 - sq];
CLEAR_BIT(bq, sq);
}
// Kings
if (state->bitboards[K]) {
sq = __builtin_ctzll(state->bitboards[K]);
score += pst_king_mid[sq];
}
if (state->bitboards[k]) {
sq = __builtin_ctzll(state->bitboards[k]);
score -= pst_king_mid[63 - sq];
}
// Add randomness to break symmetry in equal positions
score += (int)(hash_position(state) % 10) - 5;
// Slight bonus for having pieces in the center
U64 center = 0x0000001818000000ULL; // e4, e5, d4, d5
U64 extended_center = 0x00003C3C3C3C0000ULL; // c3-f3 to c6-f6
score += __builtin_popcountll(state->occ_white & center) * 5;
score -= __builtin_popcountll(state->occ_black & center) * 5;
score += __builtin_popcountll(state->occ_white & extended_center) * 2;
score -= __builtin_popcountll(state->occ_black & extended_center) * 2;
return score;
}
// Complete evaluation function
int evaluate(const GameState *state) {
int score = evaluate_material(state) + evaluate_position(state);
// Mobility bonus
GameState temp_state = *state;
Move moves[256];
// Add repetition penalty to avoid draw by repetition everytime
U64 current_hash = hash_position(state);
for (int i = 0; i < state->history.position_count; i++) {
if (state->history.positions[i].hash == current_hash) {
if (state->history.positions[i].count >= 2) {
score -= 50; // Penalty for positions appearing twice
}
break;
}
}
temp_state.side_to_move = 0; // White
int white_mobility = generate_moves(&temp_state, moves);
temp_state.side_to_move = 1; // Black
int black_mobility = generate_moves(&temp_state, moves);
score += (white_mobility - black_mobility) * 5; // 5 points per move advantage
// Adjust for side to move
return state->side_to_move == 0 ? score : -score;
}