stellar

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

match.cpp (4748B)


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