Serenity Operating System
1/*
2 * Copyright (c) 2020, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "ChessEngine.h"
8#include "MCTSTree.h"
9#include <AK/Random.h>
10#include <LibCore/DeprecatedFile.h>
11#include <LibCore/ElapsedTimer.h>
12
13using namespace Chess::UCI;
14
15void ChessEngine::handle_uci()
16{
17 send_command(IdCommand(IdCommand::Type::Name, "ChessEngine"sv));
18 send_command(IdCommand(IdCommand::Type::Author, "the SerenityOS developers"sv));
19 send_command(UCIOkCommand());
20}
21
22void ChessEngine::handle_position(PositionCommand const& command)
23{
24 // FIXME: Implement fen board position.
25 VERIFY(!command.fen().has_value());
26 m_board = Chess::Board();
27 for (auto& move : command.moves()) {
28 VERIFY(m_board.apply_move(move));
29 }
30}
31
32void ChessEngine::handle_go(GoCommand const& command)
33{
34 // FIXME: A better algorithm than naive mcts.
35 // FIXME: Add different ways to terminate search.
36 VERIFY(command.movetime.has_value());
37
38 srand(get_random<u32>());
39
40 auto elapsed_time = Core::ElapsedTimer::start_new();
41
42 auto mcts = [this]() -> MCTSTree {
43 if (!m_last_tree.has_value())
44 return { m_board };
45 auto x = m_last_tree.value().child_with_move(m_board.last_move().value());
46 if (x.has_value())
47 return move(x.value());
48 return { m_board };
49 }();
50
51 int rounds = 0;
52 while (elapsed_time.elapsed() <= command.movetime.value()) {
53 mcts.do_round();
54 ++rounds;
55 }
56 dbgln("MCTS finished {} rounds.", rounds);
57 dbgln("MCTS evaluation {}", mcts.expected_value());
58 auto& best_node = mcts.best_node();
59 auto const& best_move = best_node.last_move();
60 dbgln("MCTS best move {}", best_move.to_long_algebraic());
61 send_command(BestMoveCommand(best_move));
62
63 m_last_tree = move(best_node);
64}