home / fornax-v3-0 / src / eval / eval.cpp

eval.cpp



//
//  eval.cpp
//  fornax3
//
//  Created by Anders on 28/12/2020.
//
#include <stdio.h>
#include "eval.hpp"
#include "../libs/require.h"
#include "eval_pawn_structure.inc.h"
#include "eval_endgame_material.inc.h"
#include "../parsing.hpp"
#include "../moving/oracle.hpp"

static eval configured_contempt = EVAL_CONTEMPT_DEFAULT;

static inline eval getContemptFromGamePhase(const Board* board) {
  eval s = eval_get_phase(board) * configured_contempt / PHASE_START;
  return s;
}

eval eval_calculate_contempt(const Board* board) {
  return getContemptFromGamePhase(board) * (board->active == board->active_initial ? -1 : 1);
}

void eval_set_contempt_factor(long contempt) {
  require(contempt <= EVAL_CONTEMPT_MAX, "contempt was too big %d vs max %d\n", contempt, EVAL_CONTEMPT_MAX);
  require(contempt >= EVAL_CONTEMPT_MIN, "contempt was too small %d vs min %d\n", contempt, EVAL_CONTEMPT_MIN);
  configured_contempt = (eval) contempt;
#ifdef DEBUGLOG
  printf("ok contempt = %d\n", configured_contempt);
#endif
}

 eval eval_count_psqt(const Side *side, const piecetable *psqt) {
  eval count = 0;
  for (int i = 0; i < 6; ++i) {
    bits64 bits = side->pieces[i];
    while (bits) count += (*psqt)[i][bits_pop_trailing(&bits)];
  }
  return count;
}

eval eval_count_material(const Side* side) {
  eval count = 0;
  count += BITS_COUNT(side->pieces[QUEEN]) * EVAL_PIECE_QUEENS;
  count += BITS_COUNT(side->pieces[ROOK]) * EVAL_PIECE_ROOKS;
  count += BITS_COUNT(side->pieces[BISHOP]) * EVAL_PIECE_BISHOPS;
  count += BITS_COUNT(side->pieces[KNIGHT]) * EVAL_PIECE_KNIGHTS;
  count += BITS_COUNT(side->pieces[PAWN]) * EVAL_PIECE_PAWNS;
  return count;
}

uint8_t eval_count_phase(const Side *side) {
  uint8_t count = 0;
    count += BITS_COUNT(side->pieces[QUEEN]) * EVAL_PHASE_QUEENS;
    count += BITS_COUNT(side->pieces[ROOK]) * EVAL_PHASE_ROOKS;
    count += BITS_COUNT(side->pieces[BISHOP]) * EVAL_PHASE_BISHOPS;
    count += BITS_COUNT(side->pieces[KNIGHT]) * EVAL_PHASE_KNIGHTS;
    return count;
}

uint8_t eval_get_phase(const Board* board) {
  uint8_t phase = board->side[WHITE].eval_phase + board->side[BLACK].eval_phase;
  return phase;
}

static inline eval eval_taper(uint16_t phase, eval mg, eval eg) {
  return (mg * phase + eg * (PHASE_START - phase)) / PHASE_START;
}

template<bool debug>
static constexpr eval eval_material(const Side* white, const Side* black) {
  
  eval w_mat = ED_ADD_WHITE("material", white->eval_material);
  eval b_mat = ED_ADD_BLACK("material", black->eval_material);
  
  eval diff = w_mat - b_mat;
  diff = adjust_for_drawish_endgames(w_mat, b_mat, diff);
  
  return diff;
}

template<bool debug>
static constexpr void eval_psqt(eval* mg, eval* eg, const Side* white, const Side* black) {
  eval w_mg_psqt = ED_ADD_WHITE_MG("psqt", white->eval_mg_psqt);
  eval w_eg_psqt = ED_ADD_WHITE_EG("psqt", white->eval_eg_psqt);
  
  eval b_mg_psqt = ED_ADD_BLACK_MG("psqt", black->eval_mg_psqt);
  eval b_eg_psqt = ED_ADD_BLACK_EG("psqt", black->eval_eg_psqt);
  
  eval mg_psqt = (w_mg_psqt - b_mg_psqt);
  mg_psqt = ED_ADD_DIFF_MG("psqt", mg_psqt);
  eval eg_psqt = (w_eg_psqt - b_eg_psqt);
  eg_psqt = ED_ADD_DIFF_EG("psqt", eg_psqt);
  
  *mg += mg_psqt;
  *eg += eg_psqt;
}


static inline eval piece_activity(bits64 attacks, eval activityValue) {
  eval pieceActivity = BITS_COUNT(attacks);
  pieceActivity += BITS_COUNT(attacks & BB_CENTERMASK16);
  pieceActivity += BITS_COUNT(attacks & BB_CENTERMASK4);
  pieceActivity *= activityValue;
  return pieceActivity;
}

