Subversion Repositories Games.Chess Giants

Rev

Rev 154 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
  3.   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
  4.   Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
  5.   Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
  6.  
  7.   Stockfish is free software: you can redistribute it and/or modify
  8.   it under the terms of the GNU General Public License as published by
  9.   the Free Software Foundation, either version 3 of the License, or
  10.   (at your option) any later version.
  11.  
  12.   Stockfish is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License
  18.   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. */
  20.  
  21. #include <cassert>
  22. #include <iostream>
  23. #include <sstream>
  24. #include <string>
  25.  
  26. #include "evaluate.h"
  27. #include "movegen.h"
  28. #include "position.h"
  29. #include "search.h"
  30. #include "thread.h"
  31. #include "tt.h"
  32. #include "timeman.h"
  33. #include "uci.h"
  34. #include "syzygy/tbprobe.h"
  35.  
  36. using namespace std;
  37.  
  38. extern vector<string> setup_bench(const Position&, istream&);
  39.  
  40. namespace {
  41.  
  42.   // FEN string of the initial position, normal chess
  43.   const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
  44.  
  45.  
  46.   // position() is called when engine receives the "position" UCI command.
  47.   // The function sets up the position described in the given FEN string ("fen")
  48.   // or the starting position ("startpos") and then makes the moves given in the
  49.   // following move list ("moves").
  50.  
  51.   void position(Position& pos, istringstream& is, StateListPtr& states) {
  52.  
  53.     Move m;
  54.     string token, fen;
  55.  
  56.     is >> token;
  57.  
  58.     if (token == "startpos")
  59.     {
  60.         fen = StartFEN;
  61.         is >> token; // Consume "moves" token if any
  62.     }
  63.     else if (token == "fen")
  64.         while (is >> token && token != "moves")
  65.             fen += token + " ";
  66.     else
  67.         return;
  68.  
  69.     states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one
  70.     pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
  71.  
  72.     // Parse move list (if any)
  73.     while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
  74.     {
  75.         states->emplace_back();
  76.         pos.do_move(m, states->back());
  77.     }
  78.   }
  79.  
  80.  
  81.   // setoption() is called when engine receives the "setoption" UCI command. The
  82.   // function updates the UCI option ("name") to the given value ("value").
  83.  
  84.   void setoption(istringstream& is) {
  85.  
  86.     string token, name, value;
  87.  
  88.     is >> token; // Consume "name" token
  89.  
  90.     // Read option name (can contain spaces)
  91.     while (is >> token && token != "value")
  92.         name += string(" ", name.empty() ? 0 : 1) + token;
  93.  
  94.     // Read option value (can contain spaces)
  95.     while (is >> token)
  96.         value += string(" ", value.empty() ? 0 : 1) + token;
  97.  
  98.     if (Options.count(name))
  99.         Options[name] = value;
  100.     else
  101.         sync_cout << "No such option: " << name << sync_endl;
  102.   }
  103.  
  104.  
  105.   // go() is called when engine receives the "go" UCI command. The function sets
  106.   // the thinking time and other parameters from the input string, then starts
  107.   // the search.
  108.  
  109.   void go(Position& pos, istringstream& is, StateListPtr& states) {
  110.  
  111.     Search::LimitsType limits;
  112.     string token;
  113.     bool ponderMode = false;
  114.  
  115.     limits.startTime = now(); // As early as possible!
  116.  
  117.     while (is >> token)
  118.         if (token == "searchmoves")
  119.             while (is >> token)
  120.                 limits.searchmoves.push_back(UCI::to_move(pos, token));
  121.  
  122.         else if (token == "wtime")     is >> limits.time[WHITE];
  123.         else if (token == "btime")     is >> limits.time[BLACK];
  124.         else if (token == "winc")      is >> limits.inc[WHITE];
  125.         else if (token == "binc")      is >> limits.inc[BLACK];
  126.         else if (token == "movestogo") is >> limits.movestogo;
  127.         else if (token == "depth")     is >> limits.depth;
  128.         else if (token == "nodes")     is >> limits.nodes;
  129.         else if (token == "movetime")  is >> limits.movetime;
  130.         else if (token == "mate")      is >> limits.mate;
  131.         else if (token == "perft")     is >> limits.perft;
  132.         else if (token == "infinite")  limits.infinite = 1;
  133.         else if (token == "ponder")    ponderMode = true;
  134.  
  135.     Threads.start_thinking(pos, states, limits, ponderMode);
  136.   }
  137.  
  138.  
  139.   // bench() is called when engine receives the "bench" command. Firstly
  140.   // a list of UCI commands is setup according to bench parameters, then
  141.   // it is run one by one printing a summary at the end.
  142.  
  143.   void bench(Position& pos, istream& args, StateListPtr& states) {
  144.  
  145.     string token;
  146.     uint64_t num, nodes = 0, cnt = 1;
  147.  
  148.     vector<string> list = setup_bench(pos, args);
  149.     num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0; });
  150.  
  151.     TimePoint elapsed = now();
  152.  
  153.     for (const auto& cmd : list)
  154.     {
  155.         istringstream is(cmd);
  156.         is >> skipws >> token;
  157.  
  158.         if (token == "go")
  159.         {
  160.             cerr << "\nPosition: " << cnt++ << '/' << num << endl;
  161.             go(pos, is, states);
  162.             Threads.main()->wait_for_search_finished();
  163.             nodes += Threads.nodes_searched();
  164.         }
  165.         else if (token == "setoption")  setoption(is);
  166.         else if (token == "position")   position(pos, is, states);
  167.         else if (token == "ucinewgame") Search::clear();
  168.     }
  169.  
  170.     elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
  171.  
  172.     dbg_print(); // Just before exiting
  173.  
  174.     cerr << "\n==========================="
  175.          << "\nTotal time (ms) : " << elapsed
  176.          << "\nNodes searched  : " << nodes
  177.          << "\nNodes/second    : " << 1000 * nodes / elapsed << endl;
  178.   }
  179.  
  180. } // namespace
  181.  
  182.  
  183. /// UCI::loop() waits for a command from stdin, parses it and calls the appropriate
  184. /// function. Also intercepts EOF from stdin to ensure gracefully exiting if the
  185. /// GUI dies unexpectedly. When called with some command line arguments, e.g. to
  186. /// run 'bench', once the command is executed the function returns immediately.
  187. /// In addition to the UCI ones, also some additional debug commands are supported.
  188.  
  189. void UCI::loop(int argc, char* argv[]) {
  190.  
  191.   Position pos;
  192.   string token, cmd;
  193.   StateListPtr states(new std::deque<StateInfo>(1));
  194.   auto uiThread = std::make_shared<Thread>(0);
  195.  
  196.   pos.set(StartFEN, false, &states->back(), uiThread.get());
  197.  
  198.   for (int i = 1; i < argc; ++i)
  199.       cmd += std::string(argv[i]) + " ";
  200.  
  201.   do {
  202.       if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF
  203.           cmd = "quit";
  204.  
  205.       istringstream is(cmd);
  206.  
  207.       token.clear(); // Avoid a stale if getline() returns empty or blank line
  208.       is >> skipws >> token;
  209.  
  210.       // The GUI sends 'ponderhit' to tell us the user has played the expected move.
  211.       // So 'ponderhit' will be sent if we were told to ponder on the same move the
  212.       // user has played. We should continue searching but switch from pondering to
  213.       // normal search. In case Threads.stopOnPonderhit is set we are waiting for
  214.       // 'ponderhit' to stop the search, for instance if max search depth is reached.
  215.       if (    token == "quit"
  216.           ||  token == "stop"
  217.           || (token == "ponderhit" && Threads.stopOnPonderhit))
  218.           Threads.stop = true;
  219.  
  220.       else if (token == "ponderhit")
  221.           Threads.ponder = false; // Switch to normal search
  222.  
  223.       else if (token == "uci")
  224.           sync_cout << "id name " << engine_info(true)
  225.                     << "\n"       << Options
  226.                     << "\nuciok"  << sync_endl;
  227.  
  228.       else if (token == "setoption")  setoption(is);
  229.       else if (token == "go")         go(pos, is, states);
  230.       else if (token == "position")   position(pos, is, states);
  231.       else if (token == "ucinewgame") Search::clear();
  232.       else if (token == "isready")    sync_cout << "readyok" << sync_endl;
  233.  
  234.       // Additional custom non-UCI commands, mainly for debugging
  235.       else if (token == "flip")  pos.flip();
  236.       else if (token == "bench") bench(pos, is, states);
  237.       else if (token == "d")     sync_cout << pos << sync_endl;
  238.       else if (token == "eval")  sync_cout << Eval::trace(pos) << sync_endl;
  239.       else
  240.           sync_cout << "Unknown command: " << cmd << sync_endl;
  241.  
  242.   } while (token != "quit" && argc == 1); // Command line args are one-shot
  243. }
  244.  
  245.  
  246. /// UCI::value() converts a Value to a string suitable for use with the UCI
  247. /// protocol specification:
  248. ///
  249. /// cp <x>    The score from the engine's point of view in centipawns.
  250. /// mate <y>  Mate in y moves, not plies. If the engine is getting mated
  251. ///           use negative values for y.
  252.  
  253. string UCI::value(Value v) {
  254.  
  255.   assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
  256.  
  257.   stringstream ss;
  258.  
  259.   if (abs(v) < VALUE_MATE - MAX_PLY)
  260.       ss << "cp " << v * 100 / PawnValueEg;
  261.   else
  262.       ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
  263.  
  264.   return ss.str();
  265. }
  266.  
  267.  
  268. /// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.)
  269.  
  270. std::string UCI::square(Square s) {
  271.   return std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) };
  272. }
  273.  
  274.  
  275. /// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
  276. /// The only special case is castling, where we print in the e1g1 notation in
  277. /// normal chess mode, and in e1h1 notation in chess960 mode. Internally all
  278. /// castling moves are always encoded as 'king captures rook'.
  279.  
  280. string UCI::move(Move m, bool chess960) {
  281.  
  282.   Square from = from_sq(m);
  283.   Square to = to_sq(m);
  284.  
  285.   if (m == MOVE_NONE)
  286.       return "(none)";
  287.  
  288.   if (m == MOVE_NULL)
  289.       return "0000";
  290.  
  291.   if (type_of(m) == CASTLING && !chess960)
  292.       to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
  293.  
  294.   string move = UCI::square(from) + UCI::square(to);
  295.  
  296.   if (type_of(m) == PROMOTION)
  297.       move += " pnbrqk"[promotion_type(m)];
  298.  
  299.   return move;
  300. }
  301.  
  302.  
  303. /// UCI::to_move() converts a string representing a move in coordinate notation
  304. /// (g1f3, a7a8q) to the corresponding legal Move, if any.
  305.  
  306. Move UCI::to_move(const Position& pos, string& str) {
  307.  
  308.   if (str.length() == 5) // Junior could send promotion piece in uppercase
  309.       str[4] = char(tolower(str[4]));
  310.  
  311.   for (const auto& m : MoveList<LEGAL>(pos))
  312.       if (str == UCI::move(m, pos.is_chess960()))
  313.           return m;
  314.  
  315.   return MOVE_NONE;
  316. }
  317.