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"