stellar

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

commit 362cc43b8bc8a4e5519238dc587ddd0b8eb30ee2
parent 478983d07da27cc277fef32f73a65f5de5631f1a
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Tue, 29 Aug 2023 00:23:48 +0200

Basic time control

Diffstat:
MCMakeLists.txt | 2+-
Msrc/engine/engine.cpp | 27+++++++++++++++++++++++----
Msrc/engine/uci.cpp | 68+++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/engine/uci.hpp | 16+++++++++-------
4 files changed, 88 insertions(+), 25 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stellar - VERSION 0.0.24 + VERSION 0.0.25 DESCRIPTION "Chess engine written in C" HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git LANGUAGES C CXX diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp @@ -76,6 +76,7 @@ class TTable { std::vector<Hashe> table; }; +const uci::Settings *settings = nullptr; Board board; TTable ttable; Move pv_table[MAX_PLY][MAX_PLY]; @@ -184,6 +185,10 @@ void stats_pv_store(Move move) { } int quiescence(int16_t alpha, int16_t beta) { + if ((nodes & 2047) == 0) { + uci::communicate(settings); + if (settings->stopped) return 0; + } pv_length[ply] = ply; nodes++; @@ -207,6 +212,8 @@ int quiescence(int16_t alpha, int16_t beta) { stats_pv_store(list[idx]); if (score >= beta) return beta; } + + if (settings->stopped) return 0; } return alpha; @@ -219,6 +226,10 @@ int negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { Move bestMove; Board copy; + if ((nodes & 2047) == 0) { + uci::communicate(settings); + if (settings->stopped) return 0; + } pv_length[ply] = ply; int score = ttable.read(board, ply, &bestMove, alpha, beta, depth); @@ -251,6 +262,8 @@ int negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { if (staticEval - marginEval >= beta) return staticEval - marginEval; } + if (settings->stopped) return 0; + if (null) { // null move pruning if (ply && depth > 2 && staticEval >= beta) { @@ -326,6 +339,7 @@ int negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { stats_move_unmake(copy); searched++; + if (settings->stopped) return 0; if (score > alpha) { if (!move.is_capture()) { const piece::Type piece = board.get_square_piece_type(move.source()); @@ -361,22 +375,27 @@ int negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { return alpha; } -void search_position(const uci::Settings &setting) { +void search_position(const uci::Settings &settingsr) { int16_t alpha = -SCORE_INFINITY, beta = SCORE_INFINITY; + settings = &settingsr; - if (setting.newgame) { + if (settings->newgame) { ttable = TTable(C64(0x400000)); } ply = 0; nodes = 0; - board = setting.board; + board = settings->board; + settings->stopped = false; memset(killer, 0x00, sizeof(killer)); memset(history, 0x00, sizeof(history)); memset(pv_table, 0x00, sizeof(pv_table)); memset(pv_length, 0x00, sizeof(pv_length)); - for (uint8_t depth_crnt = 1; depth_crnt <= setting.depth;) { + for (uint8_t depth_crnt = 1; depth_crnt <= settings->depth;) { + uci::communicate(settings); + if (settings->stopped) break; + follow_pv = 1; int score = negamax(alpha, beta, depth_crnt, true); diff --git a/src/engine/uci.cpp b/src/engine/uci.cpp @@ -1,18 +1,39 @@ #include <iostream> +#include <limits> #include <sstream> #include <string> +#include <sys/time.h> #include "engine.hpp" #include "stellar_version.hpp" #include "uci.hpp" namespace uci { +uint32_t get_time_ms(void) { + struct timeval time; + gettimeofday(&time, NULL); + return time.tv_sec * 1000 + time.tv_usec / 1000; +} void move_print(const Board &board, Move move) { std::cout << square_to_coordinates(move.source()) << square_to_coordinates(move.target()); if (move.is_promote()) std::cout << piece::get_code(move.promoted(), board.get_side()); } +void communicate(const uci::Settings *settings) { + if (!settings->infinite && uci::get_time_ms() > settings->stoptime) settings->stopped = true; + + /* + if (std::cin.peek() == EOF || std::cin.peek() == '\n') { + std::cin.clear(); + return; + } + std::string command; + std::cin >> command; + if (command == "stop" || command == "quit") settings->stopped = true; + */ +} + inline bool parse_move(const Board &board, Move &move, const std::string &move_string) { Square source = square_from_coordinates(move_string.substr(0, 2)); Square target = square_from_coordinates(move_string.substr(2, 2)); @@ -64,27 +85,30 @@ void loop(void) { } iss >> command; while (iss >> command) { - if (parse_move(settings.board, move, command)) - move.make(settings.board); - else - break; + if (!parse_move(settings.board, move, command)) break; + move.make(settings.board); } } else if (command == "go") { + uint32_t wtime = 0, btime = 0, movetime = 0; + uint16_t winc = 0, binc = 0, movestogo = 30; + while (iss >> command) { if (command == "wtime") - iss >> settings.wtime; + iss >> wtime; else if (command == "btime") - iss >> settings.btime; + iss >> btime; else if (command == "winc") - iss >> settings.winc; + iss >> winc; else if (command == "binc") - iss >> settings.binc; + iss >> binc; else if (command == "depth") iss >> settings.depth; else if (command == "nodes") iss >> settings.nodes; else if (command == "movetime") - iss >> settings.movetime; + iss >> movetime; + else if (command == "movestogo") + iss >> movestogo; else if (command == "ponder") settings.ponder = true; else if (command == "mate") @@ -93,13 +117,31 @@ void loop(void) { settings.infinite = true; else if (command == "searchmoves") { while (iss >> command) { - if (parse_move(settings.board, move, command)) - settings.searchmoves.push(move); - else - break; + if (!parse_move(settings.board, move, command)) break; + settings.searchmoves.push(move); } } } + + settings.starttime = get_time_ms(); + uint32_t time = (settings.board.get_side() == Color::WHITE) ? wtime : btime; + + if (movetime != 0) { + time = movetime; + movestogo = 1; + } + + if (time != 0) { + uint16_t inc = (settings.board.get_side() == Color::WHITE) ? winc : binc; + time /= movestogo; + time -= 50; + settings.stoptime = settings.starttime += time + inc; + settings.infinite = false; + } + + if (!time) settings.infinite = true; + + // std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); engine::search_position(settings); settings.newgame = false; } diff --git a/src/engine/uci.hpp b/src/engine/uci.hpp @@ -11,22 +11,24 @@ namespace uci { struct Settings { MoveList searchmoves; Board board; - uint32_t wtime = 0; - uint32_t btime = 0; - uint32_t movetime = 0; + uint32_t starttime; + uint32_t stoptime; + uint16_t depth = 64; + uint32_t nodes = 0; - uint16_t depth = 0; - uint16_t winc = 0; - uint16_t binc = 0; bool ponder = false; bool debug = false; bool mate = false; - bool infinite = false; + bool infinite = true; bool newgame = true; + + mutable bool stopped = false; }; void loop(void); void move_print(const Board &board, Move move); +void communicate(const uci::Settings *settings); +uint32_t get_time_ms(void); } // namespace uci