File indexing completed on 2024-04-28 07:54:27

0001 /*
0002     SPDX-FileCopyrightText: 2006 Matthew Williams <matt@milliams.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 //header
0008 #include "ksquareswindow.h"
0009 
0010 //qt
0011 #include <QAction>
0012 #include <QDebug>
0013 #include <QLabel>
0014 #include <QStandardItemModel>
0015 #include <QStatusBar>
0016 #include <QTimer>
0017 
0018 //kf
0019 #include <KConfigDialog>
0020 #include <KActionCollection>
0021 #include <KLocalizedString>
0022 
0023 // kdegames
0024 #include <KGameHighScoreDialog>
0025 #include <KGameStandardAction>
0026 
0027 //generated
0028 #include "settings.h"
0029 
0030 //classes
0031 #include "aicontroller.h"
0032 #include "gameboardview.h"
0033 
0034 //ui
0035 #include "newgamedialog.h"
0036 #include "scoresdialog.h"
0037 
0038 KSquaresWindow::KSquaresWindow() : KXmlGuiWindow(), m_view(new GameBoardView(this)), m_scene(nullptr)
0039 {
0040     setCentralWidget(m_view);
0041     QTimer::singleShot(0, this, &KSquaresWindow::initObject);
0042 }
0043 
0044 KSquaresWindow::~KSquaresWindow()
0045 {
0046     delete m_view;
0047     delete m_scene;
0048     delete sGame;
0049 }
0050 
0051 void KSquaresWindow::initObject()
0052 {
0053     sGame = new KSquaresGame();
0054     connect(sGame, &KSquaresGame::takeTurnSig, this, &KSquaresWindow::playerTakeTurn);
0055     connect(sGame, &KSquaresGame::gameOver, this, &KSquaresWindow::gameOver);
0056     m_view->setRenderHints(QPainter::Antialiasing);
0057     m_view->setFrameStyle(QFrame::NoFrame);
0058     setupActions();
0059     m_player = new QLabel(i18n("Current Player"));
0060     statusBar()->addPermanentWidget(m_player);
0061     statusBar()->show();
0062     setAutoSaveSettings();
0063 
0064     gameNew();
0065 }
0066 
0067 void KSquaresWindow::showHighscores()
0068 {
0069     KGameHighScoreDialog ksdialog(KGameHighScoreDialog::Name, this);
0070     ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Easy"), i18n("Easy")));
0071     ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Medium"), i18n("Medium")));
0072     ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Hard"), i18n("Hard")));
0073     ksdialog.exec();
0074 }
0075 
0076 void KSquaresWindow::gameNew()
0077 {
0078     //load settings
0079     NewGameDialog dialog(this);
0080 
0081     //create indexed arrays of the widgets
0082     QList<QLineEdit *> nameLineEditList;
0083     nameLineEditList.append(dialog.playerOneName);
0084     nameLineEditList.append(dialog.playerTwoName);
0085     nameLineEditList.append(dialog.playerThreeName);
0086     nameLineEditList.append(dialog.playerFourName);
0087     QList<QCheckBox *> humanCheckBoxList;
0088     humanCheckBoxList.append(dialog.playerOneHuman);
0089     humanCheckBoxList.append(dialog.playerTwoHuman);
0090     humanCheckBoxList.append(dialog.playerThreeHuman);
0091     humanCheckBoxList.append(dialog.playerFourHuman);
0092 
0093     //get settings from file
0094     for (int i = 0; i < Settings::playerNames().size(); i++) {
0095         nameLineEditList.at(i)->setText(Settings::playerNames().at(i));
0096     }
0097     for (int i = 0; i < Settings::playerNames().size(); i++) {
0098         if (Settings::humanList().at(i) == 2) {
0099             humanCheckBoxList.at(i)->setCheckState(Qt::Checked);
0100         } else {
0101             humanCheckBoxList.at(i)->setCheckState(Qt::Unchecked);
0102         }
0103     }
0104     dialog.spinNumOfPlayers->setValue(Settings::numOfPlayers());
0105     dialog.spinHeight->setValue(Settings::boardHeight());
0106     dialog.spinWidth->setValue(Settings::boardWidth());
0107     if (Settings::quickStart() == 2) {
0108         dialog.quickStartCheck->setCheckState(Qt::Checked);
0109     } else {
0110         dialog.quickStartCheck->setCheckState(Qt::Unchecked);
0111     }
0112 
0113     //run dialog
0114     dialog.exec();
0115     if (dialog.result() == QDialog::Rejected) {
0116         return;
0117     }
0118 
0119     //save settings
0120     Settings::setNumOfPlayers(dialog.spinNumOfPlayers->value());
0121 
0122     QStringList tempNames;
0123     for (int i = 0; i <= 3; i++) {
0124         tempNames.append(nameLineEditList.at(i)->text());
0125     }
0126     Settings::setPlayerNames(tempNames);
0127 
0128     QList<int> tempHuman;
0129     for (int i = 0; i <= 3; i++) {
0130         tempHuman.append(humanCheckBoxList.at(i)->checkState());
0131     }
0132     Settings::setHumanList(tempHuman);
0133 
0134     Settings::setBoardHeight(dialog.spinHeight->value());
0135     Settings::setBoardWidth(dialog.spinWidth->value());
0136     Settings::setQuickStart(dialog.quickStartCheck->checkState());
0137     Settings::self()->save();
0138 
0139     gameReset();
0140 }
0141 
0142 void KSquaresWindow::gameReset()
0143 {
0144     //create players
0145     QList<KSquaresPlayer> playerList;
0146     for (int i = 0; i < Settings::numOfPlayers(); i++) {
0147         QColor color;
0148         switch (i) {
0149         case 0: //Red
0150             color = QColor(191, 3, 3); //or darker: (156,15,15);
0151             break;
0152         case 1: //Blue
0153             color = QColor(0, 67, 138); //or darker: (0,49,110);
0154             break;
0155         case 2: //Green
0156             color = QColor(0, 137, 44); //or darker: (0,110,41);
0157             break;
0158         case 3: //Yellow
0159             color = QColor(243, 195, 0); //or darker: (227,173,0);
0160             break;
0161         default:
0162             qCritical() << "KSquaresGame::playerSquareComplete(); currentPlayerId() != 0|1|2|3";
0163         }
0164         playerList.append(KSquaresPlayer(Settings::playerNames().at(i), color, Settings::humanList().at(i)));
0165     }
0166 
0167     //create physical board
0168     GameBoardScene *temp = m_scene;
0169     m_scene = new GameBoardScene(Settings::boardWidth(), Settings::boardHeight());
0170 
0171     m_view->setScene(m_scene);
0172     delete temp;
0173 
0174     m_view->setBoardSize(); //refresh board zooming
0175 
0176     //start game etc.
0177     sGame->createGame(playerList, Settings::boardWidth(), Settings::boardHeight());
0178     connect(m_scene, &GameBoardScene::lineDrawn, sGame, &KSquaresGame::addLineToIndex);
0179     //QT5: VERIFY SIGNAL DOESN'T EXIST connect(m_scene,&GameBoardScene::signalMoveRequest,this,&KSquaresWindow::slotMoveRequest);
0180     connect(sGame, &KSquaresGame::drawLine, m_scene, &GameBoardScene::drawLine);
0181     connect(sGame, &KSquaresGame::highlightMove, m_scene, &GameBoardScene::highlightLine);
0182     connect(sGame, &KSquaresGame::drawSquare, m_scene, &GameBoardScene::drawSquare);
0183 
0184     if (Settings::quickStart() == 2) {
0185         //This is being done before sGame->start(); to avoid the players cycling
0186         aiController ai(-1, sGame->lines(), QList<int>(), sGame->boardWidth(), sGame->boardHeight());
0187         QList<int> lines = ai.autoFill(8);  //There will be 8 possible safe move for the players
0188         QListIterator<int> i(lines);
0189         while (i.hasNext()) {
0190             sGame->addLineToIndex(i.next());
0191         }
0192     }
0193     sGame->start();
0194 }
0195 
0196 void KSquaresWindow::gameOver(const QList<KSquaresPlayer> &_playerList)
0197 {
0198     QList<KSquaresPlayer> playerList = _playerList;
0199     std::sort(playerList.begin(), playerList.end(), std::greater<KSquaresPlayer>());
0200     //m_scene->displayScoreTable(playerList);
0201 
0202     ScoresDialog scoresDialog(this);
0203     scoresDialog.setWindowTitle(i18nc("@title:window", "Scores"));
0204 
0205     auto scoreTableModel = new QStandardItemModel(&scoresDialog);
0206     scoreTableModel->setRowCount(playerList.size());
0207     scoreTableModel->setColumnCount(2);
0208     scoreTableModel->setHeaderData(0, Qt::Horizontal, i18n("Player Name"));
0209     scoreTableModel->setHeaderData(1, Qt::Horizontal, i18n("Completed Squares"));
0210 
0211     for (int i = 0; i <  playerList.size(); i++) {
0212         scoreTableModel->setItem(i, 0, new QStandardItem(playerList.at(i).name()));
0213         scoreTableModel->item(i, 0)->setEditable(false);
0214 
0215         QString temp;
0216         temp.setNum(playerList.at(i).score());
0217         scoreTableModel->setItem(i, 1, new QStandardItem(temp));
0218         scoreTableModel->item(i, 1)->setEditable(false);
0219     }
0220 
0221     scoresDialog.scoreTable->setModel(scoreTableModel);
0222     scoresDialog.scoreTable->resizeColumnsToContents();
0223     scoresDialog.exec();
0224 
0225     if (playerList.at(0).isHuman()) {
0226         int score = (int)(static_cast<double>(playerList.at(0).score()) - (static_cast<double>(Settings::boardWidth() * Settings::boardHeight()) / static_cast<double>(playerList.size())));
0227 
0228         KGameHighScoreDialog ksdialog(KGameHighScoreDialog::Name, this);
0229         switch (Settings::difficulty()) {
0230         case 0:
0231             ksdialog.setConfigGroup(qMakePair(QByteArray("Easy"), i18n("Easy")));
0232             ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Medium"), i18n("Medium")));
0233             ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Hard"), i18n("Hard")));
0234             break;
0235         case 1:
0236             ksdialog.setConfigGroup(qMakePair(QByteArray("Medium"), i18n("Medium")));
0237             ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Easy"), i18n("Easy")));
0238             ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Hard"), i18n("Hard")));
0239             break;
0240         case 2:
0241             ksdialog.setConfigGroup(qMakePair(QByteArray("Hard"), i18n("Hard")));
0242             ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Easy"), i18n("Easy")));
0243             ksdialog.addLocalizedConfigGroupName(qMakePair(QByteArray("Medium"), i18n("Medium")));
0244             break;
0245         }
0246         KGameHighScoreDialog::FieldInfo scoreInfo;
0247         scoreInfo[KGameHighScoreDialog::Name] = playerList.at(0).name();
0248         scoreInfo[KGameHighScoreDialog::Score].setNum(score);
0249 
0250         if (ksdialog.addScore(scoreInfo, KGameHighScoreDialog::AskName)) {
0251             ksdialog.exec();
0252         }
0253     }
0254 }
0255 
0256 void KSquaresWindow::playerTakeTurn(KSquaresPlayer *currentPlayer)
0257 {
0258     ////qDebug() << "void KSquares::playerTakeTurn(KSquaresPlayer* currentPlayer)";
0259     m_player->setText(QStringLiteral("<font color=\"%1\">%2</font>")
0260                       .arg(currentPlayer->colour().name())
0261                       .arg(currentPlayer->name()));
0262     if (currentPlayer->isHuman()) {
0263         //Let the human player interact with the board through the GameBoardView
0264 
0265         setCursor(Qt::ArrowCursor);
0266         m_scene->enableEvents();
0267     } else { //AI
0268         //lock the view to let the AI do it's magic
0269         setCursor(Qt::WaitCursor);
0270         m_scene->disableEvents();
0271 
0272         QTimer::singleShot(200, this, &KSquaresWindow::aiChooseLine);
0273         setCursor(Qt::ArrowCursor);
0274     }
0275 }
0276 
0277 // testing only
0278 void KSquaresWindow::aiChooseLine()
0279 {
0280     // This can happen when we start a new game and the ai was playing, since we have a
0281     // 200 ms singleShot timer just above, the game may have changed since the timer was shot
0282     if (sGame->currentPlayer()->isHuman())
0283         return;
0284 
0285     aiController ai(sGame->currentPlayerId(), sGame->lines(), sGame->squares(), sGame->boardWidth(), sGame->boardHeight());
0286     sGame->addLineToIndex(ai.chooseLine());
0287 }
0288 
0289 void KSquaresWindow::setupActions()
0290 {
0291     KGameStandardAction::gameNew(this, &KSquaresWindow::gameNew, actionCollection());
0292     QAction *resetGame = KGameStandardAction::restart(this, &KSquaresWindow::gameReset, actionCollection());
0293     resetGame->setStatusTip(i18n("Start a new game with the current settings"));
0294 
0295     KGameStandardAction::highscores(this, &KSquaresWindow::showHighscores, actionCollection());
0296     KGameStandardAction::quit(this, &QWidget::close, actionCollection());
0297 
0298     // Preferences
0299     KStandardAction::preferences(this, &KSquaresWindow::optionsPreferences, actionCollection());
0300 
0301     setupGUI();
0302 }
0303 
0304 void KSquaresWindow::optionsPreferences()
0305 {
0306   auto dialog =
0307       new KConfigDialog(this, QStringLiteral("settings"), Settings::self());
0308 
0309   auto displaySettingsDialog = new QWidget;
0310   ui_prefs_display.setupUi(displaySettingsDialog);
0311   dialog->addPage(displaySettingsDialog, i18n("Display"),
0312                   QStringLiteral("preferences-desktop-display"));
0313 
0314   auto aiSettingsDialog = new QWidget;
0315   ui_prefs_ai.setupUi(aiSettingsDialog);
0316   dialog->addPage(aiSettingsDialog, i18n("Computer Player"),
0317                   QStringLiteral("games-difficult"));
0318 
0319   connect(dialog, &KConfigDialog::settingsChanged, m_view,
0320           &GameBoardView::setBoardSize);
0321   dialog->show();
0322 }
0323 
0324 #include "moc_ksquareswindow.cpp"