diff --git a/src/clockwidget.cpp b/src/clockwidget.cpp index 6e98ea9..2538a45 100644 --- a/src/clockwidget.cpp +++ b/src/clockwidget.cpp @@ -1,102 +1,99 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #include "clockwidget.h" #include "knightsdebug.h" #include "ui_clockwidget.h" #include #include using namespace Knights; ClockWidget::ClockWidget ( QWidget* parent, Qt::WindowFlags f ) : QWidget ( parent, f ) { ui = new Ui::ClockWidget; ui->setupUi ( this ); } ClockWidget::~ClockWidget() { delete ui; } void ClockWidget::setDisplayedPlayer ( Color color ) { bool w = ( color == White ); ui->verticalLayout->addWidget ( w ? ui->groupB : ui->groupW ); ui->verticalLayout->addWidget ( w ? ui->groupW : ui->groupB ); } void ClockWidget::setPlayerName ( Color color, const QString& name ) { switch ( color ) { case White: ui->groupW->setTitle ( name ); break; case Black: ui->groupB->setTitle ( name ); break; default: break; } } void ClockWidget::setCurrentTime ( Color color, const QTime& time ) { m_currentTime[color] = time; const int miliSeconds = time.hour() * 3600 * 1000 + time.minute() * 60 * 1000 + time.second() * 1000 + time.msec(); const int units = miliSeconds / 100; QProgressBar* bar = ( color == White ) ? ui->progressW : ui->progressB; if ( units > bar->maximum() ) { bar->setMaximum ( units ); updateTimeFormat(); } bar->setValue ( units ); bar->setFormat ( time.toString( m_timeFormat ) ); Clock* clock = ( color == White ) ? ui->clockW : ui->clockB; clock->setTime ( time ); } void ClockWidget::setTimeLimit ( Color color, const QTime& time ) { qCDebug(LOG_KNIGHTS) << color << time; m_timeLimit[color] = time; int seconds = time.hour() * 3600 + time.minute() * 60 + time.second(); switch ( color ) { case White: ui->progressW->setMaximum ( seconds * 10 ); break; case Black: ui->progressB->setMaximum ( seconds * 10 ); break; default: break; } updateTimeFormat(); setCurrentTime( color, time ); } void ClockWidget::updateTimeFormat() { if ( m_timeLimit[White] > QTime(1,0) || m_timeLimit[Black] > QTime(1,0) ) m_timeFormat = QLatin1String("h:mm:ss"); else m_timeFormat = QLatin1String("mm:ss"); } - - -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/clockwidget.h b/src/clockwidget.h index fd09c5d..f04a0b8 100644 --- a/src/clockwidget.h +++ b/src/clockwidget.h @@ -1,62 +1,61 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #ifndef KNIGHTS_CLOCKWIDGET_H #define KNIGHTS_CLOCKWIDGET_H #include "core/piece.h" #include class QGroupBox; class QTimer; class QTime; namespace Ui { class ClockWidget; } namespace Knights { class ClockWidget : public QWidget { Q_OBJECT public: explicit ClockWidget ( QWidget* parent = nullptr, Qt::WindowFlags f = nullptr ); ~ClockWidget () override; public Q_SLOTS: void setTimeLimit ( Color color, const QTime& time ); void setDisplayedPlayer ( Color color ); void setPlayerName ( Color color, const QString& name ); void setCurrentTime ( Color color, const QTime& time ); private: Ui::ClockWidget* ui; Color m_activePlayer; QMap m_timeLimit; QMap m_currentTime; void updateTimeFormat(); QString m_timeFormat; }; } #endif // KNIGHTS_CLOCKWIDGET_H -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/core/item.cpp b/src/core/item.cpp index 6e2067b..b6267b1 100644 --- a/src/core/item.cpp +++ b/src/core/item.cpp @@ -1,144 +1,142 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #include "item.h" #include "board.h" #include "settings.h" #include #include #include #include using namespace Knights; static const int fastAnimationDuration = 150; static const int normalAnimationDuration = 250; static const int slowAnimationDuration = 400; Item::Item ( KGameRenderer* renderer, const QString &key, QGraphicsScene* scene, Pos boardPos, QGraphicsItem* parentItem ) : KGameRenderedObjectItem ( renderer, key, parentItem ) { setBoardPos ( boardPos ); if ( scene ) scene->addItem ( this ); } Item::~Item() { if ( scene() ) scene()->removeItem ( this ); } Pos Item::boardPos() const { return m_pos; } void Item::setBoardPos ( const Pos& pos ) { m_pos = pos; } void Item::move ( const QPointF& pos, qreal tileSize, bool animated ) { if ( !animated || Settings::animationSpeed() == Settings::EnumAnimationSpeed::Instant ) setPos ( pos ); else { int duration = 0; switch ( Settings::animationSpeed() ) { case Settings::EnumAnimationSpeed::Fast: duration = fastAnimationDuration; break; case Settings::EnumAnimationSpeed::Normal: duration = normalAnimationDuration; break; case Settings::EnumAnimationSpeed::Slow: duration = slowAnimationDuration; break; default: break; } duration *= qSqrt ( QPointF ( this->pos() - pos ).manhattanLength() / tileSize ); QPropertyAnimation* anim = new QPropertyAnimation ( this, "pos" ); anim->setDuration ( duration ); anim->setEasingCurve ( QEasingCurve::InOutCubic ); anim->setEndValue ( pos ); anim->start ( QAbstractAnimation::DeleteWhenStopped ); } } void Item::resize ( const QSize& size, bool animated ) { if ( !animated || Settings::animationSpeed() == Settings::EnumAnimationSpeed::Instant ) setRenderSize ( size ); else { int duration = 0; switch ( Settings::animationSpeed() ) { case Settings::EnumAnimationSpeed::Fast: duration = fastAnimationDuration; break; case Settings::EnumAnimationSpeed::Normal: duration = normalAnimationDuration; break; case Settings::EnumAnimationSpeed::Slow: duration = slowAnimationDuration; break; default: break; } QPropertyAnimation* anim = new QPropertyAnimation ( this, "renderSize" ); anim->setDuration ( duration ); anim->setEasingCurve ( QEasingCurve::InOutCubic ); anim->setEndValue ( size ); anim->start ( QAbstractAnimation::DeleteWhenStopped ); } } void Item::moveAndResize ( const QPointF& pos, qreal tileSize, const QSize& size, bool animated ) { if ( !animated || Settings::animationSpeed() == Settings::EnumAnimationSpeed::Instant ) { setPos ( pos ); setRenderSize ( size ); } else { int duration = 0; switch ( Settings::animationSpeed() ) { case Settings::EnumAnimationSpeed::Fast: duration = fastAnimationDuration; break; case Settings::EnumAnimationSpeed::Normal: duration = normalAnimationDuration; break; case Settings::EnumAnimationSpeed::Slow: duration = slowAnimationDuration; break; default: break; } duration *= qSqrt ( QPointF ( this->pos() - pos ).manhattanLength() / tileSize ); QParallelAnimationGroup* group = new QParallelAnimationGroup; QPropertyAnimation* posAnimation = new QPropertyAnimation ( this, "pos" ); posAnimation->setDuration ( duration ); posAnimation->setEasingCurve ( QEasingCurve::InOutCubic ); posAnimation->setEndValue ( pos ); group->addAnimation ( posAnimation ); QPropertyAnimation* sizeAnimation = new QPropertyAnimation ( this, "renderSize" ); sizeAnimation->setDuration ( duration ); sizeAnimation->setEasingCurve ( QEasingCurve::InOutCubic ); sizeAnimation->setEndValue ( size ); group->addAnimation ( sizeAnimation ); group->start ( QAbstractAnimation::DeleteWhenStopped ); } } - -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/core/piece.cpp b/src/core/piece.cpp index a3299d8..8850ab7 100644 --- a/src/core/piece.cpp +++ b/src/core/piece.cpp @@ -1,175 +1,167 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #include "piece.h" #include namespace Knights { QString Piece::spriteKey ( PieceType type, Color color ) { QString id; switch ( color ) { case White: id.append ( QLatin1String ( "White" ) ); break; case Black: id.append ( QLatin1String ( "Black" ) ); break; default: break; } switch ( type ) { case Pawn: id.append ( QLatin1String ( "Pawn" ) ); break; case Rook: id.append ( QLatin1String ( "Rook" ) ); break; case Knight: id.append ( QLatin1String ( "Knight" ) ); break; case Bishop: id.append ( QLatin1String ( "Bishop" ) ); break; case Queen: id.append ( QLatin1String ( "Queen" ) ); break; case King: id.append ( QLatin1String ( "King" ) ); break; default: break; } return id; } QChar Piece::charFromType ( PieceType t ) { switch ( t ) { case Pawn: return QLatin1Char ( 'P' ); case Queen: return QLatin1Char ( 'Q' ); case King: return QLatin1Char ( 'K' ); case Bishop: return QLatin1Char ( 'B' ); case Knight: return QLatin1Char ( 'N' ); case Rook: return QLatin1Char ( 'R' ); default: break; } return QLatin1Char ( 'E' ); } PieceType Piece::typeFromChar ( QChar typeChar ) { PieceType pType = Queen; if ( typeChar == QLatin1Char ( 'N' ) || typeChar == QLatin1Char ( 'n' ) ) pType = Knight; else if ( typeChar == QLatin1Char ( 'R' ) || typeChar == QLatin1Char ( 'r' ) ) pType = Rook; else if ( typeChar == QLatin1Char ( 'B' ) || typeChar == QLatin1Char ( 'b' ) ) pType = Bishop; else if ( typeChar == QLatin1Char ( 'P' ) || typeChar == QLatin1Char ( 'p' ) ) pType = Pawn; else if ( typeChar == QLatin1Char ( 'K' ) || typeChar == QLatin1Char ( 'k' ) ) pType = King; return pType; } - Piece::Piece ( KGameRenderer* renderer, PieceType type, Color color, QGraphicsScene* scene, Pos boardPos, QGraphicsItem* parent ) : Item ( renderer, spriteKey ( type, color ), scene, boardPos, parent ) { m_color = color; m_type = type; } - Piece::~Piece() = default; Color oppositeColor ( Color color ) { switch ( color ) { case Black: return White; case White: return Black; default: return color; } } - QString colorName ( Color color ) { switch ( color ) { case White: return i18n ( "White" ); case Black: return i18n ( "Black" ); default: return QString(); } } QString pieceTypeName ( PieceType type ) { switch ( type ) { case Pawn: return i18n ( "Pawn" ); case Rook: return i18n ( "Rook" ); case Knight: return i18n ( "Knight" ); case Bishop: return i18n ( "Bishop" ); case Queen: return i18n ( "Queen" ); case King: return i18n ( "King" ); default: return QString(); } } - Color Piece::color() { return m_color; } PieceType Piece::pieceType() { return m_type; } void Piece::setPieceType ( PieceType type ) { m_type = type; updateSpriteKey(); } void Piece::updateSpriteKey() { setSpriteKey ( spriteKey ( m_type, m_color ) ); update(); } - - } - -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/core/piece.h b/src/core/piece.h index 9eea0be..3f295c5 100644 --- a/src/core/piece.h +++ b/src/core/piece.h @@ -1,83 +1,82 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009-2010 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #ifndef KNIGHTS_PIECE_H #define KNIGHTS_PIECE_H #include "pos.h" #include "item.h" namespace Knights { enum PieceType { NoType = 0, King, Queen, Bishop, Knight, Rook, Pawn, PieceTypeCount }; enum Color { NoColor = 0x00, White = 0x01, Black = 0x02 }; Q_DECLARE_FLAGS(Colors, Color) Q_DECLARE_OPERATORS_FOR_FLAGS(Colors) Color oppositeColor ( Color color ); QString colorName ( Color color ); QString pieceTypeName ( PieceType type ); class Piece : public Item { Q_OBJECT public: Piece ( KGameRenderer* renderer, PieceType type, Color color, QGraphicsScene* scene, Pos boardPos, QGraphicsItem* parent = nullptr ); ~Piece() override; PieceType pieceType(); void setPieceType ( PieceType type ); Color color(); static QString spriteKey ( PieceType type, Color color ); static PieceType typeFromChar ( QChar typeChar ); static QChar charFromType ( PieceType t ); private: Color m_color; PieceType m_type; void updateSpriteKey(); }; typedef QMap Grid; typedef QPair PieceData; typedef QMap PieceDataMap; } Q_DECLARE_METATYPE ( Knights::Color ) Q_DECLARE_METATYPE ( Knights::Colors ) Q_DECLARE_METATYPE ( Knights::PieceType ) Q_DECLARE_METATYPE ( Knights::PieceData ) Q_DECLARE_METATYPE ( Knights::PieceDataMap ) #endif // KNIGHTS_PIECE_H -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/proto/ficsprotocol.cpp b/src/proto/ficsprotocol.cpp index 3de229c..a27ac32 100644 --- a/src/proto/ficsprotocol.cpp +++ b/src/proto/ficsprotocol.cpp @@ -1,559 +1,557 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #include "proto/ficsprotocol.h" #include #include "proto/ficsdialog.h" #include "proto/chatwidget.h" #include "settings.h" #include "knightsdebug.h" #include #include #include #include #include #include #include #include using namespace Knights; // TODO: Include optional [white]/[black], m, f in RegEx check const char* boolPattern = "([tf])"; const char* ratedPattern = "([ru])"; const char* namePattern = "([a-zA-Z\\(\\)]+)"; const char* ratingPattern = "([0-9\\+\\-\\s]+)"; const char* timePattern = "(\\d+)\\s+(\\d+)"; const char* variantPattern = "([a-z]+)\\s+([a-z]+)"; const char* argsPattern = "(.*)"; //TODO better const char* idPattern = "(\\d+)"; const char* pieces = "PRNBQKprnbqk"; const char* coordinate = "[abdcdefgh][12345678]"; const char* remainingTime = "\\d+ \\d+ (\\d+) \\d+ \\d+ (\\d+) (\\d+) (\\d+)"; const char* currentPlayerPattern = "([WB]) \\-?\\d+ \\d+ \\d+ \\d+ \\d+ \\d+ \\d+"; const char* offerPattern = " (\\d+) w=([a-zA-Z\\(\\)]+) t=([a-z]+) p=(.+)"; FicsProtocol::FicsProtocol ( QObject* parent ) : TextProtocol ( parent ), movePattern(QString(QLatin1String("[%1]\\/(%2)\\-(%3)(=[%4])?")) .arg ( QLatin1String(pieces) ) .arg ( QLatin1String(coordinate) ) .arg ( QLatin1String(coordinate) ) .arg ( QLatin1String(pieces) ) ), seekExp ( QString ( QLatin1String("%1 w=%2 ti=%3 rt=%4[PE\\s] t=%5 i=%6 r=%7 tp=%8 c=%9 rr=%10 a=%11 f=%12") ) .arg ( QLatin1String(idPattern) ) // %1 = index .arg ( QLatin1String(namePattern) ) // %2 = name .arg ( QLatin1String("([0-9a-f]{2,2})") ) // %3 = titles .arg ( QLatin1String("(\\d+)") ) // %4 = rating .arg ( QLatin1String("(\\d+)") ) // %5 = time .arg ( QLatin1String("(\\d+)") ) // %6 = increment .arg ( QLatin1String(ratedPattern) ) // %7 = rated ('r' or 'u') .arg ( QLatin1String("([a-z]+)") ) // %8 = type (standard, blitz, lightning, etc.) .arg ( QLatin1String("([?WB])") ) // %9 = color ('?', 'W' or 'B') .arg ( QLatin1String("(\\d+)\\-(\\d+)") ) // %10 = rating range (x-y) .arg ( QLatin1String(boolPattern) ) // %11 = automatic ( 't' or 'f' ) .arg ( QLatin1String(boolPattern) )), // %12 = formula ( 't' or 'f' ) challengeExp(QString ( QLatin1String("%1 w=%2 t=match p=%2 \\(%3\\) %2 \\(%3\\)")) .arg ( QLatin1String( idPattern ) ) // %1 = index .arg ( QLatin1String( namePattern ) ) // %2 = name .arg ( QLatin1String( ratingPattern ) ) ), // %3 = rating moveStringExp ( movePattern ), moveRegExp ( QString ( QLatin1String("<12>.*%1.*%2 (none|o-o|o-o-o|%3)") ) .arg ( QLatin1String( currentPlayerPattern ) ) .arg ( QLatin1String( remainingTime ) ) .arg ( movePattern ) ), gameStartedExp ( QString ( QLatin1String("Creating: %1 \\(%2\\) %3 \\(%4\\) %5 %6") ) .arg ( QLatin1String( namePattern ) ) .arg ( QLatin1String( ratingPattern ) ) .arg ( QLatin1String( namePattern ) ) .arg ( QLatin1String( ratingPattern ) ) .arg ( QLatin1String( variantPattern ) ) .arg ( QLatin1String( timePattern ) ) ), offerExp ( QLatin1String( offerPattern ) ), sendPassword(false), m_widget(nullptr), m_chat(nullptr) { // FICS games are always time-limited setAttribute ( QLatin1String("TimeLimitEnabled"), true ); if ( !Manager::self()->timeControlEnabled(color()) ) { TimeControl tc; tc.baseTime = QTime().addSecs( 10 * 60 ); // A default time of 10 minutes with no increment tc.increment = 0; Manager::self()->setTimeControl(color(), tc); } } FicsProtocol::~FicsProtocol() = default; Protocol::Features FicsProtocol::supportedFeatures() { return TimeLimit | SetTimeLimit | UpdateTime | Pause | Adjourn | Resign | Abort; } void FicsProtocol::startGame() { } void FicsProtocol::move ( const Move& m ) { write(m.string(false)); } void FicsProtocol::init ( ) { m_stage = ConnectStage; ChatWidget* console = createConsoleWidget(); console->addExtraButton ( QLatin1String("seek"), i18nc("Start searching for opponents", "Seek"), QLatin1String("edit-find") ); console->addExtraButton ( QLatin1String("unseek"), i18nc("Stop searching for opponents", "Unseek"), QLatin1String("edit-clear") ); console->addExtraButton ( QLatin1String("accept"), i18n("Accept"), QLatin1String("dialog-ok-accept") ); console->addExtraButton ( QLatin1String("help"), i18n("Help"), QLatin1String("help-contents") ); connect ( console, &ChatWidget::sendText, this, &FicsProtocol::writeCheckMoves ); setConsole ( console ); QTcpSocket* socket = new QTcpSocket ( this ); setDevice ( socket ); QString address = attribute("server").toString(); int port = attribute("port").toInt(); if ( port == 0 ) port = 5000; connect ( socket, static_cast (&QTcpSocket::error), this, &FicsProtocol::socketError ); socket->connectToHost ( address, port ); } QList< Protocol::ToolWidgetData > FicsProtocol::toolWidgets() { ToolWidgetData consoleData; consoleData.widget = console(); consoleData.title = i18n("Server Console"); consoleData.name = QLatin1String("console"); consoleData.type = ConsoleToolWidget; consoleData.owner = color(); if ( !m_chat ) { m_chat = createChatWidget(); connect ( m_chat, &ChatWidget::sendText, this, &FicsProtocol::sendChat ); } ToolWidgetData chatData; chatData.widget = m_chat; chatData.title = i18n("Chat with %1", playerName()); chatData.name = QLatin1String("chat"); chatData.type = ChatToolWidget; return QList() << consoleData << chatData; } void FicsProtocol::socketError() { emit error( NetworkError, device()->errorString() ); } void FicsProtocol::login ( const QString& username, const QString& password ) { otherPlayerName = username; write(username); sendPassword = true; this->password = password; } void FicsProtocol::setupOptions() { write("set style 12"); write("iset seekremove 1"); write("iset seekinfo 1"); write("iset pendinfo 1"); write("set seek 1"); } void FicsProtocol::openGameDialog() { if ( m_widget ) { m_widget->setStatus(i18n("Login failed"), true); Settings::setAutoLogin(false); m_widget->setLoginEnabled(true); return; } QDialog* dialog = new QDialog ( qApp->activeWindow() ); dialog->setWindowTitle(i18n("Chess server")); auto mainLayout = new QVBoxLayout(dialog); dialog->setLayout(mainLayout); auto bBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); bBox->button(QDialogButtonBox::Ok)->setText(i18n("Accept")); bBox->button(QDialogButtonBox::Ok)->setVisible(false); bBox->button(QDialogButtonBox::Ok)->setIcon(QIcon::fromTheme(QLatin1String("dialog-ok-accept"))); bBox->button(QDialogButtonBox::Cancel)->setText(i18n("Decline")); bBox->button(QDialogButtonBox::Cancel)->setVisible(false); bBox->button(QDialogButtonBox::Cancel)->setIcon(QIcon::fromTheme(QLatin1String("dialog-close"))); m_widget = new FicsDialog (); m_widget->setServerName ( attribute( "server" ).toString()); m_widget->setConsoleWidget ( console() ); mainLayout->addWidget(m_widget); mainLayout->addWidget(bBox); connect ( bBox, &QDialogButtonBox::rejected, m_widget, &FicsDialog::decline ); connect ( bBox, &QDialogButtonBox::accepted, m_widget, &FicsDialog::accept ); connect ( m_widget, &FicsDialog::acceptButtonNeeded, bBox->button(QDialogButtonBox::Ok), &QPushButton::setVisible ); connect ( m_widget, &FicsDialog::declineButtonNeeded, bBox->button(QDialogButtonBox::Cancel), &QPushButton::setVisible ); connect ( m_widget, &FicsDialog::login, this, &FicsProtocol::login ); connect ( m_widget, &FicsDialog::acceptSeek, this, &FicsProtocol::acceptSeek ); connect ( m_widget, &FicsDialog::acceptChallenge, this, &FicsProtocol::acceptChallenge ); connect ( m_widget, &FicsDialog::declineChallenge, this, &FicsProtocol::declineChallenge ); connect ( this, &FicsProtocol::sessionStarted, m_widget, &FicsDialog::slotSessionStarted ); connect ( this, &FicsProtocol::gameOfferReceived, m_widget, &FicsDialog::addGameOffer ); connect ( this, &FicsProtocol::gameOfferRemoved, m_widget, &FicsDialog::removeGameOffer ); connect ( this, &FicsProtocol::challengeReceived, m_widget, &FicsDialog::addChallenge ); connect ( this, &FicsProtocol::gameOfferRemoved, m_widget, &FicsDialog::removeChallenge ); connect ( m_widget, &FicsDialog::seekingChanged, this, &FicsProtocol::setSeeking ); // connect ( dialog, &QDialog::accepted, this, &FicsProtocol::dialogAccepted ); connect ( dialog, &QDialog::rejected, this, &FicsProtocol::dialogRejected ); connect ( this, &FicsProtocol::initSuccesful, dialog, &QDialog::accept ); /* TODO: The SLOT slotDialogAccepted() is not implemented. Need to recheck the intention */ //connect ( this, &FicsProtocol::initSuccesful, m_widget, &FicsDialog::slotDialogAccepted ); connect ( this, &FicsProtocol::error, dialog, &QDialog::deleteLater ); if ( Settings::autoLogin() ) m_widget->slotLogin(); dialog->show(); } bool FicsProtocol::parseStub(const QString& line) { Q_UNUSED(line); return false; } bool FicsProtocol::parseLine(const QString& line) { if ( line.isEmpty() || line.startsWith( QLatin1String("fics%") ) ) return true; bool display = true; ChatWidget::MessageType type = ChatWidget::GeneralMessage; switch ( m_stage ) { case ConnectStage: if ( line.contains ( QLatin1String("login:") ) ) { type = ChatWidget::AccountMessage; openGameDialog(); } else if ( line.contains ( QLatin1String("password:") ) ) { type = ChatWidget::AccountMessage; if ( sendPassword ) write(password); else console()->setPasswordMode(true); } else if ( line.contains ( QLatin1String("Press return to enter the server") ) ) { type = ChatWidget::AccountMessage; write(QString()); } // TODO: Check for incorrect logins else if ( line.contains ( QLatin1String("Starting FICS session") ) ) { type = ChatWidget::StatusMessage; m_stage = SeekStage; console()->setPasswordMode(false); setupOptions(); QString name = line; name.remove ( 0, name.indexOf ( QLatin1String("session as ") ) + 11 ); if ( name.contains ( QLatin1String("(U)") ) ) name.truncate ( name.indexOf ( QLatin1String("(U)") ) ); else name.truncate ( name.indexOf ( QLatin1Char ( ' ' ) ) ); qCDebug(LOG_KNIGHTS) << QLatin1String("Your name is") << name; otherPlayerName = name; emit sessionStarted(); } else if ( line.contains ( QLatin1String("Invalid password") ) ) { m_widget->setLoginEnabled ( true ); type = ChatWidget::AccountMessage; m_widget->setStatus(i18n("Invalid Password"), true); } break; case SeekStage: if ( line.startsWith( QLatin1String("") ) ) { display = false; emit clearSeeks(); } else if ( line.startsWith( QLatin1String("") ) ) { display = false; for ( const QString& str : line.split(QLatin1Char(' ') ) ) { bool ok; int id = str.toInt(&ok); if ( ok ) emit gameOfferRemoved(id); } } else if ( line.startsWith( QLatin1String("") ) && seekExp.indexIn(line) > -1 ) { display = false; FicsGameOffer offer; int n = 1; offer.gameId = seekExp.cap(n++).toInt(); offer.player.first = seekExp.cap(n++); n++; // Ignore titles for now, TODO offer.player.second = seekExp.cap(n++).toInt(); offer.baseTime = seekExp.cap(n++).toInt(); offer.timeIncrement = seekExp.cap(n++).toInt(); offer.rated = ( !seekExp.cap(n).isEmpty() && seekExp.cap(n++)[0] == QLatin1Char('r') ); offer.variant = seekExp.cap(n++); offer.color = parseColor(seekExp.cap(n++)); offer.ratingRange.first = seekExp.cap(n++).toInt(); offer.ratingRange.second = seekExp.cap(n++).toInt(); offer.automatic = ( !seekExp.cap(n).isEmpty() && seekExp.cap(n++)[0] == QLatin1Char('t') ); offer.formula = ( !seekExp.cap(n).isEmpty() && seekExp.cap(n++)[0] == QLatin1Char('t') ); emit gameOfferReceived ( offer ); } else if ( line.startsWith( QLatin1String("") ) && challengeExp.indexIn ( line ) > -1 ) { display = false; FicsChallenge challenge; challenge.gameId = challengeExp.cap ( 1 ).toInt(); challenge.player.first = challengeExp.cap ( 2 ); int ratingPos = ( challengeExp.cap(2) == challengeExp.cap(3) ) ? 4 : 6; challenge.player.second = challengeExp.cap ( ratingPos ).toInt(); emit challengeReceived ( challenge ); } else if ( line.startsWith( QLatin1String("") ) ) { display = false; for ( const QString& str : line.split( QLatin1Char(' ') ) ) { bool ok; int id = str.toInt(&ok); if ( ok ) emit challengeRemoved(id); } } else if ( gameStartedExp.indexIn ( line ) > -1 ) { qCDebug(LOG_KNIGHTS) << "Game Started" << line; type = ChatWidget::StatusMessage; QString player1 = gameStartedExp.cap ( 1 ); QString player2 = gameStartedExp.cap ( 3 ); Color color = NoColor; if ( player1 == otherPlayerName ) { color = Black; setPlayerName ( player2 ); } else { color = White; setPlayerName ( player1 ); } if ( byColor(color) != this ) { qCDebug(LOG_KNIGHTS) << "Switching protocols"; // The color is different than was assigned at first // We have to switch the protocols Protocol* t = white(); setWhiteProtocol(black()); setBlackProtocol(t); } Protocol* opp = Protocol::byColor ( oppositeColor ( color ) ); if ( opp->isLocal() ) opp->setPlayerName ( otherPlayerName ); m_stage = PlayStage; initComplete(); } break; case PlayStage: if ( moveRegExp.indexIn ( line ) > -1 ) { display = false; qCDebug(LOG_KNIGHTS) << moveRegExp.cap(1) << colorName(color()); bool validMove = !( moveRegExp.cap ( 1 ) == QLatin1String("W") && color() == White ) && !( moveRegExp.cap ( 1 ) == QLatin1String("B") && color() == Black ); const int whiteTimeLimit = moveRegExp.cap ( 3 ).toInt(); const int blackTimeLimit = moveRegExp.cap ( 4 ).toInt(); const QString moveString = moveRegExp.cap ( 6 ); qCDebug(LOG_KNIGHTS) << "Move:" << moveString; if ( moveString == QLatin1String("none") ) { TimeControl tc; tc.moves = 0; tc.baseTime = QTime().addSecs(whiteTimeLimit); tc.increment = moveRegExp.cap(2).toInt(); Manager::self()->setTimeControl(NoColor, tc); break; } if ( validMove ) { Move m; if ( moveString == QLatin1String("o-o") ) { // Short (king's rook) castling m = Move::castling ( Move::KingSide, color() ); } else if ( moveString == QLatin1String("o-o-o") ) { // Long (Queen's rock) castling m = Move::castling ( Move::QueenSide, color() ); } else if ( moveStringExp.indexIn ( moveString ) > -1 ) { m.setFrom( Pos(moveStringExp.cap(1)) ); m.setTo( Pos(moveStringExp.cap(2)) ); if ( !moveStringExp.cap(3).isEmpty() ) { m.setFlag ( Move::Promote, true ); QChar typeChar = moveRegExp.cap ( 3 ).mid ( 1, 1 ) [0]; m.setPromotedType ( Piece::typeFromChar ( typeChar ) ); } } qCDebug(LOG_KNIGHTS) << "Valid move" << m; emit pieceMoved ( m ); } Manager::self()->setCurrentTime ( White, QTime().addSecs ( whiteTimeLimit ) ); Manager::self()->setCurrentTime ( Black, QTime().addSecs ( blackTimeLimit ) ); if ( moveRegExp.cap(5).toInt() == 2 ) { // TODO: Notify the manager that time is starting now } } else if ( offerExp.indexIn(line) > -1 ) { Offer offer; offer.id = offerExp.cap(1).toInt(); offer.player = color(); QString type = offerExp.cap(3); if ( type == QLatin1String("abort") ) offer.action = ActionAbort; else if ( type == QLatin1String("adjourn") ) offer.action = ActionAdjourn; else if ( type == QLatin1String("draw") ) offer.action = ActionDraw; else if ( type == QLatin1String("takeback") ) { offer.action = ActionUndo; offer.numberOfMoves = offerExp.cap(4).toInt(); } m_offers.insert ( offer.id, offer ); Manager::self()->sendOffer ( offer ); } else if ( line.contains ( QLatin1String(" says:") ) ) { type = ChatWidget::ChatMessage; m_chat->addText ( line, type ); } else if ( line.contains ( QLatin1String("lost contact or quit") ) ) type = ChatWidget::AccountMessage; else if ( line.startsWith(QLatin1Char('{')) && line.contains(QLatin1Char('}'))) { if ( line.endsWith ( QLatin1String("1-0") ) ) { type = ChatWidget::AccountMessage; emit gameOver ( White ); } else if ( line.endsWith ( QLatin1String("1/2-1/2") ) || line.endsWith ( QLatin1Char('*') ) ) { // Knights has no way of reporting aborted or unfinished games // so we report aborted games as draws type = ChatWidget::AccountMessage; emit gameOver ( NoColor ); } else if ( line.endsWith ( QLatin1String("0-1") ) ) { type = ChatWidget::AccountMessage; emit gameOver ( Black ); } } } if ( display ) writeToConsole ( line, type ); return true; } Color FicsProtocol::parseColor ( QString str ) { if ( str.isEmpty() || str[0] == QLatin1Char('?') ) return NoColor; if ( str[0] == QLatin1Char('W') ) return White; if ( str[0] == QLatin1Char('B') ) return Black; return NoColor; } void FicsProtocol::acceptSeek ( int id ) { write ( QLatin1String("play ") + QString::number(id) ); m_seeking = false; } void FicsProtocol::acceptChallenge ( int id ) { write ( QLatin1String("accept ") + QString::number(id) ); m_seeking = true; } void FicsProtocol::declineChallenge ( int id ) { write ( QLatin1String("decline ") + QString::number(id) ); } void FicsProtocol::dialogRejected() { emit error ( UserCancelled ); } void FicsProtocol::setSeeking ( bool seek ) { m_seeking = seek; if ( seek ) { QByteArray seekText = "seek"; TimeControl tc = Manager::self()->timeControl(color()); seekText += ' '; seekText += QString::number ( 60 * tc.baseTime.hour() + tc.baseTime.minute() ).toLatin1(); seekText += ' '; seekText += QString::number ( tc.increment ).toLatin1(); seekText += m_widget->rated() ? " rated" : " unrated"; /* * Commented out until I figure out a simple way to determine if a color should be forced. switch ( color() ) { case White: seekText += " white"; break; case Black: seekText += " black"; break; default: break; } */ seekText += m_widget->autoAcceptChallenge() ? " auto" : " manual"; qCDebug(LOG_KNIGHTS) << seekText; write(QLatin1String(seekText)); } else write("unseek"); } void FicsProtocol::resign() { write("resign"); } void FicsProtocol::sendChat ( QString text ) { write ( QLatin1String("say ") + text ); } void FicsProtocol::acceptOffer(const Offer& offer) { write ( QLatin1String("accept ") + QString::number(offer.id) ); } void FicsProtocol::declineOffer(const Offer& offer) { write ( QLatin1String("decline ") + QString::number(offer.id) ); } void FicsProtocol::makeOffer(const Offer& offer) { switch (offer.action) { case ActionDraw: write ( "draw" ); break; case ActionPause: write ( "pause" ); break; case ActionUndo: write ( QLatin1String("takeback ") + QString::number ( offer.numberOfMoves ) ); break; case ActionResume: write ( "unpause" ); break; case ActionAdjourn: write ( "adjourn" ); break; case ActionAbort: write ( "abort" ); break; default: break; } } - -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/proto/protocol.cpp b/src/proto/protocol.cpp index 280d639..01a488f 100644 --- a/src/proto/protocol.cpp +++ b/src/proto/protocol.cpp @@ -1,224 +1,220 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #include "proto/protocol.h" #include "proto/chatwidget.h" #include "core/move.h" #include #include #include #include namespace Knights { int id = qRegisterMetaType ( "Protocol::ErrorCode" ); QPointer Protocol::m_white = nullptr; QPointer Protocol::m_black = nullptr; class ProtocolPrivate { public: ProtocolPrivate(); QVariantMap attributes; Protocol* white; Protocol* black; Color color; bool ready; int nextId; }; ProtocolPrivate::ProtocolPrivate() : white(nullptr) , black(nullptr) , ready(false) , nextId(0) { } - Protocol::Protocol ( QObject* parent ) : QObject ( parent ), d_ptr ( new ProtocolPrivate ) { } Protocol::~Protocol() { delete d_ptr; } QString Protocol::stringFromErrorCode ( Protocol::ErrorCode code ) { switch ( code ) { case NoError: return i18n ( "No Error" ); case UserCancelled: return i18n ( "User Canceled" ); case NetworkError: return i18n ( "Network Error" ); case UnknownError: return i18n ( "Unknown Error" ); case InstallationError: return i18n ( "Program Error" ); default: return QString(); } } void Protocol::setWhiteProtocol(Protocol* p) { p->setColor(White); m_white = p; } void Protocol::setBlackProtocol(Protocol* p) { p->setColor(Black); m_black = p; } Protocol* Protocol::white() { return m_white; } Protocol* Protocol::black() { return m_black; } Protocol* Protocol::byColor(Color color) { switch ( color ) { case White: return white(); case Black: return black(); case NoColor: return nullptr; } return nullptr; } void Protocol::setColor ( Color color ) { Q_D(Protocol); d->color = color; } Color Protocol::color() const { Q_D(const Protocol); return d->color; } void Protocol::setPlayerName ( const QString& name ) { setAttribute ( QLatin1String ( "PlayerName" ), name ); } QString Protocol::playerName() const { return attribute ( QLatin1String ( "PlayerName" ) ).toString(); } void Protocol::setAttribute ( const QString& attribute, QVariant value ) { Q_D ( Protocol ); d->attributes.insert ( attribute, value ); } void Protocol::setAttribute ( const char* attribute, QVariant value ) { setAttribute( QLatin1String ( attribute ), value ); } void Protocol::setAttributes ( QVariantMap attributes ) { Q_D ( Protocol ); d->attributes.unite ( attributes ); } QVariant Protocol::attribute ( const QString& attribute ) const { Q_D ( const Protocol ); return d->attributes.value ( attribute ); } QVariant Protocol::attribute ( const char* attribute ) const { return this->attribute ( QLatin1String ( attribute ) ); } - Protocol::Features Protocol::supportedFeatures() { return NoFeatures; } int Protocol::timeRemaining() { return -1; } QList< Protocol::ToolWidgetData > Protocol::toolWidgets() { return QList< Protocol::ToolWidgetData >(); } void Protocol::setWinner(Color winner) { Q_UNUSED(winner); } void Protocol::setTimeControl(const TimeControl& c) { Q_UNUSED(c); } void Protocol::acceptOffer(const Offer& offer) { Q_UNUSED(offer); } void Protocol::declineOffer(const Offer& offer) { Q_UNUSED(offer); } ChatWidget* Protocol::createChatWidget() { return new ChatWidget; } ChatWidget* Protocol::createConsoleWidget() { ChatWidget* console = new ChatWidget; console->setConsoleMode(true); return console; } void Protocol::initComplete() { Q_D(Protocol); d->ready = true; emit initSuccesful(); } bool Protocol::isReady() { Q_D(const Protocol); return d->ready; } bool Protocol::isLocal() { return false; } bool Protocol::isComputer() { return false; } void Protocol::setDifficulty(int depth, int memory) { Q_UNUSED(depth); Q_UNUSED(memory); } } - -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/rules/chessrules.h b/src/rules/chessrules.h index 8c13d81..085c29f 100644 --- a/src/rules/chessrules.h +++ b/src/rules/chessrules.h @@ -1,91 +1,88 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #ifndef KCHESS_CHESSRULES_H #define KCHESS_CHESSRULES_H #include #include #include #include namespace Knights { class Move; class Pos; class ChessRules : public Rules { -public: +public: ChessRules(); + ~ChessRules() override; Color winner() override; bool hasLegalMoves ( Color color ) override; PieceDataMap startingPieces () override; QList legalMoves ( const Pos& pos ) override; void moveMade ( const Move& m ) override; Directions legalDirections ( PieceType type ) override; - ~ChessRules() override; bool isAttacked ( const Pos& pos, Color color, Grid * grid = nullptr ); bool isAttacking ( const Pos& attackingPos ) override; void checkSpecialFlags ( Move* move, Color color ) override; virtual void changeNotation ( Knights::Move* move, Move::Notation notation, Color color ); private: - struct MoveData { Move m; PieceType pieceType; Color color; }; QMap directions; QMap lineDirs; QMap diagDirs; QList knightDirs; QStack moveHistory; -private: QList movesInDirection ( const Pos& dir, const Pos& pos, int length = 8, bool attackYours = false, Grid* grid = nullptr ); QList pawnMoves ( const Pos& pos ); QList castlingMoves ( const Pos& pos ); int length ( const Move& move ); bool isPathClearForCastling ( const Pos& kingPos, const Pos& rookPos ); QList legalAttackMoves ( const Pos& pos, Grid* grid = nullptr ); bool isKingAttacked ( Color color, Grid* grid = nullptr ); bool hasKingMoved ( Color color ); bool hasRookMoved ( Color color, Move::CastlingSide side ); QMap kingMoved; QMap kingRookMoved; QMap queenRookMoved; QMap queenRookStartPos; QMap kingRookStartPos; QList m_enPassantMoves; QMap kingPos; }; } #endif // KCHESS_CHESSRULES_H -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on; diff --git a/src/rules/rules.h b/src/rules/rules.h index 3b17a35..91ee2ff 100644 --- a/src/rules/rules.h +++ b/src/rules/rules.h @@ -1,118 +1,115 @@ /* This file is part of Knights, a chess board for KDE SC 4. Copyright 2009,2010,2011 Miha Čančula 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 . */ #ifndef KCHESS_RULES_H #define KCHESS_RULES_H #include "board.h" #include "core/piece.h" #include "knightsdebug.h" -#include - template class QMap; namespace Knights { class Pos; class Move; class Rules { public: enum Direction { None = 0, N = 0x001, S = 0x002, W = 0x004, E = 0x008, NW = 0x010, NE = 0x020, SW = 0x040, SE = 0x080, LineDirections = N | S | W | E, DiagDirections = NW | NE | SW | SE, AllDirections = LineDirections | DiagDirections }; typedef QFlags Directions; virtual ~Rules() = default; virtual void setGrid ( Grid* grid ) { qCDebug(LOG_KNIGHTS) << "Setting Grid"; m_grid = grid; } virtual QList legalMoves ( const Pos& pos ) = 0; /** * @return The positions and types of the staring pieces of the color @a color */ virtual PieceDataMap startingPieces () = 0; /** * Used to check whether any player has a winning position. * @return the color of the winner, or NoColor if no one has won yet * @note if the game is in a stalemate, NoColor is returned * @sa hasLegalMoves() */ virtual Color winner() = 0; /** * Check if the player has no legal moves * Used for determining stalemates */ virtual bool hasLegalMoves ( Color color ) = 0; /** * This function is more of a guideline for the board to determine whether a piece should be freely dragable. * It is currently not used anywhere in the game. */ virtual Directions legalDirections ( PieceType type ) = 0; /** * Checks if a piece on @a attackingPos is attacking the opponent's king * @param pos the position to check * @return true if a piece is attacking the king, false otherwise */ virtual bool isAttacking ( const Pos& attackingPos ) = 0; /** * Adds appropriate flags to the move. * Useful when processing moves from a computer engine, as they only specify the start and end pos, * and no other information * @param move a reference to the move with either @a from and @a to or its @a string already set. * @param color the color if the player who made this move */ virtual void checkSpecialFlags ( Move* move, Color color ) = 0; /** * Called when a move has been made, either by the player or a computer opponent * Useful to update any game state the rules engine has saved * @param move The move which was made, with all information about it. */ virtual void moveMade ( const Move& move ) = 0; protected: Grid *m_grid; }; } #endif // KCHESS_RULES_H -// kate: indent-mode cstyle; space-indent on; indent-width 4; replace-tabs on;