/* * Copyright (c) 2020, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #include "ChessEngine.h" #include "MCTSTree.h" #include #include using namespace Chess::UCI; void ChessEngine::handle_uci() { send_command(IdCommand(IdCommand::Type::Name, "ChessEngine"sv)); send_command(IdCommand(IdCommand::Type::Author, "the SerenityOS developers"sv)); send_command(UCIOkCommand()); } void ChessEngine::handle_position(PositionCommand const& command) { // FIXME: Implement fen board position. VERIFY(!command.fen().has_value()); m_board = Chess::Board(); for (auto& move : command.moves()) { VERIFY(m_board.apply_move(move)); } } void ChessEngine::handle_go(GoCommand const& command) { // FIXME: A better algorithm than naive mcts. // FIXME: Add different ways to terminate search. VERIFY(command.movetime.has_value()); srand(get_random()); auto elapsed_time = Core::ElapsedTimer::start_new(); auto mcts = [this]() -> MCTSTree { if (!m_last_tree.has_value()) return { m_board }; auto x = m_last_tree.value().child_with_move(m_board.last_move().value()); if (x.has_value()) return move(x.value()); return { m_board }; }(); int rounds = 0; while (elapsed_time.elapsed() <= command.movetime.value()) { mcts.do_round(); ++rounds; } dbgln("MCTS finished {} rounds.", rounds); dbgln("MCTS evaluation {}", mcts.expected_value()); auto& best_node = mcts.best_node(); auto const& best_move = best_node.last_move(); dbgln("MCTS best move {}", best_move.to_long_algebraic()); send_command(BestMoveCommand(best_move)); m_last_tree = move(best_node); }