diff options
Diffstat (limited to 'src/engine/evaluate.c')
| -rw-r--r-- | src/engine/evaluate.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/engine/evaluate.c b/src/engine/evaluate.c new file mode 100644 index 0000000..1722da2 --- /dev/null +++ b/src/engine/evaluate.c @@ -0,0 +1,83 @@ +#include "engine/evaluate.h" + +#include <stdlib.h> + +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 <stdbool.h> + +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 |
