diff --git a/README.md b/README.md index e0a7da2..e5c2fff 100755 --- a/README.md +++ b/README.md @@ -147,12 +147,15 @@ Below are some features/functions we need someone helps too: Working --------- - Improve interface +- Support opening info ECO +- Support endgame adjudication, using tablebases - Support some different tournament types: swiss - Support other chess variants (not soon event it is designed for multi-variants) History -------- +- 20 July 2019: v2.6, more info and more ways to control logs, improve engine managements - 16 July 2019: v2.5, multiple ways to select openings: new for each match, same for a pair, one for all matches; override options for central controlling; match statistics LOS & error margin - 14 July 2019: v2.2, knockout tournament and resumable the last tournament - 12 July 2019: v2.0, auto generating JSON files @@ -165,7 +168,7 @@ History Terms of use --------------- -The project is released under the liberal [MIT license](http://en.wikipedia.org/wiki/MIT_License), so basically you can use it with almost no restrictions. +All codes and data in the folder 3rdparty are 3rd party libraries, copyrighted and released under their terms of use. Banksia code and data is released under the GPLv3+ license. Credits diff --git a/projects/banksia.xcodeproj/project.xcworkspace/xcuserdata/nguyenpham.xcuserdatad/UserInterfaceState.xcuserstate b/projects/banksia.xcodeproj/project.xcworkspace/xcuserdata/nguyenpham.xcuserdatad/UserInterfaceState.xcuserstate index b96af0a..2f60530 100755 Binary files a/projects/banksia.xcodeproj/project.xcworkspace/xcuserdata/nguyenpham.xcuserdatad/UserInterfaceState.xcuserstate and b/projects/banksia.xcodeproj/project.xcworkspace/xcuserdata/nguyenpham.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/projects/banksia.xcodeproj/xcshareddata/xcschemes/Banksia.xcscheme b/projects/banksia.xcodeproj/xcshareddata/xcschemes/Banksia.xcscheme index f5bf68a..4b66082 100755 --- a/projects/banksia.xcodeproj/xcshareddata/xcschemes/Banksia.xcscheme +++ b/projects/banksia.xcodeproj/xcshareddata/xcschemes/Banksia.xcscheme @@ -67,6 +67,10 @@ argument = "-u -c 16" isEnabled = "NO"> + + diff --git a/projects/banksia.xcodeproj/xcuserdata/nguyenpham.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/projects/banksia.xcodeproj/xcuserdata/nguyenpham.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 50264bd..c0d1ff8 100755 --- a/projects/banksia.xcodeproj/xcuserdata/nguyenpham.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/projects/banksia.xcodeproj/xcuserdata/nguyenpham.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -104,7 +104,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/playermng.cpp" - timestampString = "585155568.3086621" + timestampString = "585303695.216538" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "142" @@ -120,7 +120,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/playermng.cpp" - timestampString = "585155568.30871" + timestampString = "585303695.21659" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "153" @@ -136,7 +136,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/configmng.h" - timestampString = "585155568.308745" + timestampString = "585289246.194873" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "94" @@ -168,7 +168,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/base/comm.h" - timestampString = "585155568.309171" + timestampString = "585303695.216666" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "98" @@ -184,7 +184,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/wbengine.cpp" - timestampString = "585155568.309248" + timestampString = "585303695.216942" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "406" @@ -200,7 +200,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/wbengine.cpp" - timestampString = "585155568.3093179" + timestampString = "585303695.216979" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "433" @@ -216,7 +216,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/wbengine.cpp" - timestampString = "585155568.309348" + timestampString = "585303695.21701" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "444" @@ -232,7 +232,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/wbengine.cpp" - timestampString = "585155568.309378" + timestampString = "585303695.2170399" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "457" @@ -248,7 +248,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/wbengine.cpp" - timestampString = "585155568.309407" + timestampString = "585303695.21707" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "407" @@ -264,12 +264,12 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/chess/chess.cpp" - timestampString = "585155568.309525" + timestampString = "585303695.2171" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1217" - endingLineNumber = "1217" - landmarkName = "ChessBoard::toMoveListString(MoveNotation notation, int itemPerLine, bool moveCounter)" + startingLineNumber = "1218" + endingLineNumber = "1218" + landmarkName = "ChessBoard::toMoveListString(MoveNotation notation, int itemPerLine, bool moveCounter, bool computingInfo)" landmarkType = "7"> @@ -280,11 +280,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/chess/chess.cpp" - timestampString = "585155568.309795" + timestampString = "585303695.217132" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1115" - endingLineNumber = "1115" + startingLineNumber = "1116" + endingLineNumber = "1116" landmarkName = "ChessBoard::checkMake(int from, int dest, PieceType promotion)" landmarkType = "7"> @@ -296,11 +296,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/chess/chess.cpp" - timestampString = "585155568.309974" + timestampString = "585303695.21716" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1116" - endingLineNumber = "1116" + startingLineNumber = "1117" + endingLineNumber = "1117" landmarkName = "ChessBoard::checkMake(int from, int dest, PieceType promotion)" landmarkType = "7"> @@ -312,7 +312,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/wbengine.cpp" - timestampString = "585155568.31015" + timestampString = "585303695.217189" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "412" @@ -328,11 +328,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.91804" + timestampString = "585303695.2172199" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "518" - endingLineNumber = "518" + startingLineNumber = "515" + endingLineNumber = "515" landmarkName = "BookMng::getRandomBook(int pairId, std::string& fenString, std::vector<Move>& moves)" landmarkType = "7"> @@ -344,11 +344,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.918545" + timestampString = "585303695.217473" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "407" - endingLineNumber = "407" + startingLineNumber = "404" + endingLineNumber = "404" landmarkName = "BookMng::load(const Json::Value& obj)" landmarkType = "7"> @@ -360,11 +360,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/chess/chess.cpp" - timestampString = "585155568.310249" + timestampString = "585303695.217652" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1333" - endingLineNumber = "1333" + startingLineNumber = "1349" + endingLineNumber = "1349" landmarkName = "ChessBoard::fromSanString(const std::string& str)" landmarkType = "7"> @@ -376,11 +376,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/chess/chess.cpp" - timestampString = "585155568.310426" + timestampString = "585303695.217685" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1353" - endingLineNumber = "1353" + startingLineNumber = "1369" + endingLineNumber = "1369" landmarkName = "ChessBoard::fromSanString(const std::string& str)" landmarkType = "7"> @@ -392,7 +392,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/main.cpp" - timestampString = "585157095.918952" + timestampString = "585303695.217718" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "48" @@ -408,7 +408,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/tourmng.h" - timestampString = "585155568.310829" + timestampString = "585303695.217957" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "106" @@ -424,11 +424,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.919193" + timestampString = "585303695.218208" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "463" - endingLineNumber = "463" + startingLineNumber = "460" + endingLineNumber = "460" landmarkName = "BookMng::loadSingle(const Json::Value& obj)" landmarkType = "7"> @@ -440,7 +440,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.919556" + timestampString = "585303695.2183861" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "107" @@ -456,7 +456,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.919894" + timestampString = "585303695.2185611" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "106" @@ -472,7 +472,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.9202271" + timestampString = "585303695.218735" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "93" @@ -488,11 +488,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/chess/chess.cpp" - timestampString = "585155568.311058" + timestampString = "585303695.218907" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1401" - endingLineNumber = "1401" + startingLineNumber = "1417" + endingLineNumber = "1417" landmarkName = "ChessBoard::fromSanMoveList(const std::string& str)" landmarkType = "7"> @@ -504,11 +504,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.920579" + timestampString = "585303695.218941" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "293" - endingLineNumber = "293" + startingLineNumber = "290" + endingLineNumber = "290" landmarkName = "BookPolyglot::getRandomBook(std::string& fenString, std::vector<Move>& moveList)" landmarkType = "7"> @@ -520,11 +520,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.9209189" + timestampString = "585303695.219116" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "294" - endingLineNumber = "294" + startingLineNumber = "291" + endingLineNumber = "291" landmarkName = "BookPolyglot::getRandomBook(std::string& fenString, std::vector<Move>& moveList)" landmarkType = "7"> @@ -536,11 +536,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.921252" + timestampString = "585303695.219378" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "513" - endingLineNumber = "513" + startingLineNumber = "510" + endingLineNumber = "510" landmarkName = "BookMng::getRandomBook(int pairId, std::string& fenString, std::vector<Move>& moves)" landmarkType = "7"> @@ -552,11 +552,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.921591" + timestampString = "585303695.219614" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "540" - endingLineNumber = "540" + startingLineNumber = "537" + endingLineNumber = "537" landmarkName = "BookMng::getRandomBook(int pairId, std::string& fenString, std::vector<Move>& moves)" landmarkType = "7"> @@ -568,11 +568,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.9219199" + timestampString = "585303695.219802" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "291" - endingLineNumber = "291" + startingLineNumber = "288" + endingLineNumber = "288" landmarkName = "BookPolyglot::getRandomBook(std::string& fenString, std::vector<Move>& moveList)" landmarkType = "7"> @@ -584,14 +584,126 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "../src/game/book.cpp" - timestampString = "585157095.922245" + timestampString = "585303695.219985" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "511" - endingLineNumber = "511" + startingLineNumber = "508" + endingLineNumber = "508" landmarkName = "BookMng::getRandomBook(int pairId, std::string& fenString, std::vector<Move>& moves)" landmarkType = "7"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/base/base.h b/src/base/base.h index bc57cd8..6826095 100755 --- a/src/base/base.h +++ b/src/base/base.h @@ -248,7 +248,8 @@ namespace banksia { int8_t castleRights[2]; u64 hashKey; int quietCnt; - double elapsed; + int score = 0, depth = 0; + double elapsed = 0; std::string moveString, comment; void set(const MoveFull& _move) { @@ -270,7 +271,7 @@ namespace banksia { int status; Result result; - + public: void reset() { for (auto && p : pieces) { diff --git a/src/base/comm.cpp b/src/base/comm.cpp index 11b6c7d..289c145 100755 --- a/src/base/comm.cpp +++ b/src/base/comm.cpp @@ -35,6 +35,8 @@ #include #include // for full path +#include // for isRunning + #else #include @@ -42,13 +44,16 @@ #include #include +#include +#include + #endif #include "comm.h" namespace banksia { - bool banksiaVerbose = false; + bool banksiaVerbose = true; extern const char* pieceTypeName; extern const char* reasonStrings[11]; @@ -63,6 +68,13 @@ namespace banksia { "*", "1-0", "1/2-1/2", "0-1", nullptr }; + const char* sideStrings[] = { + "black", "white", "none", nullptr + }; + const char* shortSideStrings[] = { + "b", "w", "n", nullptr + }; + static std::mutex consoleMutex; std::string resultType2String(ResultType type) { @@ -95,6 +107,25 @@ namespace banksia { return ReasonType::noreason; } + std::string side2String(Side side, bool shortFrom) + { + auto sd = static_cast(side); + if (sd < 0 || sd > 1) sd = 2; + return shortFrom ? shortSideStrings[sd] : sideStrings[sd]; + } + + Side string2Side(std::string s) + { + toLower(s); + for(int i = 0; sideStrings[i]; i++) { + if (sideStrings[i] == s || shortSideStrings[i] == s) { + return static_cast(i); + } + } + return Side::none; + + } + void printText(const std::string& str) { std::lock_guard dolock(consoleMutex); @@ -332,6 +363,29 @@ namespace banksia { return path.find(".exe") != std::string::npos; } + bool isRunning(int pid) + { + HANDLE pss = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + + PROCESSENTRY32 pe = { 0 }; + pe.dwSize = sizeof(pe); + + if (Process32First(pss, &pe)) + { + do + { + // pe.szExeFile can also be useful + if (pe.th32ProcessID == pid) + return true; + } + while(Process32Next(pss, &pe)); + } + + CloseHandle(pss); + + return false; + } + #else std::vector listdir(std::string dirname) { @@ -383,6 +437,11 @@ namespace banksia { return !access(path.c_str(), X_OK); } + bool isRunning(int pid) + { + return 0 == kill(pid, 0); + } + #endif diff --git a/src/base/comm.h b/src/base/comm.h index 6427a53..98c6c6f 100755 --- a/src/base/comm.h +++ b/src/base/comm.h @@ -40,7 +40,7 @@ namespace banksia { - const int BANKSIA_VERSION = (2 << 8) + 52; + const int BANKSIA_VERSION = (2 << 8) + 6; #ifdef _WIN32 const std::string folderSlash = "\\"; @@ -178,6 +178,7 @@ namespace banksia { std::vector listdir(std::string dirname); i64 getFileSize(const std::string& path); bool isExecutable(const std::string& path); + bool isRunning(int pid); std::vector splitString(const std::string& string, const std::string& regexString); std::vector splitString(const std::string &s, char delim); @@ -187,6 +188,9 @@ namespace banksia { std::string reasonType2String(ReasonType type); ReasonType string2ReasonType(const std::string& s); + std::string side2String(Side side, bool shortFrom = true); + Side string2Side(const std::string& s); + } // namespace banksia #endif /* Board_hpp */ diff --git a/src/chess/chess.cpp b/src/chess/chess.cpp index 3f7e129..40d5e96 100755 --- a/src/chess/chess.cpp +++ b/src/chess/chess.cpp @@ -23,6 +23,7 @@ */ #include +#include // for setprecision #include "chess.h" @@ -1209,7 +1210,7 @@ bool ChessBoard::createStringForLastMove(const MoveList& moveList) return true; } -std::string ChessBoard::toMoveListString(MoveNotation notation, int itemPerLine, bool moveCounter) const +std::string ChessBoard::toMoveListString(MoveNotation notation, int itemPerLine, bool moveCounter, bool computingInfo) const { std::ostringstream stringStream; @@ -1235,10 +1236,25 @@ std::string ChessBoard::toMoveListString(MoveNotation notation, int itemPerLine, } // Comment + auto haveComment = false; + if (computingInfo && hist.depth > 0) { + haveComment = true; + stringStream << " {" << (hist.score > 0 ? "+" : "") + << std::setprecision(2) << ((float)hist.score / 100.0) << "/" + << hist.depth + << " " << std::setprecision(2) << hist.elapsed; + } if (!hist.comment.empty() && moveCounter) { - stringStream << " {" << hist.comment << "} "; + stringStream << (haveComment ? "; " : " {"); + + haveComment = true; + stringStream << hist.comment ; } - + + if (haveComment) { + stringStream << "} "; + } + c++; if (itemPerLine > 0 && c >= itemPerLine) { c = 0; diff --git a/src/chess/chess.h b/src/chess/chess.h index ca9b209..62d925d 100755 --- a/src/chess/chess.h +++ b/src/chess/chess.h @@ -80,7 +80,7 @@ namespace banksia { bool checkMake(int from, int dest, PieceType promotion); - std::string toMoveListString(MoveNotation notation, int itemPerLine, bool moveCounter) const; + std::string toMoveListString(MoveNotation notation, int itemPerLine, bool moveCounter, bool computingInfo) const; Move fromSanString(const std::string&); bool fromSanMoveList(const std::string&); diff --git a/src/game/book.cpp b/src/game/book.cpp index ffaa562..d92055c 100755 --- a/src/game/book.cpp +++ b/src/game/book.cpp @@ -227,9 +227,6 @@ void BookPolyglot::load(const std::string& _path, int _maxPly, int _top100) for(int i = 0; i < itemCnt; i++) { items[i].convertToLittleEndian(); } - - std::cout << "BookPolyglot::load " << path << ", itemCnt: " << itemCnt << std::endl; - } bool BookPolyglot::isValid() const diff --git a/src/game/configmng.cpp b/src/game/configmng.cpp index 150baf3..cd17c82 100755 --- a/src/game/configmng.cpp +++ b/src/game/configmng.cpp @@ -249,7 +249,7 @@ void Option::setDefaultValue(const std::string& val, const std::vectorjoinable()) { + std::cout << "Warning 2: a chess engine/program refuses to stop, it may be still running, " << name << std::endl; + pThread->join(); + } + } void Engine::tickWork() @@ -60,7 +70,7 @@ void Engine::tickWork() if (tick_being_kill == 0) { TinyProcessLib::Process::kill(processId, true); process = nullptr; - deleteThread(); +// deleteThread(); setState(PlayerState::stopped); finished(); } @@ -186,17 +196,6 @@ void Engine::parseLine(const std::string& line) parseLine(it->second, cmdString, line); } -void Engine::deleteThread() -{ - if (pThread && pThread->joinable()) { -#ifndef _WIN32 - pthread_cancel(pThread->native_handle()); -#endif - pThread = nullptr; - std::cout << "Warning: thread is still resident " << name << std::endl; - } -} - bool Engine::kickStart() { resetPing(); @@ -244,6 +243,7 @@ bool Engine::kickStart() pThread = nullptr; }); + native_handle = processThread.native_handle(); pThread = &processThread; processThread.detach(); return true; @@ -258,6 +258,10 @@ void Engine::attach(ChessBoard* board, const GameTimeController* timeController, Player::attach(board, timeController, moveFunc, resignFunc); tick_deattach = -1; tick_idle = 0; + + if (board == nullptr) { + messageLogger = nullptr; + } } bool Engine::isSafeToDeattach() const diff --git a/src/game/engine.h b/src/game/engine.h index c607c86..d972bef 100755 --- a/src/game/engine.h +++ b/src/game/engine.h @@ -113,7 +113,6 @@ namespace banksia { int tick_ping, tick_idle, tick_being_kill = -1; //, tick_stopping = 0; std::function messageLogger = nullptr; - void deleteThread(); int correctCmdCnt = 0; private: @@ -122,6 +121,10 @@ namespace banksia { TinyProcessLib::Process::id_type processId = 0; TinyProcessLib::Process* process = nullptr; std::thread* pThread = nullptr; + +#ifndef _WIN32 + std::thread::native_handle_type native_handle = 0; +#endif }; diff --git a/src/game/game.cpp b/src/game/game.cpp index 6d616ac..c596f86 100755 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -196,18 +196,21 @@ void Game::moveFromPlayer(const Move& move, const std::string& moveString, const } assert(board.side == side); + auto sd = static_cast(board.side); + if (oldState == EngineComputingState::thinking) { if (make(move, moveString)) { assert(board.side != side); - auto lastHist = board.histList.back(); + auto& lastHist = board.histList.back(); lastHist.elapsed = timeConsumed; + lastHist.score = players[sd]->getScore(); + lastHist.depth = players[sd]->getDepth(); timeController.udateClockAfterMove(timeConsumed, lastHist.move.piece.side, int(board.histList.size())); startThinking(ponderMode ? ponderMove : Move::illegalMove); } } else if (oldState == EngineComputingState::pondering) { // missed ponderhit, stop called - auto sd = static_cast(board.side); players[sd]->go(); } } @@ -257,15 +260,24 @@ void Game::gameOver(const Result& result) Player* Game::getPlayer(Side side) { - auto sd = static_cast(side); - return players[sd]; + return players[static_cast(side)]; +} + +const Player* Game::getPlayer(Side side) const +{ + return players[static_cast(side)]; } -std::string Game::getGameTitleString() const +std::string Game::getGameTitleString(bool includeResult) const { std::string str; str += players[W] ? players[W]->getName() : "*"; - str += " vs " + (players[B] ? players[B]->getName() : "*"); + if (includeResult) { + str += " (" + board.result.toShortString() + ") "; + } else { + str += " vs "; + } + str += (players[B] ? players[B]->getName() : "*"); return str; } @@ -396,7 +408,7 @@ void Game::tickWork() } -std::string Game::toPgn(std::string event, std::string site, int round, int gameIdx) const +std::string Game::toPgn(std::string event, std::string site, int round, int gameIdx, bool richMode) const { std::ostringstream stringStream; @@ -441,7 +453,7 @@ std::string Game::toPgn(std::string event, std::string site, int round, int game } // Move text - stringStream << board.toMoveListString(MoveNotation::san, 8, true); + stringStream << board.toMoveListString(MoveNotation::san, 8, true, richMode); if (board.result.result != ResultType::noresult) { if (board.histList.size() % 8 != 0) stringStream << " "; diff --git a/src/game/game.h b/src/game/game.h index cfae871..5f8fb6b 100755 --- a/src/game/game.h +++ b/src/game/game.h @@ -54,7 +54,6 @@ namespace banksia { void newGame(); void kickStart(); -// void startPlaying(); void pause(); void stop(); bool make(const Move& move, const std::string& moveString); @@ -72,7 +71,8 @@ namespace banksia { virtual void tickWork() override; Player* getPlayer(Side side); - + const Player* getPlayer(Side side) const; + GameState getState() const { return state; } void setState(GameState st); @@ -80,9 +80,9 @@ namespace banksia { int getIdx() const; int getStateTick() const { return stateTick; } - std::string toPgn(std::string event = "", std::string site = "", int round = -1, int gameIdx = -1) const; + std::string toPgn(std::string event = "", std::string site = "", int round = -1, int gameIdx = -1, bool richMode = false) const; - std::string getGameTitleString() const; + std::string getGameTitleString(bool includeResult = false) const; public: ChessBoard board; diff --git a/src/game/player.cpp b/src/game/player.cpp index f6b17c3..9283fa5 100755 --- a/src/game/player.cpp +++ b/src/game/player.cpp @@ -62,6 +62,7 @@ void Player::setState(PlayerState st) state = st; tick_state = 0; } + void Player::attach(ChessBoard* _board, const GameTimeController* _timeController, std::function _moveReceiver, std::function _resignFunc) @@ -91,6 +92,7 @@ bool Player::goPonder(const Move& pondermove) bool Player::go() { setState(PlayerState::playing); + score = depth = 0; return true; } diff --git a/src/game/player.h b/src/game/player.h index ad68b74..82b3039 100755 --- a/src/game/player.h +++ b/src/game/player.h @@ -79,13 +79,21 @@ namespace banksia { virtual bool go(); virtual bool oppositeMadeMove(const Move& move, const std::string& sanMoveString); + int getScore() const { + return score; + } + + int getDepth() const { + return depth; + } + protected: int idNumber; // a random number, main purpose for debugging std::string name; PlayerType type; PlayerState state; - int tick_state = 0; + int tick_state = 0, score, depth; bool ponderMode = false; diff --git a/src/game/playermng.cpp b/src/game/playermng.cpp index 40fe34c..f601d63 100755 --- a/src/game/playermng.cpp +++ b/src/game/playermng.cpp @@ -61,7 +61,7 @@ void PlayerMng::tickWork() if (it != playerList.end()) { playerList.erase(it); } - killPlayer(player); + removePlayer(player); } } @@ -117,11 +117,11 @@ bool PlayerMng::returnPlayer(Player* player) return true; } - return killPlayer(player); + return removePlayer(player); } -bool PlayerMng::killPlayer(Player* player) +bool PlayerMng::removePlayer(Player* player) { if (player == nullptr) return false; diff --git a/src/game/playermng.h b/src/game/playermng.h index 5468697..e6b394d 100755 --- a/src/game/playermng.h +++ b/src/game/playermng.h @@ -55,7 +55,7 @@ namespace banksia { void shutdown(); private: - bool killPlayer(Player* player); + bool removePlayer(Player* player); private: std::mutex thelock; diff --git a/src/game/tourmng.cpp b/src/game/tourmng.cpp index 43583eb..5d2b1b0 100755 --- a/src/game/tourmng.cpp +++ b/src/game/tourmng.cpp @@ -70,9 +70,11 @@ bool MatchRecord::load(const Json::Value& obj) } auto s = obj["result"].asString(); - resultType = string2ResultType(s); - - state = resultType == ResultType::noresult ? MatchState::none : MatchState::completed; + result.result = string2ResultType(s); + s = obj["reason"].asString(); + result.reason= string2ReasonType(s); + + state = result.result == ResultType::noresult ? MatchState::none : MatchState::completed; gameIdx = obj["gameIdx"].asInt(); round = obj["round"].asInt(); @@ -103,7 +105,8 @@ Json::Value MatchRecord::saveToJson() const obj["startMoves"] = moves; } - obj["result"] = resultType2String(resultType); + obj["result"] = resultType2String(result.result); + obj["reason"] = reasonType2String(result.reason); obj["gameIdx"] = gameIdx; obj["round"] = round; obj["pairId"] = pairId; @@ -208,7 +211,7 @@ void TourMng::fixJson(Json::Value& d, const std::string& path) d[s] = v; } - s = "opening books"; + s = "openings"; if (!d.isMember(s)) { const static std::string obString = "{ \"base\" : { \"allone fen\" : \"\", \"allone san moves\" : \"\", \"seed\" : -1, \"select type\" : \"allnew\",\ @@ -256,25 +259,32 @@ void TourMng::fixJson(Json::Value& d, const std::string& path) if (!a.isMember(s)) { Json::Value v; v["mode"] = true; + v["one file"] = true; + v["rich info"] = false; + v["game title surfix"] = true; + v["guide"] = "one file: if false, games are stored in multi files using game indexes as surfix; game title surfix: use players names, results for file name surfix, affective only when 'one file' is false; rich info: log more info such as scores, depths, elapses"; v["path"] = path + folderSlash + "games.pgn"; a[s] = v; } - s = "result"; + s = "engine"; if (!a.isMember(s)) { Json::Value v; v["mode"] = true; - v["path"] = path + folderSlash + "logresult.txt"; + v["show time"] = true; + v["one file"] = false; + v["game title surfix"] = true; + v["separate by sides"] = false; + v["guide"] = "one file: if false, games are stored in multi files using game indexes as surfix; game title surfix: use players names, results for file name surfix, affective only when 'one file' is false; separate by sides: each side has different logs"; + v["path"] = path + folderSlash + "logengine.txt"; a[s] = v; } - s = "engine"; + s = "result"; if (!a.isMember(s)) { Json::Value v; v["mode"] = true; - v["show time"] = true; - v["all in one"] = false; - v["path"] = path + folderSlash + "logengine.txt"; + v["path"] = path + folderSlash + "logresult.txt"; a[s] = v; } @@ -394,12 +404,18 @@ bool TourMng::parseJsonAfterLoading(Json::Value& d) // // Less inportance // - s = "opening books"; - if (d.isMember(s)) { - auto obj = d[s]; + s = "openings"; + if (d.isMember(s) || d.isMember("opening books")) { + auto obj = d[d.isMember(s) ? s : "opening books"]; bookMng.load(obj); } - + + // TODO: endgames +// s = "endgames"; +// if (d.isMember(s)) { +// auto obj = d[s]; +// } + s = "logs"; if (d.isMember(s)) { auto a = d[s]; @@ -408,8 +424,23 @@ bool TourMng::parseJsonAfterLoading(Json::Value& d) auto v = a[s]; pgnPathMode = v["mode"].asBool(); pgnPath = v["path"].asString(); + logPgnAllInOneMode = !v.isMember("one file") || v["one file"].asBool(); + logPgnGameTitleSurfix = v.isMember("game title surfix") && v["game title surfix"].asBool(); + logPgnRichMode = v.isMember("rich info") && v["rich info"].asBool(); } + s = "engine"; + if (a.isMember(s)) { + auto v = a[s]; + logEngineMode = v["mode"].asBool(); + logEngineAllInOneMode = v.isMember("one file") && v["one file"].asBool(); + logEngineBySides = v.isMember("separate by sides") && v["separate by sides"].asBool(); + + logEngineGameTitleSurfix = v.isMember("game title surfix") && v["game title surfix"].asBool(); + logEngineShowTime = v.isMember("show time") && v["show time"].asBool(); + logEnginePath = v["path"].asString(); + } + s = "result"; if (a.isMember(s)) { auto v = a[s]; @@ -417,14 +448,6 @@ bool TourMng::parseJsonAfterLoading(Json::Value& d) logResultPath = v["path"].asString(); } - s = "engine"; - if (a.isMember(s)) { - auto v = a[s]; - logEngineInOutMode = v["mode"].asBool(); - logEngineAllInOneMode = v.isMember("all in one") && v["all in one"].asBool(); - logEngineInOutShowTime = v.isMember("show time") && v["show time"].asBool(); - logEngineInOutPath = v["path"].asString(); - } } return true; @@ -447,8 +470,18 @@ void TourMng::tickWork() break; case GameState::ended: + { + for(int sd = 0; sd < 2; sd++) { + auto side = static_cast(sd); + auto player = game->getPlayer(side); + if (player) { + player->quit(); + } + } + stoppedGameList.push_back(game); break; + } default: break; } @@ -501,11 +534,11 @@ void TourMng::startTournament() + ", ponder: " + bool2OnOffString(ponderMode) + ", book: " + bool2OnOffString(!bookMng.isEmpty()); - matchLog(info); + matchLog(info, true); showPathInfo("pgn", pgnPath, pgnPathMode); showPathInfo("result", logResultPath, logResultMode); - showPathInfo("engines", logEngineInOutPath, logEngineInOutMode); + showPathInfo("engines", logEnginePath, logEngineMode); std::cout << std::endl; // tickWork will start the matches @@ -521,11 +554,11 @@ void TourMng::finishTournament() if (!matchRecordList.empty()) { auto str = createTournamentStats(); - matchLog(str); + matchLog(str, true); } auto str = "Tournamemt finished! Elapsed: " + formatPeriod(elapsed_secs); - matchLog(str); + matchLog(str, true); removeMatchRecordFile(); @@ -538,8 +571,9 @@ std::string TourMng::createTournamentStats() { std::map resultMap; + auto abnormalCnt = 0; for(auto && m : matchRecordList) { - if (m.resultType == ResultType::noresult) { // hm + if (m.result.result == ResultType::noresult) { // hm continue; } @@ -556,8 +590,9 @@ std::string TourMng::createTournamentStats() r = it->second; assert(r.name == name); } + auto lossCnt = r.lossCnt; r.gameCnt++; - switch (m.resultType) { + switch (m.result.result) { case ResultType::win: if (sd == W) r.winCnt++; else r.lossCnt++; break; @@ -571,6 +606,13 @@ std::string TourMng::createTournamentStats() assert(false); break; } + + if (lossCnt < r.lossCnt) { + if (m.result.reason == ReasonType::illegalmove || m.result.reason == ReasonType::crash || m.result.reason == ReasonType::timeout) { + r.abnormalCnt++; + abnormalCnt++; + } + } resultMap[name] = r; } } @@ -591,7 +633,7 @@ std::string TourMng::createTournamentStats() std::stringstream stringStream; - auto separateLineSz = maxNameLen + 68; + auto separateLineSz = maxNameLen + 68 + (abnormalCnt ? 20 : 0); for(int i = 0; i < separateLineSz; i++) { stringStream << "-"; } @@ -599,8 +641,10 @@ std::string TourMng::createTournamentStats() stringStream << " # " << std::left << std::setw(maxNameLen + 2) << "name" - << "games wins% draws% losses% score los% elo+/-" << std::endl; - + << "games wins% draws% losses% score los% elo+/-" + << (abnormalCnt ? " fails" : "") + << std::endl; + for(int i = 0; i < resultList.size(); i++) { auto r = resultList.at(i); @@ -609,6 +653,7 @@ std::string TourMng::createTournamentStats() double score = double(r.winCnt) + double(r.drawCnt) / 2; Elo elo(r.winCnt, r.drawCnt, r.lossCnt); + stringStream << std::right << std::setw(3) << (i + 1) << ". " << std::left << std::setw(maxNameLen + 2) << r.name @@ -619,15 +664,22 @@ std::string TourMng::createTournamentStats() << std::right << std::setw(9) << loss // << std::left << std::setw(0) << "%" << std::right << std::setw(9) << score << std::right << std::setw(9) << elo.los * 100 - << std::right << std::setw(9) << elo.elo_difference - << std::left << std::setw(0) - << std::endl; + << std::right << std::setw(9) << elo.elo_difference; + + if (r.abnormalCnt) { + stringStream << std::right << std::setw(9) << r.abnormalCnt; + } + + stringStream << std::left << std::setw(0) << std::endl; } for(int i = 0; i < separateLineSz; i++) { stringStream << "-"; } - stringStream << std::endl << std::endl; + + if (abnormalCnt) { + stringStream << std::endl << "Failed games (timeout, crashed, illegal moves): " << abnormalCnt << " of " << matchRecordList.size(); + } return stringStream.str(); } @@ -715,10 +767,10 @@ void TourMng::checkToExtendMatches(int gIdx) if (rcd.state != MatchState::completed) { return; } - if (rcd.resultType != ResultType::win && rcd.resultType != ResultType::loss) { + if (rcd.result.result != ResultType::win && rcd.result.result != ResultType::loss) { continue; } - auto winnerName = rcd.playernames[(rcd.resultType == ResultType::win ? W : B)]; + auto winnerName = rcd.playernames[(rcd.result.result == ResultType::win ? W : B)]; playerPair.pair[playerPair.pair[W].name == winnerName ? W : B].winCnt++; auto whiteIdx = playerPair.pair[W].name == rcd.playernames[W] ? W : B; @@ -728,12 +780,12 @@ void TourMng::checkToExtendMatches(int gIdx) // It is a tie if two players have same wins and same times to play white if (playerPair.pair[0].winCnt == playerPair.pair[1].winCnt && playerPair.pair[0].whiteCnt == playerPair.pair[1].whiteCnt) { MatchRecord record = r; - record.resultType = ResultType::noresult; + record.result.result = ResultType::noresult; record.state = MatchState::none; addMatchRecord_simple(record); auto str = "* Tied! Add one more game for " + record.playernames[W] + " vs " + record.playernames[B]; - matchLog(str); + matchLog(str, banksiaVerbose); } break; } @@ -772,9 +824,9 @@ std::vector TourMng::getKnockoutWinnerList() thePair.pair[1].name = r.playernames[1]; } - if (r.resultType == ResultType::win || r.resultType == ResultType::loss) { + if (r.result.result == ResultType::win || r.result.result == ResultType::loss) { auto idxW = thePair.pair[W].name == r.playernames[W] ? W : B; - auto winIdx = r.resultType == ResultType::win ? idxW : (1 - idxW); + auto winIdx = r.result.result == ResultType::win ? idxW : (1 - idxW); thePair.pair[winIdx].winCnt++; } auto whiteSd = thePair.pair[W].name == r.playernames[W] ? W : B; @@ -820,7 +872,7 @@ bool TourMng::createKnockoutMatchList(std::vector playerVec, int rou if (playerVec.size() < 2) { if (playerVec.size() == 1) { auto str = "\n* The winner is " + playerVec.front().name; - matchLog(str); + matchLog(str, true); } return false; } @@ -857,12 +909,12 @@ bool TourMng::createKnockoutMatchList(std::vector playerVec, int rou MatchRecord record(luckPlayer.name, "", false); record.round = round; record.state = MatchState::completed; - record.resultType = ResultType::win; // win + record.result.result = ResultType::win; // win record.pairId = std::rand(); addMatchRecord_simple(record); auto str = "\n* Player " + luckPlayer.name + " is an odd (no opponent in " + std::to_string(playerVec.size()) + " players) and set won for round " + std::to_string(round + 1); - matchLog(str); + matchLog(str, banksiaVerbose); } std::sort(playerVec.begin(), playerVec.end(), [](const TourPlayer& lhs, const TourPlayer& rhs) @@ -886,7 +938,7 @@ bool TourMng::createKnockoutMatchList(std::vector playerVec, int rou auto str = "\nKnockout round: " + std::to_string(round + 1) + ", pairs: " + std::to_string(n) + ", matches: " + std::to_string(uncompletedMatches()); - matchLog(str); + matchLog(str, true); return addCnt > 0; } @@ -989,14 +1041,21 @@ bool TourMng::createMatch(int gameIdx, const std::string& whiteName, const std:: if (addGame(game)) { game->setMessageLogger([=](const std::string& name, const std::string& line, LogType logType) { - engineLog(gameIdx, name, line, logType); + auto white = game->getPlayer(Side::white); + auto fromSide = white && white->getName() == name ? Side::white : Side::black; + engineLog(game, name, line, logType, fromSide); }); game->kickStart(); std::string infoString = std::to_string(gameIdx + 1) + ". " + game->getGameTitleString(); - printText(infoString); - engineLog(gameIdx, getAppName(), "\n" + infoString + "\n", LogType::system); + if (banksiaVerbose) { + printText(infoString); + } + + if (!logEngineBySides) { + engineLog(game, getAppName(), "\n" + infoString + "\n", LogType::system); + } return true; } @@ -1009,6 +1068,31 @@ bool TourMng::createMatch(int gameIdx, const std::string& whiteName, const std:: return false; } +std::string TourMng::createLogPath(std::string opath, bool onefile, bool usesurfix, bool includeGameResult, const Game* game, Side forSide) +{ + if (onefile || game == nullptr) return opath; + + std::string s = (usesurfix ? ", " : "-") + std::to_string(game->getIdx() + 1); + if (usesurfix) { + if (!game->getPlayer(Side::white) || !game->getPlayer(Side::black)) { + return ""; + } + s += ") " + game->getGameTitleString(includeGameResult); + } + + if (forSide != Side::none) { + s += ", " + side2String(forSide, true); + } + + auto p = opath.rfind("."); + if (p == std::string::npos) { + opath += s; + } else { + opath = opath.substr(0, p) + s + opath.substr(p); + } + return opath; +} + void TourMng::matchCompleted(Game* game) { if (game == nullptr) return; @@ -1018,26 +1102,28 @@ void TourMng::matchCompleted(Game* game) auto record = &matchRecordList[gIdx]; assert(record->state == MatchState::playing); record->state = MatchState::completed; - record->resultType = game->board.result.result; - assert(matchRecordList[gIdx].resultType == game->board.result.result); + record->result = game->board.result; if (pgnPathMode && !pgnPath.empty()) { - auto pgnString = game->toPgn(eventName, siteName, record->round, record->gameIdx); - append2TextFile(pgnPath, pgnString); + auto pgnString = game->toPgn(eventName, siteName, record->round, record->gameIdx, logPgnRichMode); + auto path = createLogPath(pgnPath, logPgnAllInOneMode, logPgnGameTitleSurfix, true, game); + if (!path.empty()) { + append2TextFile(path, pgnString); + } } } - if (logResultMode || banksiaVerbose) { // log - auto wplayer = game->getPlayer(Side::white), bplayer = game->getPlayer(Side::black); - if (wplayer && bplayer) { - std::string infoString = std::to_string(gIdx + 1) + ") " + game->getGameTitleString() + ", #" + std::to_string(game->board.histList.size()) + ", " + game->board.result.toString(); - - matchLog(infoString); - // Add extra info to help understanding log - engineLog(game->getIdx(), getAppName(), infoString, LogType::system); + auto wplayer = game->getPlayer(Side::white), bplayer = game->getPlayer(Side::black); + if (wplayer && bplayer) { + std::string infoString = std::to_string(gIdx + 1) + ") " + game->getGameTitleString() + ", #" + std::to_string(game->board.histList.size()) + ", " + game->board.result.toString(); + + matchLog(infoString, banksiaVerbose); + // Add extra info to help understanding log + if (!logEngineBySides) { + engineLog(game, getAppName(), infoString, LogType::system); } } - + checkToExtendMatches(gIdx); saveMatchRecords(); @@ -1057,17 +1143,19 @@ bool TourMng::addGame(Game* game) void TourMng::setEngineLogMode(bool enabled) { - logEngineInOutMode = enabled; + logEngineMode = enabled; } void TourMng::setEngineLogPath(const std::string& path) { - logEngineInOutPath = path; + logEnginePath = path; } -void TourMng::matchLog(const std::string& infoString) +void TourMng::matchLog(const std::string& infoString, bool verbose) { - printText(infoString); + if (verbose) { + printText(infoString); + } if (logResultMode && !logResultPath.empty()) { std::lock_guard dolock(matchMutex); @@ -1080,21 +1168,27 @@ void TourMng::showEgineInOutToScreen(bool enabled) logScreenEngineInOutMode = enabled; } -void TourMng::engineLog(int gameIdx, const std::string& name, const std::string& line, LogType logType) +void TourMng::engineLog(const Game* game, const std::string& name, const std::string& line, LogType logType, Side bySide) { - if (line.empty() || !logEngineInOutMode || logEngineInOutPath.empty()) return; + if (line.empty() || !logEngineMode || logEnginePath.empty()) return; std::ostringstream stringStream; + auto gameIdx = game ? game->getIdx() : -1; if (logEngineAllInOneMode && gameIdx >= 0 && gameConcurrency > 1) { stringStream << (gameIdx + 1) << "."; } - if (logEngineInOutShowTime) { + if (logEngineShowTime) { auto tm = localtime_xp(std::time(0)); stringStream << std::put_time(&tm, "%H:%M:%S "); } - stringStream << name << (logType == LogType::toEngine ? "< " : "> ") << line; + + if (!logEngineBySides && bySide != Side::none) { + stringStream << name; + } + + stringStream << (logType == LogType::toEngine ? "< " : "> ") << line; auto str = stringStream.str(); @@ -1102,18 +1196,16 @@ void TourMng::engineLog(int gameIdx, const std::string& name, const std::string& printText(str); } - auto path = logEngineInOutPath; - if (!logEngineAllInOneMode) { - auto s = "-" + std::to_string(gameIdx + 1); - auto p = path.rfind("."); - if (p == std::string::npos) { - path += s; - } else { - path = path.substr(0, p) + s + path.substr(p); - } + auto forSide = Side::none; + if (logEngineBySides) { + forSide = bySide; + } + auto path = createLogPath(logEnginePath, logEngineAllInOneMode, logEngineGameTitleSurfix, false, game, forSide); + + if (!path.empty()) { + std::lock_guard dolock(logMutex); + append2TextFile(path, str); } - std::lock_guard dolock(logMutex); - append2TextFile(path, str); } void TourMng::append2TextFile(const std::string& path, const std::string& str) diff --git a/src/game/tourmng.h b/src/game/tourmng.h index 4bf8374..9a70031 100755 --- a/src/game/tourmng.h +++ b/src/game/tourmng.h @@ -71,7 +71,7 @@ namespace banksia { std::string startFen; std::vector startMoves; - ResultType resultType = ResultType::noresult; + Result result; int gameIdx = 0, round = 0, pairId; }; @@ -83,7 +83,7 @@ namespace banksia { { public: std::string name; - int gameCnt = 0, winCnt = 0, drawCnt = 0, lossCnt = 0, elo = 0; + int gameCnt = 0, winCnt = 0, drawCnt = 0, lossCnt = 0, abnormalCnt = 0, elo = 0; int whiteCnt = 0; // for knockdown virtual const char* className() const override { return "TourPlayer"; } @@ -159,7 +159,7 @@ namespace banksia { void finishTournament(); - void engineLog(int gameIdx, const std::string& name, const std::string& line, LogType logType); + void engineLog(const Game* game, const std::string& name, const std::string& line, LogType logType, Side bySide = Side::none); bool createNextRoundMatches(); @@ -176,7 +176,7 @@ namespace banksia { virtual void tickWork() override; - void matchLog(const std::string& line); + void matchLog(const std::string& line, bool verbose); int uncompletedMatches(); protected: @@ -207,7 +207,8 @@ namespace banksia { static void showPathInfo(const std::string& name, const std::string& path, bool mode); private: - + static std::string createLogPath(std::string opath, bool onefile, bool usesurfix, bool includeGameResult, const Game* game, Side forSide = Side::none); + int previousElapsed = 0; time_t startTime; @@ -215,15 +216,16 @@ namespace banksia { std::mutex matchMutex, logMutex; std::string pgnPath; - bool pgnPathMode = true; + bool pgnPathMode = true, logPgnAllInOneMode = false; + bool logPgnRichMode = false, logPgnGameTitleSurfix = false; std::string logResultPath; bool logResultMode = false; - std::string logEngineInOutPath; - bool logEngineAllInOneMode = false; - bool logEngineInOutMode = false; - bool logEngineInOutShowTime = false; + std::string logEnginePath; + bool logEngineAllInOneMode = false, logEngineMode = false; + bool logEngineShowTime = false, logEngineGameTitleSurfix = false; + bool logEngineBySides = false; bool logScreenEngineInOutMode = false; }; diff --git a/src/game/uciengine.cpp b/src/game/uciengine.cpp index d772cc5..b162540 100755 --- a/src/game/uciengine.cpp +++ b/src/game/uciengine.cpp @@ -57,7 +57,7 @@ bool UciEngine::sendOptions() if (!isWritable()) { return false; } - + auto o = ConfigMng::instance->checkOverrideOption(option); if (o.isDefaultValue()) { continue; @@ -234,6 +234,12 @@ void UciEngine::parseLine(int cmdInt, const std::string& cmdString, const std::s } break; + case UciEngineCmd::info: + if (computingState == EngineComputingState::thinking) { + parseInfo(line); + } + break; + case UciEngineCmd::bestmove: { auto timeCtrl = timeController; @@ -265,13 +271,12 @@ void UciEngine::parseLine(int cmdInt, const std::string& cmdString, const std::s if (!moveString.empty() && moveReceiver != nullptr) { auto move = board->moveFromCoordiateString(moveString); auto ponderMove = board->moveFromCoordiateString(ponderMoveString); - (moveRecv)(move, moveString, ponderMove, period, oldComputingState); } break; } - + case UciEngineCmd::uciok: { setState(PlayerState::ready); @@ -280,6 +285,7 @@ void UciEngine::parseLine(int cmdInt, const std::string& cmdString, const std::s sendPing(); break; } + case UciEngineCmd::theId: { auto vec = splitString(line, ' '); @@ -417,4 +423,45 @@ bool UciEngine::parseOption(const std::string& s) return false; } +bool UciEngine::parseInfo(const std::string& line) +{ + assert(!line.empty()); + + std::string str; + auto p = line.find(" pv "); + if (p != std::string::npos) { + str = line.substr(5, p); + } else { + str = line.substr(5); + } + + auto vec = splitString(str, ' '); + for(int i = 0; i < vec.size() - 1; i++) { + auto name = vec.at(i); + if (name == "depth") { + ++i; + auto s = vec.at(i); + depth = std::atoi(s.c_str()); + continue; + } + + if (name == "score") { + ++i; + auto s = vec.at(i); + + auto iscpscore = false; + if (s == "cp") { + iscpscore = true; + ++i; + s = vec.at(i); + } + score = std::atoi(s.c_str()); + if (!iscpscore) score *= 100; + continue; + } + + } + + return false; +} diff --git a/src/game/uciengine.h b/src/game/uciengine.h index 20a405e..ac5d632 100755 --- a/src/game/uciengine.h +++ b/src/game/uciengine.h @@ -72,6 +72,7 @@ namespace banksia { private: std::string timeControlString() const; bool parseOption(const std::string& str); + bool parseInfo(const std::string& line); bool expectingBestmove = false; Move ponderingMove; diff --git a/src/game/wbengine.cpp b/src/game/wbengine.cpp index e33fca6..1d77831 100644 --- a/src/game/wbengine.cpp +++ b/src/game/wbengine.cpp @@ -528,10 +528,26 @@ void WbEngine::parseLine(int cmdInt, const std::string& cmdString, const std::st if (state != PlayerState::playing) { return; } + + if (computingState != EngineComputingState::thinking) { + return; + } auto ch = line.front(); if (isdigit(ch)) { // it may be thinking output -> ignore // 9 156 1084 48000 Nf3 Nc6 Nc3 Nf6 - engineSentCorrectCmds(); + // ply score time nodes pv + auto vec = splitString(line, ' '); + if (vec.size() > 2) { + auto scoreStr = vec.at(1); + if (!scoreStr.empty()) { + auto c = scoreStr[0]; + if (isdigit(c) || c == '-' || c == '+') { + engineSentCorrectCmds(); + score = std::atoi(scoreStr.c_str()); + depth = std::atoi(vec[0].c_str()); + } + } + } } return; } diff --git a/src/main.cpp b/src/main.cpp index ff9272e..2f19d11 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,7 +60,7 @@ int main(int argc, const char * argv[]) std::string str = arg; auto ok = true; - if (arg == "-jsonpath" || arg == "-d" || arg == "-c") { + if (arg == "-jsonpath" || arg == "-d" || arg == "-c" || arg == "-v") { if (i + 1 < argc) { i++; str = argv[i]; @@ -81,6 +81,10 @@ int main(int argc, const char * argv[]) mainJsonPath = argmap["-jsonpath"]; } + if (argmap.find("-v") != argmap.end()) { + banksia::banksiaVerbose = argmap["-v"] == "on"; + } + banksia::JsonMaker maker; banksia::TourMng tourMng; @@ -141,9 +145,10 @@ int main(int argc, const char * argv[]) std::cout << tourMng.createTournamentStats() << std::endl; continue; } - if (cmd == "engineverbose" || cmd == "ev") { + if (cmd == "v") { std::string str = vec.size() > 1 ? vec[1] : ""; - tourMng.showEgineInOutToScreen(str == "on"); + //tourMng.showEgineInOutToScreen(str == "on"); + banksia::banksiaVerbose = str == "on"; continue; } @@ -173,6 +178,7 @@ void show_usage(std::string name) << " -u update\n" << " -c concurrency (for updating only)\n" << " -d PATH main engines' folder, may have subfolder (for updating only)\n" + << " -v on|off turn on/off verbose (default on)\n" << "\n" << "Examples:\n" << " " << name << " -jsonpath c:\\tour.json\n" @@ -189,7 +195,7 @@ void show_help() << "Usage:\n" << " help show this help message\n" << " status current result\n" - << " ev [on|off] Show/not to screen engine's input / output (engineverbose)\n" + << " v [on|off] verbose on/off. Show/Don't show individual match (default on)\n" << " quit quit\n" << std::endl; }