#include "engine/evaluate.h" #include enum { EVAL_PAWN = 100, EVAL_KNIGHT = 320, EVAL_BISHOP = 320, EVAL_ROOK = 500, EVAL_QUEEN = 900, }; static const i32 MATERIAL[PIECE_TYPE_COUNT] = { [WHITE_KING] = 0, [WHITE_QUEEN] = EVAL_QUEEN, [WHITE_ROOK] = EVAL_ROOK, [WHITE_BISHOP] = EVAL_BISHOP, [WHITE_KNIGHT] = EVAL_KNIGHT, [WHITE_PAWN] = EVAL_PAWN, [BLACK_KING] = 0, [BLACK_QUEEN] = EVAL_QUEEN, [BLACK_ROOK] = EVAL_ROOK, [BLACK_BISHOP] = EVAL_BISHOP, [BLACK_KNIGHT] = EVAL_KNIGHT, [BLACK_PAWN] = EVAL_PAWN, }; // simple positional bonus (a light "pst"): pawns like to advance, knights like // the centre. everything else is just material. static i32 pst_bonus(int piece_type, int square) { int rank = square / 8; int file = square % 8; if (piece_type == WHITE_PAWN) return (rank - 1) * 6; if (piece_type == BLACK_PAWN) return (6 - rank) * 6; if (piece_type == WHITE_KNIGHT || piece_type == BLACK_KNIGHT) { bool central = (file == 3 || file == 4) && (rank == 3 || rank == 4); bool nearcentre = (file >= 2 && file <= 5) && (rank >= 2 && rank <= 5); return central ? 16 : (nearcentre ? 4 : -4); } return 0; } i32 evaluate(position_t position) { i32 white = 0; i32 black = 0; for (int piece = 0; piece < PIECE_TYPE_COUNT; piece++) { bitboard_t bb = position.bitboards[piece]; while (bb) { int sq = __builtin_ctzll(bb); bb &= bb - 1; if (piece < BLACK_KING) { white += MATERIAL[piece] + pst_bonus(piece, sq); } else { black += MATERIAL[piece] + pst_bonus(piece, sq); } } } i32 score = white - black; return (position.turn == WHITE_TURN) ? score : -score; } #ifdef TEST_MOD #include bool test_eval_startpos_is_balanced() { position_t start = position_starting(); // symmetric starting position -> static eval should be ~0. return abs(evaluate(start)) < 100; } bool test_eval_scales_with_material() { position_t pos = {0}; pos.turn = WHITE_TURN; // give white a queen on a1, black only a king on h8 pos.bitboards[WHITE_QUEEN] = 1ULL; pos.bitboards[BLACK_KING] = (1ULL << 63); pos.bitboards[WHITE_KING] = (1ULL << 4); // a5, far from the action pos.bitboards[BLACK_PAWN] = 0; i32 score = evaluate(pos); // white is up a queen (~900) plus a little; should be comfortably positive. return score > 800; } #endif