/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2026 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 the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "evaluate.h" #include #include #include #include #include #include #include #include #include "misc.h" #include "nnue/network.h" #include "nnue/nnue_misc.h" #include "position.h" #include "types.h" #include "uci.h" #include "nnue/nnue_accumulator.h" namespace Stockfish { // Evaluate is the evaluator for the outer world. It returns a static evaluation // of the position from the point of view of the side to move. Value Eval::evaluate(const Eval::NNUE::Network& network, const Position& pos, Eval::NNUE::AccumulatorStack& accumulators, Eval::NNUE::AccumulatorCaches& caches, int optimism) { assert(!pos.checkers()); auto [psqt, positional] = network.evaluate(pos, accumulators, caches); Value nnue = psqt + positional; // Blend optimism and eval with nnue complexity int nnueComplexity = std::abs(psqt - positional); optimism += optimism * i64(nnueComplexity) / 476; nnue -= nnue * i64(nnueComplexity) / 18236; int material = 534 * pos.count() + pos.non_pawn_material(); int v = (nnue * i64(77871 + material) + optimism * i64(7191 + material)) / 77871; // Damp down the evaluation linearly when shuffling v -= v * pos.rule50_count() / 199; // Guarantee evaluation does not hit the tablebase range v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); return v; } // Like evaluate(), but instead of returning a value, it returns // a string (suitable for outputting to stdout) that contains the detailed // descriptions and values of each evaluation term. Useful for debugging. // Trace scores are from white's point of view std::string Eval::trace(Position& pos, const Eval::NNUE::Network& network) { if (pos.checkers()) return "Final evaluation: none (in check)"; auto accumulators = std::make_unique(); auto caches = std::make_unique(network); std::stringstream ss; ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2); ss << '\n' << NNUE::trace(pos, network, *caches) << '\n'; ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2) << std::setw(15); auto [psqt, positional] = network.evaluate(pos, *accumulators, *caches); Value v = psqt + positional; ss << "NNUE evaluation " << v << " (side to move, internal units)\n"; v = pos.side_to_move() == WHITE ? v : -v; ss << "NNUE evaluation " << 0.01 * UCIEngine::to_cp(v, pos) << " (white side)\n"; v = evaluate(network, pos, *accumulators, *caches, VALUE_ZERO); v = pos.side_to_move() == WHITE ? v : -v; ss << "Final evaluation "; ss << 0.01 * UCIEngine::to_cp(v, pos) << " (white side)"; ss << " [with scaled NNUE, ...]\n"; return ss.str(); } } // namespace Stockfish