diff --git a/src/main.cpp b/src/main.cpp index 7a25098..2c08f71 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,11 +40,15 @@ int main(int argc, const char* argv[]) Position::InitHashNumbers(); #if defined(PURE_HCE) Hce::init(); +#else +#if defined(IGEL_EXTERNAL_NET) + Evaluator::initEval(); // nothing embedded: wait for setoption name EvalFile #else if (!Evaluator::initEval()) { std::cout << "Fatal error: unable to load default network" << std::endl; return 1; } +#endif #endif std::unique_ptr searcher(new Search); diff --git a/src/nnue.cpp b/src/nnue.cpp index 083df25..b91bf3f 100644 --- a/src/nnue.cpp +++ b/src/nnue.cpp @@ -41,7 +41,7 @@ #if !defined(PURE_HCE) #include "incbin/incbin.h" -#if !defined(_MSC_VER) +#if !defined(_MSC_VER) && !defined(IGEL_EXTERNAL_NET) INCBIN(EmbeddedNNUE, EVALFILE); #endif // _MSC_VER @@ -85,7 +85,10 @@ EVAL Evaluator::evaluate(Position & pos) { #if !defined(PURE_HCE) bool Evaluator::initEval() { -#if !defined(_MSC_VER) +#if defined(IGEL_EXTERNAL_NET) + // no embedded network: it is loaded with setoption name EvalFile + return false; +#elif !defined(_MSC_VER) class MemoryBuffer : public std::basic_streambuf { public: MemoryBuffer(char* p, size_t n) { setg(p, p, p + n); setp(p, p + n); } }; @@ -96,7 +99,9 @@ bool Evaluator::initEval() std::ifstream stream("network_file", std::ios::binary); #endif +#if !defined(IGEL_EXTERNAL_NET) return initEval(stream); +#endif } /*static */bool Evaluator::initEval(std::istream & stream) { @@ -130,6 +135,30 @@ bool Evaluator::initEval() return stream.good() && stream.peek() == std::ios::traits_type::eof(); } +/*static */bool Evaluator::hasNetwork() +{ + return m_transformer && m_networks.size() == LAYERED_NETWORKS; +} + +#if defined(IGEL_EXTERNAL_NET) +/*static */bool Evaluator::setEvalFile(const std::string & evalFile) +{ + if (!evalFile.empty() && evalFile != "") { + std::ifstream stream(evalFile, std::ios::binary); + + if (stream && initEval(stream)) { + std::cout << "info string network " << evalFile << " loaded" << std::endl; + return true; + } + } + + m_transformer.reset(); + m_networks.clear(); + ++s_networkGeneration; + std::cout << "info string ERROR: unable to load network " << evalFile << ", no network loaded" << std::endl; + return false; +} +#else /*static */bool Evaluator::setEvalFile(const std::string & evalFile) { if (evalFile.empty() || evalFile == "") { @@ -149,6 +178,7 @@ bool Evaluator::initEval() std::cout << "info string unable to load network " << evalFile << ", default network restored" << std::endl; return false; } +#endif // IGEL_EXTERNAL_NET int Evaluator::NnueEvaluate(Position & pos) { diff --git a/src/nnue.h b/src/nnue.h index bcade6b..5c5f9cb 100644 --- a/src/nnue.h +++ b/src/nnue.h @@ -135,6 +135,7 @@ public: static bool initEval(); static bool initEval(std::istream & stream); static bool setEvalFile(const std::string & evalFile); + static bool hasNetwork(); EVAL evaluate(Position & pos); EVAL evaluateRaw(Position & pos); static EVAL fromRaw(EVAL raw, int fifty); diff --git a/src/uci.cpp b/src/uci.cpp index 805aa3c..fbb8e32 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -108,6 +108,12 @@ int Uci::handleCommands() onEval(); else if (startsWith(cmd, "gen")) onGenerate(split(cmd)); +#if defined(IGEL_EXTERNAL_NET) + else if (std::cin) { + if (!cmd.empty()) + std::cout << "info string unknown command " << cmd << std::endl; + } +#endif else { std::cout << "Unknown command. Good bye." << std::endl; onQuit(); // important to exit when stdin is gone to prevent issues in OpenBench @@ -150,6 +156,9 @@ void Uci::onUci() " max " << MAX_LEVEL << std::endl; std::cout << "option name UCI_Chess960 type check default false" << std::endl; +#if defined(IGEL_EXTERNAL_NET) + std::cout << "option name EvalFile type string default " << std::endl; +#endif std::cout << "uciok" << std::endl; } @@ -179,6 +188,14 @@ void Uci::onGo(commandParams params) assert(params[0] == "go"); +#if defined(IGEL_EXTERNAL_NET) + if (!Evaluator::hasNetwork()) { + std::cout << "info string ERROR: no network loaded, send setoption name EvalFile value " << std::endl; + std::cout << "bestmove 0000" << std::endl; + return; + } +#endif + TTable::instance().increaseAge(); m_searcher.startPrincipalSearch(time, params[1] == "ponder"); } @@ -200,6 +217,12 @@ void Uci::onPonderHit() void Uci::onEval() { +#if defined(IGEL_EXTERNAL_NET) + if (!Evaluator::hasNetwork()) { + std::cout << "info string ERROR: no network loaded" << std::endl; + return; + } +#endif std::unique_ptr evaluator(new Evaluator); std::cout << "eval: " << evaluator->evaluate(m_searcher.m_position) << std::endl; } @@ -223,6 +246,12 @@ int Uci::onBench(const char * depth, const char * evalFile) return 1; } #endif +#if defined(IGEL_EXTERNAL_NET) + if (!Evaluator::hasNetwork()) { + std::cout << "Fatal error: no network, usage: bench " << std::endl; + return 1; + } +#endif auto & time = Time::instance(); @@ -356,6 +385,14 @@ void Uci::onSetOption(commandParams params) #endif else if (name == "Ponder") ; // nothing to do, we are stateless here +#if defined(IGEL_EXTERNAL_NET) + else if (name == "EvalFile") { + std::string path = value; + for (size_t i = 5; i < params.size(); ++i) + path += " " + params[i]; + Evaluator::setEvalFile(path); + } +#endif else if (name == "UCI_Chess960") g_uci_chess960 = (value == "true" || value == "True" || value == "TRUE" || value == "1"); else