#include "incbin/incbin.h"
-// Macro to embed the default NNUE file data in the engine binary (using incbin.h, by Dale Weiler).
+// Macro to embed the default efficiently updatable neural network (NNUE) file
+// data in the engine binary (using incbin.h, by Dale Weiler).
// This macro invocation will declare the following three variables
// const unsigned char gEmbeddedNNUEData[]; // a pointer to the embedded data
// const unsigned char *const gEmbeddedNNUEEnd; // a marker to the end
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
-// Note that this does not work in Microsof Visual Studio.
+// Note that this does not work in Microsoft Visual Studio.
#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
INCBIN(EmbeddedNNUE, EvalFileDefaultName);
#else
using namespace std;
-using namespace Eval::NNUE;
+using namespace Stockfish::Eval::NNUE;
+
+namespace Stockfish {
namespace Eval {
bool useNNUE;
string eval_file_loaded = "None";
- /// NNUE::init() tries to load a nnue network at startup time, or when the engine
+ /// NNUE::init() tries to load a NNUE network at startup time, or when the engine
/// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
- /// The name of the nnue network is always retrieved from the EvalFile option.
+ /// The name of the NNUE network is always retrieved from the EvalFile option.
/// We search the given network in three locations: internally (the default
/// network may be embedded in the binary), in the active working directory and
/// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY
score += BishopOnKingRing;
int mob = popcount(b & mobilityArea[Us]);
-
mobility[Us] += MobilityBonus[Pt - 2][mob];
if (Pt == BISHOP || Pt == KNIGHT)
// Penalty if the piece is far from the king
score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
- if (Pt == BISHOP)
+ if constexpr (Pt == BISHOP)
{
// Penalty according to the number of our pawns on the same color square as the
// bishop, bigger when the center files are blocked with pawns and smaller
}
}
- if (Pt == ROOK)
+ if constexpr (Pt == ROOK)
{
// Bonuses for rook on a (semi-)open or closed file
if (pos.is_on_semiopen_file(Us, s))
}
}
- if (Pt == QUEEN)
+ if constexpr (Pt == QUEEN)
{
// Penalty if any relative pin or discovered attack against the queen
Bitboard queenPinners;
score -= WeakQueen;
}
}
- if (T)
+ if constexpr (T)
Trace::add(Pt, Us, score);
return score;
// Penalty if king flank is under attack, potentially moving toward the king
score -= FlankAttacks * kingFlankAttack;
- if (T)
+ if constexpr (T)
Trace::add(KING, Us, score);
return score;
score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]) * (1 + queenImbalance);
}
- if (T)
+ if constexpr (T)
Trace::add(THREAT, Us, score);
return score;
score += bonus - PassedFile * edge_distance(file_of(s));
}
- if (T)
+ if constexpr (T)
Trace::add(PASSED, Us, score);
return score;
int weight = pos.count<ALL_PIECES>(Us) - 3 + std::min(pe->blocked_count(), 9);
Score score = make_score(bonus * weight * weight / 16, 0);
- if (T)
+ if constexpr (T)
Trace::add(SPACE, Us, score);
return score;
+ eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
v /= PHASE_MIDGAME;
- if (T)
+ if constexpr (T)
{
Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
Value v = winnable(score);
// In case of tracing add all remaining individual evaluation terms
- if (T)
+ if constexpr (T)
{
Trace::add(MATERIAL, pos.psq_score());
Trace::add(IMBALANCE, me->imbalance());
return v;
}
+ // specifically correct for cornered bishops to fix FRC with NNUE.
+ Value fix_FRC(const Position& pos) {
+
+ Value bAdjust = Value(0);
+
+ constexpr Value p1=Value(209), p2=Value(136), p3=Value(148);
+
+ Color Us = pos.side_to_move();
+ if ( (pos.pieces(Us, BISHOP) & relative_square(Us, SQ_A1))
+ && (pos.pieces(Us, PAWN) & relative_square(Us, SQ_B2)))
+ {
+ bAdjust -= !pos.empty(relative_square(Us,SQ_B3)) ? p1
+ : pos.piece_on(relative_square(Us,SQ_C3)) == make_piece(Us, PAWN) ? p2
+ : p3;
+ }
+ if ( (pos.pieces(Us, BISHOP) & relative_square(Us, SQ_H1))
+ && (pos.pieces(Us, PAWN) & relative_square(Us, SQ_G2)))
+ {
+ bAdjust -= !pos.empty(relative_square(Us,SQ_G3)) ? p1
+ : pos.piece_on(relative_square(Us,SQ_F3)) == make_piece(Us, PAWN) ? p2
+ : p3;
+ }
+ if ( (pos.pieces(~Us, BISHOP) & relative_square(Us, SQ_A8))
+ && (pos.pieces(~Us, PAWN) & relative_square(Us, SQ_B7)))
+ {
+ bAdjust += !pos.empty(relative_square(Us,SQ_B6)) ? p1
+ : pos.piece_on(relative_square(Us,SQ_C6)) == make_piece(~Us, PAWN) ? p2
+ : p3;
+ }
+ if ( (pos.pieces(~Us, BISHOP) & relative_square(Us, SQ_H8))
+ && (pos.pieces(~Us, PAWN) & relative_square(Us, SQ_G7)))
+ {
+ bAdjust += !pos.empty(relative_square(Us,SQ_G6)) ? p1
+ : pos.piece_on(relative_square(Us,SQ_F6)) == make_piece(~Us, PAWN) ? p2
+ : p3;
+ }
+ return bAdjust;
+ }
+
} // namespace
// Scale and shift NNUE for compatibility with search and classical evaluation
auto adjusted_NNUE = [&](){
int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count<PAWN>();
- return NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo;
+ Value nnueValue = NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo;
+
+ if (pos.is_chess960())
+ nnueValue += fix_FRC(pos);
+
+ return nnueValue;
};
// If there is PSQ imbalance use classical eval, with small probability if it is small
return ss.str();
}
+
+} // namespace Stockfish