stellar

UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE |

match.cpp (4749B)


1 #include "match.hpp" 2 #include "logger.hpp" 3 #include "repetition.hpp" 4 #include "timer.hpp" 5 6 uint16_t Match::id_t = 0; 7 Match::~Match() { logger::log(std::format("Match {}: destroyed", id), logger::Debug); } 8 Match::Match(Engine &white, Engine &black) : engines({&white, &black}) { 9 logger::log(std::format("Match {}: created", id), logger::Debug); 10 } 11 12 Game Match::play(Settings swhite, Settings sblack, const std::string fen = Game::startPosition) { 13 const std::string position = "position " + (fen == Game::startPosition ? "startpos" : "fen " + fen); 14 15 repetition::Table rtable; 16 Board board(fen); 17 Move move; 18 19 logger::log(std::format("Match {}: Play a game between {}(white) and {}(black)", id, 20 engines[0]->get_name(), engines[1]->get_name())); 21 Game game(id, engines[0]->get_name(), engines[1]->get_name(), fen); 22 23 engines[0]->send("ucinewgame"); 24 engines[1]->send("ucinewgame"); 25 26 color::Color turn = board.get_side(); 27 while (true) { 28 const MoveList list = MoveList(board, false, true); 29 if (!list.size()) { 30 game.set_winner(color::other(turn)); 31 break; 32 } 33 34 Engine *engine = engines[to_underlying(turn)]; 35 engine->send(std::format("{} moves {}", position, game.get_moves())); 36 engine->send(get_go(swhite, sblack, turn)); 37 38 uint64_t time_start = timer::get_ms(); 39 40 std::string response; 41 while (true) { 42 response = engine->receive(); 43 if (response.starts_with("bestmove")) break; 44 } 45 46 std::string move_str = response.substr(9); 47 if ((move = parse_move(list, move_str)) == Move() || !move.make(board)) { 48 logger::log( 49 std::format("Match {}: {} illegal {}", id, color::to_string(turn), (std::string)move)); 50 game.set_terminate(Game::Illegal); 51 game.set_winner(color::other(turn)); 52 break; 53 } 54 55 if (rtable.is_repetition(board.get_hash())) { 56 logger::log(std::format("Match {}: {} repetition", id, color::to_string(turn))); 57 game.set_terminate(Game::Repetition); 58 game.set_draw(true); 59 break; 60 } 61 62 rtable.push_hash(board.get_hash()); 63 if (!move.is_repeatable()) rtable.push_null(); 64 game.play(move); 65 66 uint64_t time_passed = timer::get_ms() - time_start; 67 if (turn == color::WHITE ? swhite.time <= time_passed : sblack.time <= time_passed) { 68 logger::log(std::format("Match {}: {} timeout", id, color::to_string(turn))); 69 game.set_terminate(Game::Timeout); 70 game.set_winner(color::other(turn)); 71 break; 72 } 73 74 if (turn == color::WHITE && !swhite.depth) swhite.time -= time_passed; 75 if (turn == color::BLACK && !sblack.depth) sblack.time -= time_passed; 76 77 turn = color::other(turn); 78 } 79 80 if (!game.is_draw()) { 81 logger::log(std::format("Match {}: winner is {}", id, color::to_string(turn))); 82 } else { 83 logger::log(std::format("Match {}: ended in a draw", id)); 84 } 85 86 std::swap(engines[0], engines[1]); 87 return game; 88 } 89 90 std::string Match::get_go(Settings &swhite, Settings &sblack, color::Color side) { 91 std::string go = "go"; 92 if (side == color::WHITE && swhite.depth) go += " depth " + std::to_string(swhite.depth); 93 else { 94 if (side == color::WHITE && swhite.togo) go += " movestogo " + std::to_string(swhite.togo); 95 if (!sblack.depth && swhite.time) go += " wtime " + std::to_string(swhite.time); 96 if (swhite.inc) go += " winc " + std::to_string(swhite.inc); 97 if (swhite.movetime) go += " movetime " + std::to_string(swhite.movetime); 98 } 99 100 if (side == color::BLACK && sblack.depth) go += " depth " + std::to_string(sblack.depth); 101 else { 102 if (side == color::BLACK && sblack.togo) go += " movestogo " + std::to_string(sblack.togo); 103 if (!swhite.depth && sblack.time) go += " btime " + std::to_string(sblack.time); 104 if (sblack.inc) go += " binc " + std::to_string(sblack.inc); 105 if (swhite.movetime) go += " movetime " + std::to_string(sblack.movetime); 106 } 107 return go; 108 } 109 110 Move Match::parse_move(const MoveList list, const std::string &move_string) { 111 const square::Square source = square::from_coordinates(move_string.substr(0, 2)); 112 const square::Square target = square::from_coordinates(move_string.substr(2, 2)); 113 114 for (int i = 0; i < list.size(); i++) { 115 const Move crnt = list[i]; 116 if (crnt.source() != source || crnt.target() != target) continue; 117 if (move_string[4] && tolower(piece::get_code(crnt.promoted())) != move_string[4]) continue; 118 return crnt; 119 } 120 return {}; 121 }