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