diff --git a/gamewindow.ui b/gamewindow.ui index e247efef..cb6169aa 100644 --- a/gamewindow.ui +++ b/gamewindow.ui @@ -291,6 +291,7 @@ + @@ -1113,6 +1114,17 @@ 电脑着法随机(&R) + + + true + + + true + + + 必败时认输(&G) + + diff --git a/src/ai/search.cpp b/src/ai/search.cpp index 3c4c256c..e80690f2 100644 --- a/src/ai/search.cpp +++ b/src/ai/search.cpp @@ -831,6 +831,7 @@ const char* MillGameAi_ab::bestMove() { vector bestMoves; size_t bestMovesSize = 0; + bool isMostLose = true; // 是否必败 if ((rootNode->children).empty()) { return "error!"; @@ -867,6 +868,30 @@ const char* MillGameAi_ab::bestMove() i++; } + // 检查是否必败 + + MillGame::Player whosTurn = chess_.whosTurn(); + + for (auto child : rootNode->children) { + // TODO: 使用常量代替 + if (whosTurn == MillGame::PLAYER1 && child->value > -10000 || + whosTurn == MillGame::PLAYER2 && child->value < 10000) { + isMostLose = false; + break; + } + } + + // 自动认输 + if (isMostLose) { + if (whosTurn == MillGame::PLAYER1) { + sprintf(cmdline, "Player1 give up!"); + } else if (whosTurn == MillGame::PLAYER2) { + sprintf(cmdline, "Player2 give up!"); + } + + return cmdline; + } + for (auto child : rootNode->children) { if (child->value == rootNode->value) { bestMoves.push_back(child); diff --git a/src/game/millgame.cpp b/src/game/millgame.cpp index 5b67e97d..7c822214 100644 --- a/src/game/millgame.cpp +++ b/src/game/millgame.cpp @@ -168,6 +168,7 @@ MillGame &MillGame::operator = (const MillGame &chess) currentStep = chess.currentStep; moveStep = chess.moveStep; randomMove_ = chess.randomMove_; + giveUpIfMostLose_ = chess.giveUpIfMostLose_; board_ = context.board; currentPos = chess.currentPos; winner = chess.winner; @@ -663,8 +664,11 @@ void MillGame::createMillTable() } // 设置配置 -bool MillGame::configure(bool randomMove) +bool MillGame::configure(bool giveUpIfMostLose, bool randomMove) { + // 设置是否必败时认输 + this->giveUpIfMostLose_ = giveUpIfMostLose; + // 设置是否随机走子 this->randomMove_ = randomMove; @@ -1398,10 +1402,12 @@ bool MillGame::giveup(Player loser) winner = PLAYER2; tips = "玩家1投子认负。"; sprintf(cmdline, "Player1 give up!"); + score_2++; } else if (loser == PLAYER2) { winner = PLAYER1; tips = "玩家2投子认负。"; sprintf(cmdline, "Player2 give up!"); + score_1++; } cmdlist.emplace_back(string(cmdline)); @@ -1465,7 +1471,7 @@ bool MillGame::command(const char *cmd) } // 认输 - args = sscanf(cmd, "Players%1u give up!", &t); + args = sscanf(cmd, "Player%1u give up!", &t); if (args == 1) { if (t == 1) { diff --git a/src/game/millgame.h b/src/game/millgame.h index 80854146..f0fe6239 100644 --- a/src/game/millgame.h +++ b/src/game/millgame.h @@ -304,7 +304,7 @@ public: MillGame &operator=(const MillGame &); // 设置配置 - bool configure(bool randomMove); + bool configure(bool giveUpIfMostLose, bool randomMove); // 设置棋局状态和棋盘上下文,用于初始化 bool setContext(const struct Rule *rule, @@ -362,6 +362,12 @@ public: int getMoveStep() const { return moveStep; + } + + // 获取是否必败时认输 + bool getGiveUpIfMostLose() const + { + return giveUpIfMostLose_; } // 获取 AI 是否随机走子 @@ -575,6 +581,9 @@ private: // 从走子阶段开始或上次吃子起的步数 int moveStep {}; + // 是否必败时认输 + bool giveUpIfMostLose_ {true}; + // AI 是否随机走子 bool randomMove_ {true}; diff --git a/src/ui/qt/gamecontroller.cpp b/src/ui/qt/gamecontroller.cpp index 7508b2a4..183eabd6 100644 --- a/src/ui/qt/gamecontroller.cpp +++ b/src/ui/qt/gamecontroller.cpp @@ -54,6 +54,7 @@ GameController::GameController(GameScene & scene, QObject * parent) : ruleNo_(-1), timeLimit(0), stepsLimit(50), + giveUpIfMostLose_(true), randomMove_(true) { // 已在view的样式表中添加背景,scene中不用添加背景 @@ -116,7 +117,7 @@ const QMap GameController::getActions() void GameController::gameStart() { - chess_.configure(randomMove_); + chess_.configure(giveUpIfMostLose_, randomMove_); chess_.start(); chessTemp = chess_; @@ -142,7 +143,7 @@ void GameController::gameReset() } // 重置游戏 - chess_.configure(randomMove_); + chess_.configure(giveUpIfMostLose_, randomMove_); chess_.reset(); chessTemp = chess_; @@ -283,7 +284,7 @@ void GameController::setRule(int ruleNo, MillGame::step_t stepLimited /*= -1*/, void GameController::setEngine1(bool arg) { - chess_.configure(randomMove_); + chess_.configure(giveUpIfMostLose_, randomMove_); isAiPlayer1 = arg; if (arg) { @@ -299,7 +300,7 @@ void GameController::setEngine1(bool arg) void GameController::setEngine2(bool arg) { - chess_.configure(randomMove_); + chess_.configure(giveUpIfMostLose_, randomMove_); isAiPlayer2 = arg; if (arg) { @@ -370,6 +371,11 @@ void GameController::playSound(const QString &soundPath) #endif /* ! DONOT_PLAY_SOUND */ } +void GameController::setGiveUpIfMostLose(bool arg) +{ + giveUpIfMostLose_ = arg; +} + void GameController::setAutoRestart(bool arg) { isAutoRestart = arg; @@ -778,11 +784,9 @@ bool GameController::giveUp() if (chess_.whosTurn() == MillGame::PLAYER1) { result = chess_.giveup(MillGame::PLAYER1); - chess_.score_2++; } else if (chess_.whosTurn() == MillGame::PLAYER2) { result = chess_.giveup(MillGame::PLAYER2); - chess_.score_1++; } if (result) { diff --git a/src/ui/qt/gamecontroller.h b/src/ui/qt/gamecontroller.h index 0787cd50..06b055ea 100644 --- a/src/ui/qt/gamecontroller.h +++ b/src/ui/qt/gamecontroller.h @@ -70,6 +70,11 @@ public: return stepsLimit; } + bool getGiveUpIfMostLose() + { + return giveUpIfMostLose_; + } + bool getRandomMove() { return randomMove_; @@ -150,6 +155,9 @@ public slots: // 播放声音 void playSound(const QString &soundPath); + // 是否必败时认输 + void setGiveUpIfMostLose(bool arg); + // 是否自动开局 void setAutoRestart(bool arg = false); @@ -240,6 +248,9 @@ private: // 是否有落子音效 bool hasSound; + // 是否必败时认输 + bool giveUpIfMostLose_; + // 是否棋局结束后自动重新开局 bool isAutoRestart; diff --git a/src/ui/qt/gamewindow.cpp b/src/ui/qt/gamewindow.cpp index 384e9e67..5ab7a4df 100644 --- a/src/ui/qt/gamewindow.cpp +++ b/src/ui/qt/gamewindow.cpp @@ -204,6 +204,9 @@ void MillGameWindow::initialize() connect(ui.actionAnimation_A, SIGNAL(toggled(bool)), game, SLOT(setAnimation(bool))); + connect(ui.actionGiveUpIfMostLose_G, SIGNAL(toggled(bool)), + game, SLOT(setGiveUpIfMostLose(bool))); + connect(ui.actionAutoRestart_A, SIGNAL(toggled(bool)), game, SLOT(setAutoRestart(bool)));