X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fevaluate.cpp;h=bb4f9ef7f44ba53892773959b7f8b862de3beeed;hb=ace9632c6713e346ccca73b3e2edc046c1f5527c;hp=dd5d23b253dd074a0feef432367a899d9dc1e1b3;hpb=66a7a8a0cc4a5958c91c46d32197dc04523cdb43;p=stockfish diff --git a/src/evaluate.cpp b/src/evaluate.cpp index dd5d23b2..bb4f9ef7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,12 +37,13 @@ #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 @@ -53,16 +54,18 @@ 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 @@ -225,7 +228,7 @@ namespace { // BishopPawns[distance from edge] contains a file-dependent penalty for pawns on // squares of the same color as our bishop. constexpr Score BishopPawns[int(FILE_NB) / 2] = { - S(3, 8), S(3, 9), S(1, 8), S(3, 7) + S(3, 8), S(3, 9), S(2, 8), S(3, 8) }; // KingProtector[knight/bishop] contains penalty for each distance unit to own king @@ -233,7 +236,7 @@ namespace { // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a // pawn protected square on rank 4 to 6 which is also safe from a pawn attack. - constexpr Score Outpost[] = { S(56, 34), S(31, 23) }; + constexpr Score Outpost[] = { S(57, 38), S(31, 24) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { @@ -255,7 +258,7 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score BadOutpost = S( -7, 36); + constexpr Score UncontestedOutpost = S( 1, 10); constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); @@ -422,13 +425,12 @@ namespace { score += BishopOnKingRing; int mob = popcount(b & mobilityArea[Us]); - mobility[Us] += MobilityBonus[Pt - 2][mob]; if (Pt == BISHOP || Pt == KNIGHT) { // Bonus if the piece is on an outpost square or can reach one - // Reduced bonus for knights (BadOutpost) if few relevant targets + // Bonus for knights (UncontestedOutpost) if few relevant targets bb = OutpostRanks & (attackedBy[Us][PAWN] | shift(pos.pieces(PAWN))) & ~pe->pawn_attacks_span(Them); Bitboard targets = pos.pieces(Them) & ~pos.pieces(PAWN); @@ -437,7 +439,7 @@ namespace { && bb & s & ~CenterFiles // on a side outpost && !(b & targets) // no relevant attacks && (!more_than_one(targets & (s & QueenSide ? QueenSide : KingSide)))) - score += BadOutpost; + score += UncontestedOutpost * popcount(pos.pieces(PAWN) & (s & QueenSide ? QueenSide : KingSide)); else if (bb & s) score += Outpost[Pt == BISHOP]; else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) @@ -450,7 +452,7 @@ namespace { // Penalty if the piece is far from the king score -= KingProtector[Pt == BISHOP] * distance(pos.square(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 @@ -482,7 +484,7 @@ namespace { } } - 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)) @@ -509,7 +511,7 @@ namespace { } } - if (Pt == QUEEN) + if constexpr (Pt == QUEEN) { // Penalty if any relative pin or discovered attack against the queen Bitboard queenPinners; @@ -517,7 +519,7 @@ namespace { score -= WeakQueen; } } - if (T) + if constexpr (T) Trace::add(Pt, Us, score); return score; @@ -617,7 +619,7 @@ namespace { // 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; @@ -718,7 +720,7 @@ namespace { score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]) * (1 + queenImbalance); } - if (T) + if constexpr (T) Trace::add(THREAT, Us, score); return score; @@ -791,11 +793,13 @@ namespace { unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); // If there are no enemy pieces or attacks on passed pawn span, assign a big bonus. + // Or if there is some, but they are all attacked by our pawns, assign a bit smaller bonus. // Otherwise assign a smaller bonus if the path to queen is not attacked // and even smaller bonus if it is attacked but block square is not. - int k = !unsafeSquares ? 35 : - !(unsafeSquares & squaresToQueen) ? 20 : - !(unsafeSquares & blockSq) ? 9 : + int k = !unsafeSquares ? 36 : + !(unsafeSquares & ~attackedBy[Us][PAWN]) ? 30 : + !(unsafeSquares & squaresToQueen) ? 17 : + !(unsafeSquares & blockSq) ? 7 : 0 ; // Assign a larger bonus if the block square is defended @@ -809,7 +813,7 @@ namespace { score += bonus - PassedFile * edge_distance(file_of(s)); } - if (T) + if constexpr (T) Trace::add(PASSED, Us, score); return score; @@ -850,7 +854,7 @@ namespace { int weight = pos.count(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; @@ -865,7 +869,7 @@ namespace { Value Evaluation::winnable(Score score) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - - distance(pos.square(WHITE), pos.square(BLACK)); + + int(rank_of(pos.square(WHITE)) - rank_of(pos.square(BLACK))); bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); @@ -945,7 +949,7 @@ namespace { + 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)); @@ -1017,7 +1021,7 @@ make_v: 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()); @@ -1034,6 +1038,45 @@ make_v: 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 @@ -1050,8 +1093,13 @@ Value Eval::evaluate(const Position& pos) { { // Scale and shift NNUE for compatibility with search and classical evaluation auto adjusted_NNUE = [&](){ - int mat = pos.non_pawn_material() + PawnValueMg * pos.count(); - return NNUE::evaluate(pos) * (679 + mat / 32) / 1024 + Tempo; + int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count(); + 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 @@ -1144,3 +1192,5 @@ std::string Eval::trace(const Position& pos) { return ss.str(); } + +} // namespace Stockfish