static inline eval piece_threats(piecetype piece, bits64 attacks, const bits64* hostiles) {
  const eval *treat_values = THREAT_TABLE[piece];
  eval threats = BITS_COUNT(attacks & hostiles[PAWN]) * treat_values[PAWN];
  threats += BITS_COUNT(attacks & hostiles[KNIGHT]) * treat_values[KNIGHT];
  threats += BITS_COUNT(attacks & hostiles[BISHOP]) * treat_values[BISHOP];
  threats += BITS_COUNT(attacks & hostiles[ROOK]) * treat_values[ROOK];
  threats += BITS_COUNT(attacks & hostiles[QUEEN]) * treat_values[QUEEN];
  return threats;
}

static inline eval king_threats_or_defence(bits64 attacks, bits64 kingNeighborSquares) {
  return BITS_COUNT(attacks & kingNeighborSquares);
}

static inline eval king_shield_score(eval pawnShield) {
  switch (pawnShield) {
    case 0: return -40;
    case 1: return -20;
    case 2: return 0;
    case 3: return 10;
    default: return 15;
  }
}
template<color c>
static constexpr eval get_king_open_file_score(const Side* friendly,
                                               const Side* hostile) {
  constexpr direction dir = c == WHITE ? N : S;
  
  square king = bits_get_leading(friendly->pieces[KING]);
  bits64 slide = oracle_get_slide<dir>(king);
  
  eval count = BITS_COUNT(slide & (friendly->pieces[PAWN] | hostile->pieces[PAWN]));
  
  switch (count) {
    case 0: return -20;
    case 1: return -10;
    default: return 0;
  }
}


template<color c>
static constexpr eval shield_count(const Side* side) {
  const bits64 king = side->pieces[KING];
  
  bits64 pawn_shield_area = oracle_get_king_pawn_shield_area(bits_get_leading(king));
  bits64 piece_shield_area = side->attackkmaps[0].bits;
  
  eval pawn_shield = BITS_COUNT(pawn_shield_area & side->pieces[PAWN]);
  eval piece_shield = BITS_COUNT(piece_shield_area & (side->pieces[KNIGHT] | side->pieces[BISHOP]));
  
  eval total_shield = pawn_shield + piece_shield + ((king & BB_CORNERS) > 0);
  
  return total_shield;
}

static constexpr eval king_threat_score(eval recorded_nearby_hostile_attacks,
                                     eval recorded_nearby_friendly_attacks,
                                     eval shield_count) {
  shield_count--;
  eval def = shield_count * shield_count + recorded_nearby_friendly_attacks - 10;
  eval attacks = recorded_nearby_hostile_attacks * 2;
  eval diff = attacks - def;
  eval threat = diff > 0 ? (diff * diff) : diff / 2;
  return -threat;
}

template<bool debug>
static constexpr void eval_king_safety(eval* mg,
                                    const Side* white,
                                    const Side* black) {
  
  const bits64 w_king_neighbors = white->attackkmaps[0].bits | white->pieces[KING];
  const bits64 b_king_neighbors = black->attackkmaps[0].bits | black->pieces[KING];
  eval w_king_nearby_friendly_attacks = 0;
  eval w_king_nearby_hostile_attacks = 0;
  eval b_king_nearby_friendly_attacks = 0;
  eval b_king_nearby_hostile_attacks = 0;
  
  for (uint8_t i = 0; i < white->attackmapsize; ++i) {
    Attackmap set = white->attackkmaps[i];
    bits64 attacks = set.bits;
    w_king_nearby_friendly_attacks += king_threats_or_defence(attacks, w_king_neighbors);
    b_king_nearby_hostile_attacks += king_threats_or_defence(attacks, b_king_neighbors);
  }
  for (uint8_t i = 0; i < black->attackmapsize; ++i) {
    Attackmap set = black->attackkmaps[i];
    bits64 attacks = set.bits;
    b_king_nearby_friendly_attacks += king_threats_or_defence(attacks, b_king_neighbors);
    w_king_nearby_hostile_attacks += king_threats_or_defence(attacks, w_king_neighbors);
  }
  
  eval w_shield_count = shield_count<WHITE>(white);
  eval b_shield_count = shield_count<BLACK>(black);
  
  eval w_shield_score = ED_ADD_WHITE_MG("king shield", king_shield_score(w_shield_count));
  eval b_shield_score = ED_ADD_BLACK_MG("king shield", king_shield_score(b_shield_count));
  eval shield_score = w_shield_score - b_shield_score;
  *mg += shield_score;
  
  eval w_threat_score = ED_ADD_WHITE_MG(
      "king safe",
      king_threat_score(w_king_nearby_hostile_attacks, w_king_nearby_friendly_attacks, w_shield_count)
  );
  eval b_threat_score = ED_ADD_BLACK_MG(
      "king safe",
      king_threat_score(b_king_nearby_hostile_attacks, b_king_nearby_friendly_attacks, b_shield_count)
  );
  eval threat_score = w_threat_score - b_threat_score;
  *mg += threat_score;
  
  eval w_open_file_score = ED_ADD_WHITE_MG("king open", get_king_open_file_score<WHITE>(white, black));
  eval b_open_file_score = ED_ADD_BLACK_MG("king open", get_king_open_file_score<BLACK>(black, white));
  eval open_score = w_open_file_score - b_open_file_score;
  *mg += open_score;
}

