/*
Texel - A UCI chess engine.
Copyright (C) 2012 Peter Ă–sterlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* uciprotocol.cpp
*
* Created on: Mar 4, 2012
* Author: petero
*/
#include "uciprotocol.hpp"
#include "searchparams.hpp"
#include "computerPlayer.hpp"
#include "textio.hpp"
#include <iostream>
void
UCIProtocol::main(bool autoStart) {
UCIProtocol uciProt;
uciProt.mainLoop(std::cin, std::cout, autoStart);
}
UCIProtocol::UCIProtocol()
: pos(TextIO::readFEN(TextIO::startPosFEN)),
quit(false)
{
}
void
UCIProtocol::mainLoop(std::istream& is, std::ostream& os, bool autoStart) {
if (autoStart)
handleCommand("uci", os);
std::string line;
while (true) {
getline(is, line);
if (!is.good()) {
if (engine)
engine->stopSearch();
break;
}
handleCommand(line, os);
if (quit)
break;
}
}
void
UCIProtocol::handleCommand(const std::string& cmdLine, std::ostream& os) {
std::vector<std::string> tokens;
tokenize(cmdLine, tokens);
const int nTok = (int)tokens.size();
if (nTok == 0)
return;
try {
std::string cmd = tokens[0];
if (cmd == "uci") {
os << "id name " << ComputerPlayer::engineName << std::endl;
os << "id author Peter Osterlund" << std::endl;
EngineControl::printOptions(os);
os << "uciok" << std::endl;
} else if (cmd == "isready") {
initEngine(os);
os << "readyok" << std::endl;
} else if (cmd == "setoption") {
initEngine(os);
std::string optionName;
std::string optionValue;
if (nTok < 2)
return;
if (tokens[1] == "name") {
int idx = 2;
while ((idx < nTok) && (tokens[idx] != "value")) {
optionName += toLowerCase(tokens[idx++]);
optionName += ' ';
}
if ((idx < nTok) && (tokens[idx++] == "value")) {
while ((idx < nTok)) {
optionValue += toLowerCase(tokens[idx++]);
optionValue += ' ';
}
}
engine->setOption(trim(optionName), trim(optionValue), true);
}
} else if (cmd == "ucinewgame") {
if (engine)
engine->newGame();
} else if (cmd == "position") {
std::string fen;
int idx = 1;
if (nTok < 2)
return;
if (tokens[idx] == "startpos") {
idx++;
fen = TextIO::startPosFEN;
} else if (tokens[idx] == "fen") {
idx++;
std::string sb;
while ((idx < nTok) && (tokens[idx] != "moves")) {
sb += tokens[idx++];
sb += ' ';
}
fen = trim(sb);
}
if (fen.length() > 0) {
pos = TextIO::readFEN(fen);
moves.clear();
if ((idx < nTok) && (tokens[idx++] == "moves")) {
for (int i = idx; i < nTok; i++) {
Move m = TextIO::uciStringToMove(tokens[i]);
if (m.isEmpty())
break;
moves.push_back(m);
}
}
}
} else if (cmd == "go") {
initEngine(os);
int idx = 1;
SearchParams sPar;
bool ponder = false;
while (idx < nTok) {
std::string subCmd = tokens[idx++];
if (subCmd == "searchmoves") {
while (idx < nTok) {
Move m = TextIO::uciStringToMove(tokens[idx]);
if (m.isEmpty())
break;
sPar.searchMoves.push_back(m);
idx++;
}
} else if (subCmd == "ponder") {
ponder = true;
} else if (subCmd == "wtime") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.wTime);
} else if (subCmd == "btime") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.bTime);
} else if (subCmd == "winc") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.wInc);
} else if (subCmd == "binc") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.bInc);
} else if (subCmd == "movestogo") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.movesToGo);
} else if (subCmd == "depth") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.depth);
} else if (subCmd == "nodes") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.nodes);
} else if (subCmd == "mate") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.mate);
} else if (subCmd == "movetime") {
if (idx < nTok)
str2Num(tokens[idx++], sPar.moveTime);
} else if (subCmd == "infinite") {
sPar.infinite = true;
}
}
if (ponder) {
engine->startPonder(pos, moves, sPar);
} else {
engine->startSearch(pos, moves, sPar);
}
} else if (cmd == "stop") {
if (engine)
engine->stopSearch();
} else if (cmd == "ponderhit") {
engine->ponderHit();
} else if (cmd == "quit") {
if (engine)
engine->stopSearch();
quit = true;
}
} catch (const ChessParseError&) {
}
}
void
UCIProtocol::initEngine(std::ostream& os) {
if (!engine)
engine = std::make_shared<EngineControl>(os);
}
/** Convert a string to tokens by splitting at whitespace characters. */
void
UCIProtocol::tokenize(const std::string& cmdLine, std::vector<std::string>& tokens) {
tokens.clear();
std::string tmp = trim(cmdLine);
int start = 0;
bool inWord = true;
for (int i = 0; i < (int)tmp.size(); i++) {
if (inWord) {
if (isspace(tmp[i])) {
tokens.push_back(tmp.substr(start, i - start));
inWord = false;
}
} else {
if (!isspace(tmp[i])) {
start = i;
inWord = true;
}
}
}
if (inWord)
tokens.push_back(tmp.substr(start, tmp.size() - start));
}