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