template<bool debug>
static constexpr void eval_activity(eval* mg, eval* eg, const Side* white, const Side* black) {
  const bits64* whitepieces = white->pieces;
  const bits64* blackpieces = black->pieces;

  eval w_activity = 0;
  eval w_threats = 0;
  eval b_activity = 0;
  eval b_threats = 0;
  
  for (uint8_t i = 0; i < white->attackmapsize; ++i) {
    Attackmap set = white->attackkmaps[i];
    eval activityValue = ACTIVITYVALUE[set.piece];
    bits64 attacks = set.bits;
    bits64 hostileattacks = set.bits & black->piecemask;
    bits64 friendlyattaks = set.bits & white->piecemask;
    bits64 emptyattacks = attacks ^ (hostileattacks | friendlyattaks);
    
    w_activity += piece_activity(emptyattacks, activityValue);
    w_threats += piece_threats(set.piece, hostileattacks, blackpieces);
  }
  for (uint8_t i = 0; i < black->attackmapsize; ++i) {
    Attackmap set = black->attackkmaps[i];
    eval activityValue = ACTIVITYVALUE[set.piece];
    bits64 attacks = set.bits;
    bits64 hostileattacks = set.bits & white->piecemask;
    bits64 friendlyattaks = set.bits & black->piecemask;
    bits64 emptyattacks = attacks ^ (hostileattacks | friendlyattaks);
    
    b_activity += piece_activity(emptyattacks, activityValue);
    b_threats += piece_threats(set.piece, hostileattacks, whitepieces);
  }
  
  eval activity = ED_ADD_WHITE("activity", w_activity) - ED_ADD_BLACK("activity", b_activity);
  activity = ED_ADD_DIFF("activity", activity / 2);
  
  eval threats = ED_ADD_WHITE("threats", w_threats) - ED_ADD_BLACK("threats", b_threats);
  threats = ED_ADD_DIFF("threats", threats);
  
  *mg += activity + threats;
  *eg += activity + threats;
}

template<bool debug>
static constexpr void eval_bishop_pair(eval* mg, eval* eg, const Side* white, const Side* black) {
  bool w_pair = bits_is_multi_bit(white->pieces[BISHOP]);
  eval w_mg_bp = ED_ADD_WHITE_MG("bishop pair", w_pair * 20);
  eval w_eg_bp = ED_ADD_WHITE_EG("bishop pair", w_pair * 50);
  
  bool b_pair = bits_is_multi_bit(black->pieces[BISHOP]);
  eval b_mg_bp = ED_ADD_BLACK_MG("bishop pair", b_pair * 20);
  eval b_eg_bp = ED_ADD_BLACK_EG("bishop pair", b_pair * 50);
  
  eval mg_diff = ED_ADD_DIFF_MG("bishop pair", w_mg_bp - b_mg_bp);
  eval eg_diff = ED_ADD_DIFF_EG("bishop pair", w_eg_bp - b_eg_bp);
  
  *mg += mg_diff;
  *eg += eg_diff;
}

template<bool debug>
static constexpr void eval_rook_pair(eval* eg, const Side* white, const Side* black) {
  bool w_pair = bits_is_multi_bit(white->pieces[ROOK]);
  eval w_eg_rp = ED_ADD_WHITE_EG("rook pair", w_pair * -25);
  
  bool b_pair = bits_is_multi_bit(black->pieces[ROOK]);
  eval b_eg_rp = ED_ADD_BLACK_EG("rook pair", b_pair * -25);
  
  eval eg_diff = ED_ADD_DIFF_EG("rook pair", w_eg_rp - b_eg_rp);
  
  *eg += eg_diff;
}

template <bool debug = false>
static constexpr eval eval_evaluate_templ(const Board* board) {
  ED_START(board->active == WHITE);
  
  const Side* white = &board->side[WHITE];
  const Side* black = &board->side[BLACK];
  
  eval material = eval_material<debug>(white, black);
  eval mg_total = material;
  eval eg_total = material;
  
  eval_psqt<debug>(&mg_total, &eg_total, white, black);
  eval_activity<debug>(&mg_total, &eg_total, white, black);
  eval_king_safety<debug>(&mg_total, white, black);
  eval_pawn_structure<debug>(&mg_total, &eg_total, board);
  eval_bishop_pair<debug>(&mg_total, &eg_total, white, black);
  eval_rook_pair<debug>(&eg_total, white, black);

  uint16_t phase = eval_get_phase(board);
  eval total = eval_taper(phase, mg_total, eg_total);
  ED_END(board, total);
  return board->active ? -total : total;
}

eval eval_evaluate(const Board* board) {
  return eval_evaluate_templ<false>(board);
}
eval eval_evaluate_debug(const Board* board) {
  return eval_evaluate_templ<true>(board);
}