From 3d36cefa8d863a27c78f3c24c4fcb848a905191a Mon Sep 17 00:00:00 2001 From: liuweilhy Date: Sun, 9 Dec 2018 04:09:17 +0800 Subject: [PATCH] =?UTF-8?q?AI=E4=B8=8EGUI=E4=BA=A4=E4=BA=92=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NineChess/src/aithread.cpp | 2 +- NineChess/src/gamecontroller.cpp | 374 ++++++++++++++---------------- NineChess/src/gamecontroller.h | 10 +- NineChess/src/ninechessai_ab.cpp | 98 ++++---- NineChess/src/ninechessai_ab.h | 2 - NineChess/src/ninechesswindow.cpp | 148 +++++++----- NineChess/src/ninechesswindow.h | 38 +-- 7 files changed, 330 insertions(+), 342 deletions(-) diff --git a/NineChess/src/aithread.cpp b/NineChess/src/aithread.cpp index 72709978..8ab6bc11 100644 --- a/NineChess/src/aithread.cpp +++ b/NineChess/src/aithread.cpp @@ -48,7 +48,7 @@ void AiThread::run() mutex.unlock(); } - ai_ab.alphaBetaPruning(3); + ai_ab.alphaBetaPruning(6); const char * str = ai_ab.bestMove(); qDebug() << str; if (strcmp(str, "error!")) diff --git a/NineChess/src/gamecontroller.cpp b/NineChess/src/gamecontroller.cpp index d8b81154..e128d184 100644 --- a/NineChess/src/gamecontroller.cpp +++ b/NineChess/src/gamecontroller.cpp @@ -334,89 +334,22 @@ void GameController::timerEvent(QTimerEvent *event) */ } -bool GameController::command(const QString &cmd, bool update /*= true*/) -{ - // 防止接收滞后结束的线程发送的指令 - if (sender() == &ai1 && !isEngine1) - return false; - if (sender() == &ai2 && !isEngine2) - return false; - - if (!chess.command(cmd.toStdString().c_str())) - return false; - - if (chess.getPhase() == NineChess::GAME_NOTSTARTED) { - gameReset(); - gameStart(); - } - - if (update) - updateScence(chess); - - // 将新增的棋谱行插入到ListModel - currentRow = manualListModel.rowCount() - 1; - int k = 0; - // 输出命令行 - for (auto i = (chess.getCmdList())->begin(); i != (chess.getCmdList())->end(); ++i) { - // 跳过已添加的,因标准list容器没有下标 - if (k++ <= currentRow) - continue; - manualListModel.insertRow(++currentRow); - manualListModel.setData(manualListModel.index(currentRow), (*i).c_str()); - } - - // AI设置 - if (&chess == &(this->chess)) { - // 如果还未决出胜负 - if (chess.whoWin() == NineChess::NOBODY) { - if (chess.whosTurn() == NineChess::PLAYER1) { - if (isEngine1) - ai1.resume(); - } - else { - if (isEngine2) - ai2.resume(); - } - } - // 如果已经决出胜负 - else { - ai1.stop(); - ai2.stop(); - } - } - return true; -} - -// 历史局面 -bool GameController::phaseChange(int row) -{ - // 如果row是当前浏览的棋谱行,则不需要刷新 - if (currentRow == row) - return false; - - // 需要刷新 - currentRow = row; - int rows = manualListModel.rowCount(); - QStringList mlist = manualListModel.stringList(); - qDebug() << "rows:" << rows << " current:" << row; - for (int i = 0; i <= row; i++) - { - qDebug() << mlist.at(i); - chessTemp.command(mlist.at(i).toStdString().c_str()); - } - // 下面这步关键,会让悔棋者承担时间损失 - chessTemp.setStartTimeb(chess.getStartTimeb()); - // 刷新棋局场景 - updateScence(chessTemp); - return true; -} - // 槽函数,根据QGraphicsScene的信号和状态来执行选子、落子或去子 bool GameController::actionPiece(QPointF pos) { - bool result = false; + // 点击非落子点,不执行 + int c, p; + if (!scene.pos2cp(pos, c, p)) { + return false; + } - // 是否在浏览历史记录 + // 电脑走棋时,点击无效 + if (chess.whosTurn() == NineChess::PLAYER1 && isEngine1) + return false; + if (chess.whosTurn() == NineChess::PLAYER2 && isEngine2) + return false; + + // 在浏览历史记录时点击棋盘,则认为是悔棋 if (currentRow != manualListModel.rowCount() - 1) { // 定义新对话框 @@ -444,39 +377,60 @@ bool GameController::actionPiece(QPointF pos) } } else - { - return result; - } + return false; } - - switch (chess.getPhase()) { - case NineChess::GAME_NOTSTARTED: - // 如果未开局则开局,这里还要继续判断,不可break + // 如果未开局则开局 + if (chess.getPhase() == NineChess::GAME_NOTSTARTED) gameStart(); - case NineChess::GAME_OPENING: - // 如果是开局阶段(轮流落下新子),落子 - if (chess.getAction() == NineChess::ACTION_PLACE) { - result = placePiece(pos); - }// 去子 - else if (chess.getAction() == NineChess::ACTION_CAPTURE) { - result = capturePiece(pos); + // 判断执行选子、落子或去子 + bool result = false; + PieceItem *piece = nullptr; + QGraphicsItem *item = scene.itemAt(pos, QTransform()); + + switch (chess.getAction()) + { + case NineChess::ACTION_PLACE: + if (chess.place(c, p)) + { + if (chess.getAction() == NineChess::ACTION_CAPTURE) { + // 播放成三音效 + playSound(":/sound/resources/sound/capture.wav"); + } + else { + // 播放移动棋子音效 + playSound(":/sound/resources/sound/drog.wav"); + } + result = true; + break; + } + // 如果移子不成功,尝试重新选子,这里不break + + case NineChess::ACTION_CHOOSE: + piece = qgraphicsitem_cast(item); + if (!piece) + break; + if (chess.choose(c, p)) { + // 播放选子音效 + playSound(":/sound/resources/sound/choose.wav"); + result = true; + } + else { + // 播放禁止音效 + playSound(":/sound/resources/sound/forbidden.wav"); } break; - case NineChess::GAME_MID: - // 如果是中局阶段(轮流移子) - // 选子 - if (chess.getAction() == NineChess::ACTION_CHOOSE) { - result = choosePiece(pos); - }// 移子 - else if (chess.getAction() == NineChess::ACTION_PLACE) { - // 如果移子不成功,尝试重新选子 - result = movePiece(pos); - }// 去子 - else if (chess.getAction() == NineChess::ACTION_CAPTURE) { - result = capturePiece(pos); + case NineChess::ACTION_CAPTURE: + if (chess.capture(c, p)) { + // 播放音效 + playSound(":/sound/resources/sound/remove.wav"); + result = true; + } + else { + // 播放禁止音效 + playSound(":/sound/resources/sound/forbidden.wav"); } break; @@ -487,6 +441,10 @@ bool GameController::actionPiece(QPointF pos) if (result) { + // 发信号更新状态栏 + message = QString::fromStdString(chess.getTip()); + emit statusBarChanged(message); + // 将新增的棋谱行插入到ListModel currentRow = manualListModel.rowCount() - 1; int k = 0; @@ -498,116 +456,142 @@ bool GameController::actionPiece(QPointF pos) manualListModel.insertRow(++currentRow); manualListModel.setData(manualListModel.index(currentRow), (*i).c_str()); } - if (chess.whoWin() != NineChess::NOBODY && - (manualListModel.data(manualListModel.index(currentRow-1))).toString().contains("Time over.")) + if (chess.whoWin() != NineChess::NOBODY && + (manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over.")) playSound(":/sound/resources/sound/win.wav"); + + // AI设置 + if (&chess == &(this->chess)) { + // 如果还未决出胜负 + if (chess.whoWin() == NineChess::NOBODY) { + if (chess.whosTurn() == NineChess::PLAYER1) { + if (isEngine1) + ai1.resume(); + if (isEngine2) + ai2.pause(); + } + else { + if (isEngine1) + ai1.pause(); + if (isEngine2) + ai2.resume(); + } + } + // 如果已经决出胜负 + else { + ai1.stop(); + ai2.stop(); + } + } } updateScence(); return result; } -// 选子 -bool GameController::choosePiece(QPointF pos) +// 棋谱的命令行执行 +bool GameController::command(const QString &cmd, bool update /*= true*/) { - int c, p; - if (!scene.pos2cp(pos, c, p)) { - return false; - } - PieceItem *piece = nullptr; - QGraphicsItem *item = scene.itemAt(pos, QTransform()); - piece = qgraphicsitem_cast(item); - if (!piece) { - return false; - } - if (chess.choose(c, p)) { - // 发信号更新状态栏 - message = QString::fromStdString(chess.getTip()); - emit statusBarChanged(message); - // 播放选子音效 - playSound(":/sound/resources/sound/choose.wav"); - return true; - } - else { - // 播放禁止音效 - playSound(":/sound/resources/sound/forbidden.wav"); - return false; - } -} + Q_UNUSED(hasSound) -// 落下新子 -bool GameController::placePiece(QPointF pos) -{ - int c, p; - if (!scene.pos2cp(pos, c, p)) { + // 防止接收滞后结束的线程发送的指令 + if (sender() == &ai1 && !isEngine1) return false; - } - if (!chess.place(c, p)) { - // 播放禁止音效 - playSound(":/sound/resources/sound/forbidden.wav"); + if (sender() == &ai2 && !isEngine2) return false; + + // 声音 + QString sound; + switch (chess.getAction()) + { + case NineChess::ACTION_CHOOSE: + case NineChess::ACTION_PLACE: + sound = ":/sound/resources/sound/drog.wav"; + break; + case NineChess::ACTION_CAPTURE: + sound = ":/sound/resources/sound/remove.wav"; + break; + default: + break; + } + + if (!chess.command(cmd.toStdString().c_str())) + return false; + + if (sound == ":/sound/resources/sound/drog.wav" && chess.getAction() == NineChess::ACTION_CAPTURE) + { + sound = ":/sound/resources/sound/capture.wav"; + } + + if (chess.getPhase() == NineChess::GAME_NOTSTARTED) { + gameReset(); + gameStart(); + } + + if (update) { + playSound(sound); + updateScence(chess); + } + + // 将新增的棋谱行插入到ListModel + currentRow = manualListModel.rowCount() - 1; + int k = 0; + // 输出命令行 + for (auto i = (chess.getCmdList())->begin(); i != (chess.getCmdList())->end(); ++i) { + // 跳过已添加的,因标准list容器没有下标 + if (k++ <= currentRow) + continue; + manualListModel.insertRow(++currentRow); + manualListModel.setData(manualListModel.index(currentRow), (*i).c_str()); + } + + // AI设置 + if (&chess == &(this->chess)) { + // 如果还未决出胜负 + if (chess.whoWin() == NineChess::NOBODY) { + if (chess.whosTurn() == NineChess::PLAYER1) { + if (isEngine1) + ai1.resume(); + if (isEngine2) + ai2.pause(); + } + else { + if (isEngine1) + ai1.pause(); + if (isEngine2) + ai2.resume(); + } + } + // 如果已经决出胜负 + else { + ai1.stop(); + ai2.stop(); + } } - // 发信号更新状态栏 - message = QString::fromStdString(chess.getTip()); - emit statusBarChanged(message); - // 播放成三音效 - if (chess.getAction() == NineChess::ACTION_CAPTURE) - playSound(":/sound/resources/sound/capture.wav"); - // 播放落下棋子音效 - else - playSound(":/sound/resources/sound/drog.wav"); return true; } -// 移动旧子 -bool GameController::movePiece(QPointF pos) +// 浏览历史局面,通过command函数刷新局面显示 +bool GameController::phaseChange(int row) { - if (!currentPiece) { + // 如果row是当前浏览的棋谱行,则不需要刷新 + if (currentRow == row) return false; - } - int c, p; - if (!scene.pos2cp(pos, c, p)) { - return false; - } - if (chess.place(c, p)) + // 需要刷新 + currentRow = row; + int rows = manualListModel.rowCount(); + QStringList mlist = manualListModel.stringList(); + qDebug() << "rows:" << rows << " current:" << row; + for (int i = 0; i <= row; i++) { - // 发信号更新状态栏 - message = QString::fromStdString(chess.getTip()); - emit statusBarChanged(message); - // 播放成三音效 - if (chess.getAction() == NineChess::ACTION_CAPTURE) - playSound(":/sound/resources/sound/capture.wav"); - // 播放移动棋子音效 - else - playSound(":/sound/resources/sound/move.wav"); - return true; + qDebug() << mlist.at(i); + chessTemp.command(mlist.at(i).toStdString().c_str()); } - // 如果移子不成功,尝试重新选子 - else - { - return choosePiece(pos); - } -} - -// 去子 -bool GameController::capturePiece(QPointF pos) -{ - int c, p; - if (!scene.pos2cp(pos, c, p)) { - return false; - } - if (!chess.capture(c, p)) { - // 播放禁止音效 - playSound(":/sound/resources/sound/forbidden.wav"); - return false; - } - - // 发信号更新状态栏 - message = QString::fromStdString(chess.getTip()); - emit statusBarChanged(message); - // 播放音效 - playSound(":/sound/resources/sound/remove.wav"); + // 下面这步关键,会让悔棋者承担时间损失 + chessTemp.setStartTimeb(chess.getStartTimeb()); + // 刷新棋局场景 + updateScence(chessTemp); return true; } diff --git a/NineChess/src/gamecontroller.h b/NineChess/src/gamecontroller.h index e3281d68..09805743 100644 --- a/NineChess/src/gamecontroller.h +++ b/NineChess/src/gamecontroller.h @@ -75,7 +75,7 @@ public slots: bool command(const QString &cmd, bool update = true); // 历史局面及局面改变 bool phaseChange(int row); - // 更新棋局显示,每步后必须执行 + // 更新棋局显示,每步后执行才能刷新局面 bool updateScence(); bool updateScence(NineChess &chess); @@ -83,14 +83,6 @@ protected: //bool eventFilter(QObject * watched, QEvent * event); // 定时器 void timerEvent(QTimerEvent * event); - // 选子 - bool choosePiece(QPointF pos); - // 落下新子 - bool placePiece(QPointF pos); - // 移动旧子 - bool movePiece(QPointF pos); - // 去子 - bool capturePiece(QPointF pos); private: // 棋对象的数据模型 diff --git a/NineChess/src/ninechessai_ab.cpp b/NineChess/src/ninechessai_ab.cpp index 6e807564..9eb9c8d2 100644 --- a/NineChess/src/ninechessai_ab.cpp +++ b/NineChess/src/ninechessai_ab.cpp @@ -7,7 +7,6 @@ #include "ninechessai_ab.h" #include #include -#include NineChessAi_ab::NineChessAi_ab(): rootNode(nullptr), @@ -156,28 +155,6 @@ void NineChessAi_ab::setChess(const NineChess &chess) rootNode->parent = nullptr; requiredQuit = false; - // 生成棋子价值表 - for (int j = 0; j < NineChess::SEAT; j++) - { - // 对于0、2、4、6位(偶数位) - if (!(j & 1)) { - boardScore[1 * NineChess::SEAT + j] = 90; - boardScore[2 * NineChess::SEAT + j] = 100; - boardScore[3 * NineChess::SEAT + j] = 90; - } - // 对于有斜线情况下的1、3、5、7位(奇数位) - else if(chessTemp.rule.hasObliqueLine) { - boardScore[1 * NineChess::SEAT + j] = 85; - boardScore[2 * NineChess::SEAT + j] = 95; - boardScore[3 * NineChess::SEAT + j] = 85; - } - // 对于无斜线情况下的1、3、5、7位(奇数位) - else { - boardScore[1 * NineChess::SEAT + j] = 80; - boardScore[2 * NineChess::SEAT + j] = 85; - boardScore[3 * NineChess::SEAT + j] = 80; - } - } } int NineChessAi_ab::evaluate(Node *node) @@ -189,27 +166,38 @@ int NineChessAi_ab::evaluate(Node *node) case NineChess::GAME_NOTSTARTED: break; - // 开局和中局阶段用同样的评价方法 case NineChess::GAME_OPENING: - case NineChess::GAME_MID: - // 按手棋数目计分,每子50分 - value += (chessData->player1_InHand) * 50 - (chessData->player2_InHand) * 50; + // 按手中的棋子计分,不要break; + value += chessData->player1_InHand * 50 - chessData->player2_InHand * 50; // 按场上棋子计分 - for (int i = 1*NineChess::SEAT; i < NineChess::SEAT*(NineChess::RING+1); i++) { - if (chessData->board[i] & 0x10) - value += boardScore[i]; - else if (chessData->board[i] & 0x20) - value -= boardScore[i]; + value += chessData->player1_Remain * 100 - chessData->player2_Remain * 100; + switch (chessData->action) + { + // 选子和落子使用相同的评价方法 + case NineChess::ACTION_CHOOSE: + case NineChess::ACTION_PLACE: + break; + // 如果形成去子状态,每有一个可去的子,算100分 + case NineChess::ACTION_CAPTURE: + value += (chessData->turn == NineChess::PLAYER1) ? (chessData->num_NeedRemove) * 100 : -(chessData->num_NeedRemove) * 100; + break; + default: + break; } + break; + + case NineChess::GAME_MID: + // 按场上棋子计分 + value += chessData->player1_Remain * 100 - chessData->player2_Remain * 100; switch (chessData->action) { // 选子和落子使用相同的评价方法 case NineChess::ACTION_CHOOSE: case NineChess::ACTION_PLACE: break; - // 如果形成去子状态,每有一个可去的子,算1000分 + // 如果形成去子状态,每有一个可去的子,算100分 case NineChess::ACTION_CAPTURE: - value += (chessData->turn == NineChess::PLAYER1) ? chessData->num_NeedRemove * 1000 : -chessData->num_NeedRemove * 1000; + value += (chessData->turn == NineChess::PLAYER1) ? (chessData->num_NeedRemove) * 100 : -(chessData->num_NeedRemove) * 100; break; default: break; @@ -242,6 +230,9 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) { // 评价值 int value; + // 当前节点的MinMax值,最终赋值给节点value,与alpha和Beta不同 + int minMax; + if (!depth || chessTemp.data.phase == NineChess::GAME_OVER) { node->value = evaluate(node); return node->value; @@ -255,45 +246,45 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) // 根据演算模型执行MiniMax检索 // 对先手,搜索Max if (chessTemp.whosTurn() == NineChess::PLAYER1) { + minMax = -infinity; for (auto child : node->children) { dataStack.push(chessTemp.data); - if(!chessTemp.command(child->move)) - qDebug() << child->move; + chessTemp.command(child->move); value = alphaBetaPruning(depth - 1, alpha, beta, child); chessTemp.data = dataStack.top(); dataStack.pop(); // 取最大值 + if (value > minMax) + minMax = value; if (value > alpha) alpha = value; // 剪枝返回 - if (alpha >= beta) { - node->value = alpha; - return value; - } + if (alpha >= beta) + break; } // 取最大值 - node->value = alpha; + node->value = minMax; } // 对后手,搜索Min else { + minMax = infinity; for (auto child : node->children) { dataStack.push(chessTemp.data); - if(!chessTemp.command(child->move)) - qDebug() << child->move; + chessTemp.command(child->move); value = alphaBetaPruning(depth - 1, alpha, beta, child); chessTemp.data = dataStack.top(); dataStack.pop(); // 取最小值 + if (value < minMax) + minMax = value; if (value < beta) beta = value; // 剪枝返回 - if (alpha >= beta) { - node->value = beta; - return value; - } + if (alpha >= beta) + break; } // 取最小值 - node->value = beta; + node->value = minMax; } // 返回 return node->value; @@ -303,18 +294,11 @@ const char *NineChessAi_ab::bestMove() { if ((rootNode->children).size() == 0) return "error!"; - // 在最好的招法中随机挑一个 - int16_t moves[12] = {0}; - int n = 0; for (auto child : rootNode->children) { if (child->value == rootNode->value) - moves[n++] = child->move; - if (n >= 12) - break; + return move2string(child->move); } - srand((unsigned)time(0)); - int i = rand() % n; - return move2string(moves[i]); + return "error!"; } const char *NineChessAi_ab::move2string(int16_t move) diff --git a/NineChess/src/ninechessai_ab.h b/NineChess/src/ninechessai_ab.h index 10d5e037..9867453c 100644 --- a/NineChess/src/ninechessai_ab.h +++ b/NineChess/src/ninechessai_ab.h @@ -97,8 +97,6 @@ private: static const int infinity = INT32_MAX; private: - // 棋子价值表 - char boardScore[(NineChess::RING + 2)*NineChess::SEAT]; // 命令行 char cmdline[32]; }; diff --git a/NineChess/src/ninechesswindow.cpp b/NineChess/src/ninechesswindow.cpp index d41ebdbf..7459a7d7 100644 --- a/NineChess/src/ninechesswindow.cpp +++ b/NineChess/src/ninechesswindow.cpp @@ -27,7 +27,8 @@ NineChessWindow::NineChessWindow(QWidget *parent) : QMainWindow(parent), scene(nullptr), game(nullptr), - ruleNo(-1) + ruleNo(-1), + autoRunTimer(this) { ui.setupUi(this); //去掉标题栏 @@ -73,10 +74,14 @@ NineChessWindow::NineChessWindow(QWidget *parent) // 初始化游戏规则菜单 ui.menu_R->installEventFilter(this); + // 关联自动运行定时器 + connect(&autoRunTimer, SIGNAL(timeout()), + this, SLOT(onAutoRunTimeOut())); + // 主窗口居中显示 QRect deskTopRect = qApp->desktop()->availableGeometry(); - int unitw=(deskTopRect.width() - width())/2; - int unith=(deskTopRect.height() - height())/2; + int unitw = (deskTopRect.width() - width())/2; + int unith = (deskTopRect.height() - height())/2; this->move(unitw,unith); // 游戏初始化 @@ -96,6 +101,8 @@ void NineChessWindow::closeEvent(QCloseEvent *event) { if (file.isOpen()) file.close(); + // 取消自动运行 + ui.actionAutoRun_A->setChecked(false); //qDebug() << "closed"; QMainWindow::closeEvent(event); } @@ -310,9 +317,13 @@ void NineChessWindow::on_actionLimited_T_triggered() void NineChessWindow::actionRules_triggered() { + // 取消自动运行 + ui.actionAutoRun_A->setChecked(false); + // 取消其它规则的选择 for(QAction *action: ruleActionList) action->setChecked(false); + // 选择当前规则 QAction *action = dynamic_cast(sender()); action->setChecked(true); @@ -336,6 +347,8 @@ void NineChessWindow::on_actionNew_N_triggered() { if (file.isOpen()) file.close(); + // 取消自动运行 + ui.actionAutoRun_A->setChecked(false); // 取消AI设定 ui.actionEngine1_T->setChecked(false); ui.actionEngine2_R->setChecked(false); @@ -525,6 +538,10 @@ void NineChessWindow::on_actionRowChange() } } + // 更新局面 + game->phaseChange(currentRow); + + /* 下面的代码全部取消,改用QTimer的方式实现 // 更新局面 bool changed = game->phaseChange(currentRow); // 处理自动播放时的动画 @@ -542,70 +559,77 @@ void NineChessWindow::on_actionRowChange() QTimer::singleShot(waitTime, &loop, SLOT(quit())); loop.exec(); } + */ +} + +void NineChessWindow::onAutoRunTimeOut(QPrivateSignal signal) +{ + int rows = ui.listView->model()->rowCount(); + int currentRow = ui.listView->currentIndex().row(); + + if (rows <= 1) { + ui.actionAutoRun_A->setChecked(false); + return; + } + + // 执行“下一招” + if (currentRow < rows - 1) + { + if (currentRow < rows - 1) + { + ui.listView->setCurrentIndex(ui.listView->model()->index(currentRow + 1, 0)); + } + currentRow = ui.listView->currentIndex().row(); + // 更新动作状态 + if (currentRow <= 0) { + ui.actionBegin_S->setEnabled(false); + ui.actionPrevious_B->setEnabled(false); + ui.actionNext_F->setEnabled(true); + ui.actionEnd_E->setEnabled(true); + ui.actionAutoRun_A->setEnabled(true); + } + else if (currentRow >= rows - 1) + { + ui.actionBegin_S->setEnabled(true); + ui.actionPrevious_B->setEnabled(true); + ui.actionNext_F->setEnabled(false); + ui.actionEnd_E->setEnabled(false); + ui.actionAutoRun_A->setEnabled(false); + } + else + { + ui.actionBegin_S->setEnabled(true); + ui.actionPrevious_B->setEnabled(true); + ui.actionNext_F->setEnabled(true); + ui.actionEnd_E->setEnabled(true); + ui.actionAutoRun_A->setEnabled(true); + } + + // 更新局面 + game->phaseChange(currentRow); + } + else { + ui.actionAutoRun_A->setChecked(false); + } } // 自动运行 void NineChessWindow::on_actionAutoRun_A_toggled(bool arg1) { - if (!arg1) - return; - - int rows = ui.listView->model()->rowCount(); - int currentRow = ui.listView->currentIndex().row(); - - if (rows <= 1) - return; - - // 自动运行前禁用所有控件 - ui.menuBar->setEnabled(false); - ui.mainToolBar->setEnabled(false); - ui.dockWidget->setEnabled(false); - ui.gameView->setEnabled(false); - - // 反复执行“下一招” - while (currentRow < rows - 1) - { - if (currentRow < rows - 1) - { - ui.listView->setCurrentIndex(ui.listView->model()->index(currentRow + 1, 0)); - } - currentRow = ui.listView->currentIndex().row(); - // 更新动作状态 - if (currentRow <= 0) { - ui.actionBegin_S->setEnabled(false); - ui.actionPrevious_B->setEnabled(false); - ui.actionNext_F->setEnabled(true); - ui.actionEnd_E->setEnabled(true); - ui.actionAutoRun_A->setEnabled(true); - } - else if (currentRow >= rows - 1) - { - ui.actionBegin_S->setEnabled(true); - ui.actionPrevious_B->setEnabled(true); - ui.actionNext_F->setEnabled(false); - ui.actionEnd_E->setEnabled(false); - ui.actionAutoRun_A->setEnabled(false); - } - else - { - ui.actionBegin_S->setEnabled(true); - ui.actionPrevious_B->setEnabled(true); - ui.actionNext_F->setEnabled(true); - ui.actionEnd_E->setEnabled(true); - ui.actionAutoRun_A->setEnabled(true); - } - - // 更新局面 - game->phaseChange(currentRow); - } - - // 自动运行结束后启用所有控件 - ui.menuBar->setEnabled(true); - ui.mainToolBar->setEnabled(true); - ui.dockWidget->setEnabled(true); - ui.gameView->setEnabled(true); - // 取消自动运行按钮的选中状态 - ui.actionAutoRun_A->setChecked(false); + if (arg1) { + // 自动运行前禁用控件 + ui.dockWidget->setEnabled(false); + ui.gameView->setEnabled(false); + // 启动定时器 + autoRunTimer.start(game->getDurationTime() + 50); + } + else { + // 关闭定时器 + autoRunTimer.stop(); + // 自动运行结束后启用控件 + ui.dockWidget->setEnabled(true); + ui.gameView->setEnabled(true); + } } void NineChessWindow::on_actionLocal_L_triggered() diff --git a/NineChess/src/ninechesswindow.h b/NineChess/src/ninechesswindow.h index 7992f33d..1f12020a 100644 --- a/NineChess/src/ninechesswindow.h +++ b/NineChess/src/ninechesswindow.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "ui_ninechesswindow.h" class GameScene; @@ -22,27 +23,16 @@ protected: bool eventFilter(QObject * watched, QEvent * event); void closeEvent(QCloseEvent *event); -private: - // 界面文件 - Ui::NineChessWindowClass ui; - // 视图场景 - GameScene *scene; - // 控制器 - GameController *game; - // 动态增加的菜单栏动作列表 - QList ruleActionList; - // 游戏的规则号,涉及菜单项和对话框,所以要有 - int ruleNo; - // 文件 - QFile file; - // 更新规则标签 - void ruleInfo(); - private slots: // 初始化 void initialize(); // 动态增加的菜单栏动作的槽函数 void actionRules_triggered(); + // 更新规则标签 + void ruleInfo(); + // 自动运行定时处理函数 + void onAutoRunTimeOut(QPrivateSignal signal); + // 下面是各动作的槽函数 // 注释掉的是已在UI管理器或主窗口初始化函数中连接好的 void on_actionNew_N_triggered(); @@ -74,6 +64,22 @@ private slots: void on_actionViewHelp_V_triggered(); void on_actionWeb_W_triggered(); void on_actionAbout_A_triggered(); + +private: + // 界面文件 + Ui::NineChessWindowClass ui; + // 视图场景 + GameScene *scene; + // 控制器 + GameController *game; + // 动态增加的菜单栏动作列表 + QList ruleActionList; + // 游戏的规则号,涉及菜单项和对话框,所以要有 + int ruleNo; + // 文件 + QFile file; + // 定时器 + QTimer autoRunTimer; }; #endif // NINECHESSWINDOW_H