File indexing completed on 2024-05-12 04:04:16
0001 /* 0002 This file is part of Knights, a chess board for KDE SC 4. 0003 SPDX-FileCopyrightText: 2011 Miha Čančula <miha@noughmad.eu> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "uciprotocol.h" 0009 #include "gamemanager.h" 0010 #include "knightsdebug.h" 0011 0012 #include <KProcess> 0013 using namespace Knights; 0014 0015 UciProtocol::UciProtocol(QObject* parent): ComputerProtocol(parent), 0016 mWhiteTime(0), 0017 mBlackTime(0), 0018 mDifficulty(0) { 0019 0020 } 0021 0022 UciProtocol::~UciProtocol() { 0023 if ( mProcess && mProcess->isOpen() ) { 0024 write("quit"); 0025 if ( !mProcess->waitForFinished ( 500 ) ) 0026 mProcess->kill(); 0027 } 0028 } 0029 0030 Protocol::Features UciProtocol::supportedFeatures() { 0031 //TODO: UCI is stateless. Undo needs to be implemented completely in the client. 0032 return GameOver | Pause | Resign | SetDifficulty | AdjustDifficulty; 0033 } 0034 0035 bool UciProtocol::parseStub(const QString& line) { 0036 Q_UNUSED(line); 0037 return false; 0038 } 0039 0040 bool UciProtocol::parseLine(const QString& line) { 0041 if ( line.isEmpty() ) 0042 return true; 0043 ChatWidget::MessageType type = ChatWidget::GreetMessage; 0044 qCDebug(LOG_KNIGHTS) << line; 0045 if ( line.startsWith ( QLatin1String("uciok") ) ) { 0046 type = ChatWidget::AccountMessage; 0047 write ( "isready" ); 0048 } else if ( line.startsWith ( QLatin1String("readyok") ) ) { 0049 type = ChatWidget::AccountMessage; 0050 initComplete(); 0051 } else if ( line.startsWith ( QLatin1String("id name ") ) ) { 0052 type = ChatWidget::AccountMessage; 0053 // Chop off the "id name " port, the remainder if the engine's name 0054 setPlayerName ( line.mid ( 8 ) ); 0055 } else if ( line.startsWith ( QLatin1String("bestmove") ) ) { 0056 type = ChatWidget::MoveMessage; 0057 QStringList lst = line.split(QLatin1Char(' ')); 0058 if ( lst.size() > 1 ) { 0059 Move m = Move ( lst[1] ); 0060 mMoveHistory << m; 0061 Q_EMIT pieceMoved ( m ); 0062 } else 0063 return false; 0064 if ( lst.size() > 3 && lst[2] == QLatin1String("ponder") ) 0065 mPonderMove.setString ( lst[3] ); 0066 } 0067 writeToConsole ( line, type ); 0068 return true; 0069 } 0070 0071 void UciProtocol::declineOffer(const Knights::Offer& offer) { 0072 Q_UNUSED(offer); 0073 } 0074 0075 void UciProtocol::acceptOffer(const Knights::Offer& offer) { 0076 Q_UNUSED(offer); 0077 } 0078 0079 void UciProtocol::makeOffer(const Knights::Offer& offer) { 0080 Q_UNUSED(offer); 0081 } 0082 0083 void UciProtocol::startGame() { 0084 write ( "ucinewgame" ); 0085 if ( color() == White ) 0086 requestNextMove(); 0087 } 0088 0089 void UciProtocol::init() { 0090 startProgram(); 0091 write("uci"); 0092 } 0093 0094 void UciProtocol::move(const Knights::Move& m) { 0095 mMoveHistory << m; 0096 requestNextMove(); 0097 } 0098 0099 void UciProtocol::requestNextMove() { 0100 QString str = QStringLiteral("position startpos"); 0101 0102 if ( !mMoveHistory.isEmpty() ) { 0103 str += QLatin1String(" moves"); 0104 for ( const Move& move : std::as_const(mMoveHistory) ) { 0105 QString moveString = QLatin1Char(' ') + move.from().string() + move.to().string(); 0106 if ( move.promotedType() ) 0107 moveString += Piece::charFromType ( move.promotedType() ).toLower(); 0108 str += moveString; 0109 } 0110 } 0111 write ( str ); 0112 0113 QString goString = QStringLiteral("go"); 0114 0115 if ( mDifficulty ) 0116 goString += QLatin1String(" depth ") + QString::number ( mDifficulty ); 0117 0118 if ( Manager::self()->timeControlEnabled(NoColor) ) { 0119 goString += QLatin1String(" wtime ") + QString::number ( mWhiteTime ); 0120 goString += QLatin1String(" btime ") + QString::number ( mBlackTime ); 0121 0122 int winc = Manager::self()->timeControl ( White ).increment; 0123 if ( winc ) 0124 goString += QLatin1String(" winc ") + QString::number ( winc * 1000 ); 0125 int binc = Manager::self()->timeControl ( Black ).increment; 0126 if ( winc ) 0127 goString += QLatin1String(" binc ") + QString::number ( binc * 1000 ); 0128 0129 int moves = Manager::self()->timeControl ( NoColor ).moves; 0130 if (moves > 0) { 0131 int movesToGo = mMoveHistory.size() % moves; 0132 if ( movesToGo > 0 ) 0133 goString += QLatin1String(" movestogo ") + QString::number ( movesToGo ); 0134 } 0135 } 0136 0137 write ( goString ); 0138 } 0139 0140 void UciProtocol::changeCurrentTime(Color color, const QTime& time) { 0141 int msecs = QTime().msecsTo ( time ); 0142 switch ( color ) { 0143 case White: 0144 mWhiteTime = msecs; 0145 break; 0146 0147 case Black: 0148 mBlackTime = msecs; 0149 break; 0150 0151 default: 0152 mBlackTime = msecs; 0153 mWhiteTime = msecs; 0154 break; 0155 } 0156 } 0157 0158 void UciProtocol::setDifficulty(int depth, int memory) { 0159 mDifficulty = depth; 0160 write ( QLatin1String("setoption name Hash value ") + QString::number ( memory ) ); 0161 } 0162