summaryrefslogtreecommitdiff
path: root/src/engine/evaluate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/evaluate.c')
-rw-r--r--src/engine/evaluate.c83
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