diff --git a/src/ai/evaluate.cpp b/src/ai/evaluate.cpp index caf9d31f..dd53f149 100644 --- a/src/ai/evaluate.cpp +++ b/src/ai/evaluate.cpp @@ -21,7 +21,7 @@ #include "evaluate.h" -value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillGameAi_ab::Node *node) +value_t Evaluation::getValue(Position &dummyPosition, PositionContext *positionContext, MillGameAi_ab::Node *node) { // 初始评估值为0,对先手有利则增大,对后手有利则减小 value_t value = 0; @@ -31,31 +31,31 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG int nPiecesNeedRemove = 0; #ifdef DEBUG_AB_TREE - node->stage = gameContext->stage; - node->action = gameContext->action; + node->stage = positionContext->stage; + node->action = positionContext->action; node->evaluated = true; #endif - switch (gameContext->stage) { + switch (positionContext->stage) { case GAME_NOTSTARTED: break; case GAME_PLACING: // 按手中的棋子计分,不要break; - nPiecesInHandDiff = gameContext->nPiecesInHand_1 - gameContext->nPiecesInHand_2; + nPiecesInHandDiff = positionContext->nPiecesInHand_1 - positionContext->nPiecesInHand_2; value += nPiecesInHandDiff * 50; #ifdef DEBUG_AB_TREE node->nPiecesInHandDiff = nPiecesInHandDiff; #endif // 按场上棋子计分 - nPiecesOnBoardDiff = gameContext->nPiecesOnBoard_1 - gameContext->nPiecesOnBoard_2; + nPiecesOnBoardDiff = positionContext->nPiecesOnBoard_1 - positionContext->nPiecesOnBoard_2; value += nPiecesOnBoardDiff * 100; #ifdef DEBUG_AB_TREE node->nPiecesOnBoardDiff = nPiecesOnBoardDiff; #endif - switch (gameContext->action) { + switch (positionContext->action) { // 选子和落子使用相同的评价方法 case ACTION_CHOOSE: case ACTION_PLACE: @@ -63,8 +63,8 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG // 如果形成去子状态,每有一个可去的子,算100分 case ACTION_CAPTURE: - nPiecesNeedRemove = (gameContext->turn == PLAYER1) ? - gameContext->nPiecesNeedRemove : -(gameContext->nPiecesNeedRemove); + nPiecesNeedRemove = (positionContext->turn == PLAYER1) ? + positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove); value += nPiecesNeedRemove * 100; #ifdef DEBUG_AB_TREE node->nPiecesNeedRemove = nPiecesNeedRemove; @@ -78,14 +78,14 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG case GAME_MOVING: // 按场上棋子计分 - value += gameContext->nPiecesOnBoard_1 * 100 - gameContext->nPiecesOnBoard_2 * 100; + value += positionContext->nPiecesOnBoard_1 * 100 - positionContext->nPiecesOnBoard_2 * 100; #ifdef EVALUATE_MOBILITY // 按棋子活动能力计分 - value += gameTemp.getMobilityDiff(gameContext->turn, gameTemp.currentRule, gameContext->nPiecesInHand_1, gameContext->nPiecesInHand_2, false) * 10; + value += dummyPosition.getMobilityDiff(positionContext->turn, dummyPosition.currentRule, positionContext->nPiecesInHand_1, positionContext->nPiecesInHand_2, false) * 10; #endif /* EVALUATE_MOBILITY */ - switch (gameContext->action) { + switch (positionContext->action) { // 选子和落子使用相同的评价方法 case ACTION_CHOOSE: case ACTION_PLACE: @@ -93,8 +93,8 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG // 如果形成去子状态,每有一个可去的子,算128分 case ACTION_CAPTURE: - nPiecesNeedRemove = (gameContext->turn == PLAYER1) ? - gameContext->nPiecesNeedRemove : -(gameContext->nPiecesNeedRemove); + nPiecesNeedRemove = (positionContext->turn == PLAYER1) ? + positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove); value += nPiecesNeedRemove * 128; #ifdef DEBUG_AB_TREE node->nPiecesNeedRemove = nPiecesNeedRemove; @@ -109,9 +109,9 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG // 终局评价最简单 case GAME_OVER: // 布局阶段闷棋判断 - if (gameContext->nPiecesOnBoard_1 + gameContext->nPiecesOnBoard_2 >= + if (positionContext->nPiecesOnBoard_1 + positionContext->nPiecesOnBoard_2 >= Board::N_SEATS * Board::N_RINGS) { - if (gameTemp.getRule()->isStartingPlayerLoseWhenBoardFull) { + if (dummyPosition.getRule()->isStartingPlayerLoseWhenBoardFull) { // winner = PLAYER2; value -= 10000; #ifdef DEBUG_AB_TREE @@ -123,11 +123,11 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG } // 走棋阶段被闷判断 - if (gameContext->action == ACTION_CHOOSE && - gameTemp.context.board.isAllSurrounded(gameContext->turn, gameTemp.currentRule, gameContext->nPiecesOnBoard_1, gameContext->nPiecesOnBoard_2, gameContext->turn) && - gameTemp.getRule()->isLoseWhenNoWay) { + if (positionContext->action == ACTION_CHOOSE && + dummyPosition.context.board.isAllSurrounded(positionContext->turn, dummyPosition.currentRule, positionContext->nPiecesOnBoard_1, positionContext->nPiecesOnBoard_2, positionContext->turn) && + dummyPosition.getRule()->isLoseWhenNoWay) { // 规则要求被“闷”判负,则对手获胜 - if (gameContext->turn == PLAYER1) { + if (positionContext->turn == PLAYER1) { value -= 10000; #ifdef DEBUG_AB_TREE node->result = -2; @@ -141,12 +141,12 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG } // 剩余棋子个数判断 - if (gameContext->nPiecesOnBoard_1 < gameTemp.getRule()->nPiecesAtLeast) { + if (positionContext->nPiecesOnBoard_1 < dummyPosition.getRule()->nPiecesAtLeast) { value -= 10000; #ifdef DEBUG_AB_TREE node->result = -1; #endif - } else if (gameContext->nPiecesOnBoard_2 < gameTemp.getRule()->nPiecesAtLeast) { + } else if (positionContext->nPiecesOnBoard_2 < dummyPosition.getRule()->nPiecesAtLeast) { value += 10000; #ifdef DEBUG_AB_TREE node->result = 1; diff --git a/src/ai/evaluate.h b/src/ai/evaluate.h index eeb9a130..1cd8e5f1 100644 --- a/src/ai/evaluate.h +++ b/src/ai/evaluate.h @@ -34,7 +34,7 @@ public: Evaluation &operator=(const Evaluation &) = delete; - static value_t getValue(MillGame &gameTemp, GameContext *gameContext, MillGameAi_ab::Node *node); + static value_t getValue(Position &dummyPosition, PositionContext *positionContext, MillGameAi_ab::Node *node); // 评估子力 #ifdef EVALUATE_ENABLE diff --git a/src/ai/movegen.cpp b/src/ai/movegen.cpp index d1e7ead4..af4228e8 100644 --- a/src/ai/movegen.cpp +++ b/src/ai/movegen.cpp @@ -23,7 +23,7 @@ #include "movegen.h" -void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, +void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition, MillGameAi_ab::Node *node, MillGameAi_ab::Node *rootNode, move_t bestMove) { @@ -32,23 +32,23 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, size_t newCapacity = 24; // 留足余量空间避免多次重新分配,此动作本身也占用 CPU/内存 开销 - switch (gameTemp.getStage()) { + switch (dummyPosition.getStage()) { case GAME_PLACING: - if (gameTemp.getAction() == ACTION_CAPTURE) { - if (gameTemp.whosTurn() == PLAYER1) - newCapacity = static_cast(gameTemp.getPiecesOnBoardCount_2()); + if (dummyPosition.getAction() == ACTION_CAPTURE) { + if (dummyPosition.whosTurn() == PLAYER1) + newCapacity = static_cast(dummyPosition.getPiecesOnBoardCount_2()); else - newCapacity = static_cast(gameTemp.getPiecesOnBoardCount_1()); + newCapacity = static_cast(dummyPosition.getPiecesOnBoardCount_1()); } else { - newCapacity = static_cast(gameTemp.getPiecesInHandCount_1() + gameTemp.getPiecesInHandCount_2()); + newCapacity = static_cast(dummyPosition.getPiecesInHandCount_1() + dummyPosition.getPiecesInHandCount_2()); } break; case GAME_MOVING: - if (gameTemp.getAction() == ACTION_CAPTURE) { - if (gameTemp.whosTurn() == PLAYER1) - newCapacity = static_cast(gameTemp.getPiecesOnBoardCount_2()); + if (dummyPosition.getAction() == ACTION_CAPTURE) { + if (dummyPosition.whosTurn() == PLAYER1) + newCapacity = static_cast(dummyPosition.getPiecesOnBoardCount_2()); else - newCapacity = static_cast(gameTemp.getPiecesOnBoardCount_1()); + newCapacity = static_cast(dummyPosition.getPiecesOnBoardCount_1()); } else { newCapacity = 6; } @@ -69,28 +69,28 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, } // 对手 - Player opponent = MillGame::getOpponent(gameTemp.context.turn); + Player opponent = Position::getOpponent(dummyPosition.context.turn); // 列出所有合法的下一招 - switch (gameTemp.context.action) { + switch (dummyPosition.context.action) { // 对于选子和落子动作 case ACTION_CHOOSE: case ACTION_PLACE: // 对于摆子阶段 - if (gameTemp.context.stage & (GAME_PLACING | GAME_NOTSTARTED)) { + if (dummyPosition.context.stage & (GAME_PLACING | GAME_NOTSTARTED)) { for (int i : movePriorityTable) { location = i; - if (gameTemp.board_[location]) { + if (dummyPosition.board_[location]) { continue; } - if (gameTemp.context.stage != GAME_NOTSTARTED || node != rootNode) { - ai_ab.addNode(node, 0, location, bestMove, gameTemp.context.turn); + if (dummyPosition.context.stage != GAME_NOTSTARTED || node != rootNode) { + ai_ab.addNode(node, 0, location, bestMove, dummyPosition.context.turn); } else { // 若为先手,则抢占星位 - if (MillGame::isStarPoint(location)) { - ai_ab.addNode(node, MillGameAi_ab::INF_VALUE, location, bestMove, gameTemp.context.turn); + if (Position::isStarPoint(location)) { + ai_ab.addNode(node, MillGameAi_ab::INF_VALUE, location, bestMove, dummyPosition.context.turn); } } } @@ -98,36 +98,36 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, } // 对于移子阶段 - if (gameTemp.context.stage & GAME_MOVING) { + if (dummyPosition.context.stage & GAME_MOVING) { int newLocation, oldLocation; // 尽量走理论上较差的位置的棋子 for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) { oldLocation = movePriorityTable[i]; - if (!gameTemp.choose(oldLocation)) { + if (!dummyPosition.choose(oldLocation)) { continue; } - if ((gameTemp.context.turn == PLAYER1 && - (gameTemp.context.nPiecesOnBoard_1 > gameTemp.currentRule.nPiecesAtLeast || !gameTemp.currentRule.allowFlyWhenRemainThreePieces)) || - (gameTemp.context.turn == PLAYER2 && - (gameTemp.context.nPiecesOnBoard_2 > gameTemp.currentRule.nPiecesAtLeast || !gameTemp.currentRule.allowFlyWhenRemainThreePieces))) { + if ((dummyPosition.context.turn == PLAYER1 && + (dummyPosition.context.nPiecesOnBoard_1 > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces)) || + (dummyPosition.context.turn == PLAYER2 && + (dummyPosition.context.nPiecesOnBoard_2 > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces))) { // 对于棋盘上还有3个子以上,或不允许飞子的情况,要求必须在着法表中 for (int moveDirection = MOVE_DIRECTION_CLOCKWISE; moveDirection <= MOVE_DIRECTION_OUTWARD; moveDirection++) { // 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中 newLocation = moveTable[oldLocation][moveDirection]; - if (newLocation && !gameTemp.board_[newLocation]) { + if (newLocation && !dummyPosition.board_[newLocation]) { int move = (oldLocation << 8) + newLocation; - ai_ab.addNode(node, 0, move, bestMove, gameTemp.context.turn); // (12%) + ai_ab.addNode(node, 0, move, bestMove, dummyPosition.context.turn); // (12%) } } } else { // 对于棋盘上还有不到3个字,但允许飞子的情况,不要求在着法表中,是空位就行 for (newLocation = Board::LOCATION_BEGIN; newLocation < Board::LOCATION_END; newLocation++) { - if (!gameTemp.board_[newLocation]) { + if (!dummyPosition.board_[newLocation]) { int move = (oldLocation << 8) + newLocation; - ai_ab.addNode(node, 0, move, bestMove, gameTemp.context.turn); + ai_ab.addNode(node, 0, move, bestMove, dummyPosition.context.turn); } } } @@ -137,12 +137,12 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, // 对于吃子动作 case ACTION_CAPTURE: - if (gameTemp.context.board.isAllInMills(opponent)) { + if (dummyPosition.context.board.isAllInMills(opponent)) { // 全成三的情况 for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) { location = movePriorityTable[i]; - if (gameTemp.board_[location] & opponent) { - ai_ab.addNode(node, 0, -location, bestMove, gameTemp.context.turn); + if (dummyPosition.board_[location] & opponent) { + ai_ab.addNode(node, 0, -location, bestMove, dummyPosition.context.turn); } } break; @@ -151,9 +151,9 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, // 不是全成三的情况 for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) { location = movePriorityTable[i]; - if (gameTemp.board_[location] & opponent) { - if (gameTemp.getRule()->allowRemoveMill || !gameTemp.context.board.inHowManyMills(location)) { - ai_ab.addNode(node, 0, -location, bestMove, gameTemp.context.turn); + if (dummyPosition.board_[location] & opponent) { + if (dummyPosition.getRule()->allowRemoveMill || !dummyPosition.context.board.inHowManyMills(location)) { + ai_ab.addNode(node, 0, -location, bestMove, dummyPosition.context.turn); } } } @@ -164,7 +164,7 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, } } -void MoveList::createMoveTable(MillGame &game) +void MoveList::createMoveTable(Position &position) { #if 1 const int moveTable_obliqueLine[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = { @@ -356,7 +356,7 @@ void MoveList::createMoveTable(MillGame &game) }; #endif - if (game.currentRule.hasObliqueLines) { + if (position.currentRule.hasObliqueLines) { memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable)); } else { memcpy(moveTable, moveTable_noObliqueLine, sizeof(moveTable)); @@ -379,14 +379,14 @@ void MoveList::createMoveTable(MillGame &game) #endif } -void MoveList::shuffleMovePriorityTable(MillGame & game) +void MoveList::shuffleMovePriorityTable(Position &position) { array movePriorityTable0 = { 17, 19, 21, 23 }; // 中圈四个顶点 (星位) array movePriorityTable1 = { 25, 27, 29, 31, 9, 11, 13, 15 }; // 外圈和内圈四个顶点 array movePriorityTable2 = { 16, 18, 20, 22 }; // 中圈十字架 array movePriorityTable3 = { 24, 26, 28, 30, 8, 10, 12, 14 }; // 外内圈十字架 - if (game.getRandomMove() == true) { + if (position.getRandomMove() == true) { uint32_t seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed)); diff --git a/src/ai/movegen.h b/src/ai/movegen.h index 44210e24..d5277a68 100644 --- a/src/ai/movegen.h +++ b/src/ai/movegen.h @@ -34,15 +34,15 @@ public: MoveList &operator=(const MoveList &) = delete; // 生成所有合法的着法并建立子节点 - static void generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp, + static void generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition, MillGameAi_ab::Node *node, MillGameAi_ab::Node *rootNode, move_t bestMove); // 生成着法表 - static void createMoveTable(MillGame &game); + static void createMoveTable(Position &position); // 随机打乱着法搜索顺序 - static void shuffleMovePriorityTable(MillGame &game); + static void shuffleMovePriorityTable(Position &position); // 着法表 // TODO: Move to private inline static int moveTable[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = { {0} }; diff --git a/src/ai/search.cpp b/src/ai/search.cpp index 46163565..7063fffb 100644 --- a/src/ai/search.cpp +++ b/src/ai/search.cpp @@ -57,7 +57,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth) { depth_t newDepth = originalDepth; - if ((gameTemp.context.stage) & (GAME_PLACING)) { + if ((dummyPosition.context.stage) & (GAME_PLACING)) { #ifdef GAME_PLACING_DYNAMIC_DEPTH #ifdef DEAL_WITH_HORIZON_EFFECT #ifdef TRANSPOSITION_TABLE_ENABLE @@ -77,7 +77,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth) depth_t depthTable[] = { 2, 13, 13, 13, 12, 11, 10, 9, 9, 8, 8, 7, 1 }; #endif #endif // DEAL_WITH_HORIZON_EFFECT - newDepth = depthTable[gameTemp.getPiecesInHandCount_1()]; + newDepth = depthTable[dummyPosition.getPiecesInHandCount_1()]; #elif defined GAME_PLACING_FIXED_DEPTH newDepth = GAME_PLACING_FIXED_DEPTH; #endif // GAME_PLACING_DYNAMIC_DEPTH @@ -85,7 +85,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth) #ifdef GAME_MOVING_FIXED_DEPTH // 走棋阶段将深度调整 - if ((gameTemp.context.stage) & (GAME_MOVING)) { + if ((dummyPosition.context.stage) & (GAME_MOVING)) { newDepth = GAME_MOVING_FIXED_DEPTH; } #endif /* GAME_MOVING_FIXED_DEPTH */ @@ -141,8 +141,8 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode( #ifdef DEBUG_AB_TREE newNode->root = rootNode; - newNode->stage = gameTemp.context.stage; - newNode->action = gameTemp.context.action; + newNode->stage = dummyPosition.context.stage; + newNode->action = dummyPosition.context.action; newNode->evaluated = false; newNode->nPiecesInHandDiff = INT_MAX; newNode->nPiecesOnBoardDiff = INT_MAX; @@ -156,15 +156,15 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode( char cmd[32] = { 0 }; if (move < 0) { - gameTemp.context.board.locationToPolar(-move, r, s); + dummyPosition.context.board.locationToPolar(-move, r, s); sprintf(cmd, "-(%1u,%1u)", r, s); } else if (move & 0x7f00) { int r1, s1; - gameTemp.context.board.locationToPolar(move >> 8, r1, s1); - gameTemp.context.board.locationToPolar(move & 0x00ff, r, s); + dummyPosition.context.board.locationToPolar(move >> 8, r1, s1); + dummyPosition.context.board.locationToPolar(move & 0x00ff, r, s); sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s); } else { - gameTemp.context.board.locationToPolar(move & 0x007f, r, s); + dummyPosition.context.board.locationToPolar(move & 0x007f, r, s); sprintf(cmd, "(%1u,%1u)", r, s); } @@ -176,7 +176,7 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode( if (bestMove == 0 || move != bestMove) { #ifdef MILL_FIRST // 优先成三 - if (gameTemp.getStage() == GAME_PLACING && move > 0 && gameTemp.context.board.isInMills(move, true)) { + if (dummyPosition.getStage() == GAME_PLACING && move > 0 && dummyPosition.context.board.isInMills(move, true)) { parent->children.insert(parent->children.begin(), newNode); } else { parent->children.push_back(newNode); @@ -233,7 +233,7 @@ void MillGameAi_ab::sortLegalMoves(Node *node) { // 这个函数对效率的影响很大,排序好的话,剪枝较早,节省时间,但不能在此函数耗费太多时间 - if (gameTemp.whosTurn() == PLAYER1) { + if (dummyPosition.whosTurn() == PLAYER1) { std::stable_sort(node->children.begin(), node->children.end(), nodeGreater); } else { std::stable_sort(node->children.begin(), node->children.end(), nodeLess); @@ -260,10 +260,10 @@ void MillGameAi_ab::deleteTree(Node *node) #endif } -void MillGameAi_ab::setGame(const MillGame &game) +void MillGameAi_ab::setPosition(const Position &position) { // 如果规则改变,重建hashmap - if (strcmp(this->game_.currentRule.name, game.currentRule.name) != 0) { + if (strcmp(this->position_.currentRule.name, position.currentRule.name) != 0) { #ifdef TRANSPOSITION_TABLE_ENABLE TranspositionTable::clearTranspositionTable(); #endif // TRANSPOSITION_TABLE_ENABLE @@ -277,9 +277,9 @@ void MillGameAi_ab::setGame(const MillGame &game) positions.clear(); } - this->game_ = game; - gameTemp = game; - gameContext = &(gameTemp.context); + this->position_ = position; + dummyPosition = position; + positionContext = &(dummyPosition.context); requiredQuit = false; deleteTree(rootNode); #ifdef MEMORY_POOL @@ -313,11 +313,11 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth) chrono::steady_clock::time_point timeEnd; #ifdef BOOK_LEARNING - if (game_.getStage() == GAME_PLACING) + if (position_.getStage() == GAME_PLACING) { - if (game_.context.nPiecesInHand_1 <= 10) { + if (position_.context.nPiecesInHand_1 <= 10) { // 开局库只记录摆棋阶段最后的局面 - openingBook.push_back(game_.getHash()); + openingBook.push_back(position_.getHash()); } else { // 暂时在此处清空开局库 openingBook.clear(); @@ -328,8 +328,8 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth) #ifdef THREEFOLD_REPETITION static int nRepetition = 0; - if (game_.getStage() == GAME_MOVING) { - hash_t hash = game_.getHash(); + if (position_.getStage() == GAME_MOVING) { + hash_t hash = position_.getHash(); if (std::find(positions.begin(), positions.end(), hash) != positions.end()) { nRepetition++; @@ -342,13 +342,13 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth) } } - if (game_.getStage() == GAME_PLACING) { + if (position_.getStage() == GAME_PLACING) { positions.clear(); } #endif // THREEFOLD_REPETITION // 随机打乱着法顺序 - MoveList::shuffleMovePriorityTable(game_); + MoveList::shuffleMovePriorityTable(position_); #ifdef IDS_SUPPORT // 深化迭代 @@ -404,7 +404,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be enum TranspositionTable::HashType hashf = TranspositionTable::hashfALPHA; // 获取哈希值 - hash_t hash = gameTemp.getHash(); + hash_t hash = dummyPosition.getHash(); #ifdef DEBUG_AB_TREE node->hash = hash; #endif @@ -432,7 +432,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be #if 0 // TODO: 有必要针对深度微调 value? - if (gameContext->turn == PLAYER1) + if (positionContext->turn == PLAYER1) node->value += hashValue.depth - depth; else node->value -= hashValue.depth - depth; @@ -447,7 +447,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be #ifdef DEBUG_AB_TREE node->depth = depth; node->root = rootNode; - // node->player = gameContext->turn; + // node->player = positionContext->turn; // 初始化 node->isLeaf = false; node->isTimeout = false; @@ -459,9 +459,9 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be #endif // DEBUG_AB_TREE // 搜索到叶子节点(决胜局面) // TODO: 对哈希进行特殊处理 - if (gameContext->stage == GAME_OVER) { + if (positionContext->stage == GAME_OVER) { // 局面评估 - node->value = Evaluation::getValue(gameTemp, gameContext, node); + node->value = Evaluation::getValue(dummyPosition, positionContext, node); evaluatedNodeCount++; // 为争取速胜,value 值 +- 深度 @@ -486,11 +486,11 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be // 搜索到第0层或需要退出 if (!depth || requiredQuit) { // 局面评估 - node->value = Evaluation::getValue(gameTemp, gameContext, node); + node->value = Evaluation::getValue(dummyPosition, positionContext, node); evaluatedNodeCount++; // 为争取速胜,value 值 +- 深度 (有必要?) - if (gameContext->turn == PLAYER1) { + if (positionContext->turn == PLAYER1) { node->value += depth; } else { node->value -= depth; @@ -504,8 +504,8 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be #ifdef BOOK_LEARNING // 检索开局库 - if (gameContext->stage == GAME_PLACING && findBookHash(hash, hashValue)) { - if (gameContext->turn == PLAYER2) { + if (positionContext->stage == GAME_PLACING && findBookHash(hash, hashValue)) { + if (positionContext->turn == PLAYER2) { // 是否需对后手扣分 // TODO: 先后手都处理 node->value += 1; } @@ -521,18 +521,18 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be } // 生成子节点树,即生成每个合理的着法 - MoveList::generateLegalMoves(*this, gameTemp, node, rootNode, bestMove); + MoveList::generateLegalMoves(*this, dummyPosition, node, rootNode, bestMove); // 根据演算模型执行 MiniMax 检索,对先手,搜索 Max, 对后手,搜索 Min - minMax = gameTemp.whosTurn() == PLAYER1 ? -INF_VALUE : INF_VALUE; + minMax = dummyPosition.whosTurn() == PLAYER1 ? -INF_VALUE : INF_VALUE; for (auto child : node->children) { // 上下文入栈保存,以便后续撤销着法 - contextStack.push(gameTemp.context); + contextStack.push(dummyPosition.context); // 执行着法 - gameTemp.command(child->move); + dummyPosition.command(child->move); #ifdef DEAL_WITH_HORIZON_EFFECT // 克服“水平线效应”: 若遇到吃子,则搜索深度增加 @@ -553,10 +553,10 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child); // 上下文弹出栈,撤销着法 - gameTemp.context = contextStack.top(); + dummyPosition.context = contextStack.top(); contextStack.pop(); - if (gameTemp.whosTurn() == PLAYER1) { + if (dummyPosition.whosTurn() == PLAYER1) { // 为走棋一方的层, 局面对走棋的一方来说是以 α 为评价 // 取最大值 @@ -686,10 +686,10 @@ const char* MillGameAi_ab::bestMove() // 检查是否必败 - if (game_.getGiveUpIfMostLose() == true) { + if (position_.getGiveUpIfMostLose() == true) { bool isMostLose = true; // 是否必败 - Player whosTurn = game_.whosTurn(); + Player whosTurn = position_.whosTurn(); for (auto child : rootNode->children) { // TODO: 使用常量代替 @@ -750,15 +750,15 @@ const char *MillGameAi_ab::move2string(move_t move) int r, s; if (move < 0) { - gameTemp.context.board.locationToPolar(-move, r, s); + dummyPosition.context.board.locationToPolar(-move, r, s); sprintf(cmdline, "-(%1u,%1u)", r, s); } else if (move & 0x7f00) { int r1, s1; - gameTemp.context.board.locationToPolar(move >> 8, r1, s1); - gameTemp.context.board.locationToPolar(move & 0x00ff, r, s); + dummyPosition.context.board.locationToPolar(move >> 8, r1, s1); + dummyPosition.context.board.locationToPolar(move & 0x00ff, r, s); sprintf(cmdline, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s); } else { - gameTemp.context.board.locationToPolar(move & 0x007f, r, s); + dummyPosition.context.board.locationToPolar(move & 0x007f, r, s); sprintf(cmdline, "(%1u,%1u)", r, s); } diff --git a/src/ai/search.h b/src/ai/search.h index 61058527..3428fa84 100644 --- a/src/ai/search.h +++ b/src/ai/search.h @@ -75,7 +75,7 @@ public: bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出 bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面 bool visited; // 是否在遍历时访问过 - GameStage stage; // 摆棋阶段还是走棋阶段 + PositionStage stage; // 摆棋阶段还是走棋阶段 Action action; // 动作状态 int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值 int nPiecesInHandDiff; // 手中的棋子个数和对手的差值 @@ -97,7 +97,7 @@ public: MillGameAi_ab(); ~MillGameAi_ab(); - void setGame(const MillGame &game); + void setPosition(const Position &position); void quit() { @@ -185,15 +185,15 @@ protected: private: // 原始模型 - MillGame game_; + Position position_; // 演算用的模型 - MillGame gameTemp; + Position dummyPosition; - GameContext *gameContext {}; + PositionContext *positionContext {}; // hash 计算时,各种转换用的模型 - MillGame gameTempShift; + Position dummyPositionShift; // 根节点 Node *rootNode {nullptr}; @@ -218,9 +218,9 @@ private: // 局面数据栈 //#ifdef MEMORY_POOL -// StackAlloc > contextStack; +// StackAlloc > contextStack; //#else - stack contextStack; + stack contextStack; //#endif // 标识,用于跳出剪枝算法,立即返回 diff --git a/src/ai/tt.cpp b/src/ai/tt.cpp index f6163fd7..f4fe7485 100644 --- a/src/ai/tt.cpp +++ b/src/ai/tt.cpp @@ -50,17 +50,17 @@ bool TranspositionTable::findHash(hash_t hash, TranspositionTable::HashValue &ha return iter; // 变换局面,查找 hash (废弃) - gameTempShift = gameTemp; + dummyPositionShift = dummyPosition; for (int i = 0; i < 2; i++) { if (i) - gameTempShift.mirror(false); + dummyPositionShift.mirror(false); for (int j = 0; j < 2; j++) { if (j) - gameTempShift.turn(false); + dummyPositionShift.turn(false); for (int k = 0; k < 4; k++) { - gameTempShift.rotate(k * 90, false); - iter = hashmap.find(gameTempShift.getHash()); + dummyPositionShift.rotate(k * 90, false); + iter = hashmap.find(dummyPositionShift.getHash()); if (iter != hashmap.end()) return iter; } diff --git a/src/base/thread.cpp b/src/base/thread.cpp index 8c16194f..e6ab8b43 100644 --- a/src/base/thread.cpp +++ b/src/base/thread.cpp @@ -26,7 +26,7 @@ AiThread::AiThread(int id, QObject *parent) : QThread(parent), waiting_(false), - game_(nullptr), + position_(nullptr), aiDepth(2), aiTime(3600) { @@ -60,12 +60,12 @@ AiThread::~AiThread() wait(); } -void AiThread::setAi(const MillGame &game) +void AiThread::setAi(const Position &position) { mutex.lock(); - this->game_ = &game; - ai_ab.setGame(*(this->game_)); + this->position_ = &position; + ai_ab.setPosition(*(this->position_)); #ifdef TRANSPOSITION_TABLE_ENABLE // 新下一盘前清除哈希表 (注意可能同时存在每步之前清除) @@ -77,11 +77,11 @@ void AiThread::setAi(const MillGame &game) mutex.unlock(); } -void AiThread::setAi(const MillGame &game, depth_t depth, int time) +void AiThread::setAi(const Position &position, depth_t depth, int time) { mutex.lock(); - this->game_ = &game; - ai_ab.setGame(game); + this->position_ = &position; + ai_ab.setPosition(position); aiDepth = depth; aiTime = time; mutex.unlock(); @@ -107,7 +107,7 @@ void AiThread::run() while (!isInterruptionRequested()) { mutex.lock(); - i = MillGame::playerToId(game_->whosTurn()); + i = Position::playerToId(position_->whosTurn()); if (i != id || waiting_) { pauseCondition.wait(&mutex); @@ -115,7 +115,7 @@ void AiThread::run() continue; } - ai_ab.setGame(*game_); + ai_ab.setPosition(*position_); emit calcStarted(); mutex.unlock(); diff --git a/src/base/thread.h b/src/base/thread.h index fcf8afd2..669b3a80 100644 --- a/src/base/thread.h +++ b/src/base/thread.h @@ -54,8 +54,8 @@ protected: public: // AI设置 - void setAi(const MillGame &game); - void setAi(const MillGame &game, depth_t depth, int time); + void setAi(const Position &position); + void setAi(const Position &position, depth_t depth, int time); Server *getServer() { @@ -107,7 +107,7 @@ private: QWaitCondition pauseCondition; // 主线程棋对象的引用 - const MillGame *game_; + const Position *position_; // Alpha-Beta剪枝算法类 MillGameAi_ab ai_ab; diff --git a/src/game/millgame.cpp b/src/game/millgame.cpp index b0c6f4cf..6c61a102 100644 --- a/src/game/millgame.cpp +++ b/src/game/millgame.cpp @@ -24,7 +24,7 @@ #include "search.h" #include "movegen.h" -MillGame::MillGame() +Position::Position() { // 单独提出 board 等数据,免得每次都写 context.board; board_ = context.board.locations; @@ -44,40 +44,40 @@ MillGame::MillGame() score_1 = score_2 = score_draw = 0; } -MillGame::~MillGame() = default; +Position::~Position() = default; -MillGame::MillGame(const MillGame &game) +Position::Position(const Position &position) { - *this = game; + *this = position; } -MillGame &MillGame::operator= (const MillGame &game) +Position &Position::operator= (const Position &position) { - if (this == &game) + if (this == &position) return *this; - currentRule = game.currentRule; - context = game.context; - currentStep = game.currentStep; - moveStep = game.moveStep; - randomMove_ = game.randomMove_; - giveUpIfMostLose_ = game.giveUpIfMostLose_; + currentRule = position.currentRule; + context = position.context; + currentStep = position.currentStep; + moveStep = position.moveStep; + randomMove_ = position.randomMove_; + giveUpIfMostLose_ = position.giveUpIfMostLose_; board_ = context.board.locations; - currentLocation = game.currentLocation; - winner = game.winner; - startTime = game.startTime; - currentTime = game.currentTime; - elapsedSeconds_1 = game.elapsedSeconds_1; - elapsedSeconds_2 = game.elapsedSeconds_2; - move_ = game.move_; - memcpy(cmdline, game.cmdline, sizeof(cmdline)); - cmdlist = game.cmdlist; - tips = game.tips; + currentLocation = position.currentLocation; + winner = position.winner; + startTime = position.startTime; + currentTime = position.currentTime; + elapsedSeconds_1 = position.elapsedSeconds_1; + elapsedSeconds_2 = position.elapsedSeconds_2; + move_ = position.move_; + memcpy(cmdline, position.cmdline, sizeof(cmdline)); + cmdlist = position.cmdlist; + tips = position.tips; return *this; } -int MillGame::playerToId(enum Player player) +int Position::playerToId(enum Player player) { if (player == PLAYER1) return 1; @@ -87,7 +87,7 @@ int MillGame::playerToId(enum Player player) return 0; } -Player MillGame::getOpponent(Player player) +Player Position::getOpponent(Player player) { switch (player) { @@ -103,7 +103,7 @@ Player MillGame::getOpponent(Player player) } // 设置配置 -bool MillGame::configure(bool giveUpIfMostLose, bool randomMove) +bool Position::configure(bool giveUpIfMostLose, bool randomMove) { // 设置是否必败时认输 this->giveUpIfMostLose_ = giveUpIfMostLose; @@ -115,7 +115,7 @@ bool MillGame::configure(bool giveUpIfMostLose, bool randomMove) } // 设置棋局状态和棋盘数据,用于初始化 -bool MillGame::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int maxTimeLedToLose, +bool Position::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int maxTimeLedToLose, step_t initialStep, int flags, const char *board, int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove) { @@ -266,7 +266,7 @@ bool MillGame::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int return false; } -void MillGame::getContext(struct Rule &rule, step_t &step, int &flags, +void Position::getContext(struct Rule &rule, step_t &step, int &flags, int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &nPiecesNeedRemove) { rule = this->currentRule; @@ -278,7 +278,7 @@ void MillGame::getContext(struct Rule &rule, step_t &step, int &flags, nPiecesNeedRemove = context.nPiecesNeedRemove; } -bool MillGame::reset() +bool Position::reset() { if (context.stage == GAME_NOTSTARTED && elapsedSeconds_1 == elapsedSeconds_2 == 0) { @@ -351,7 +351,7 @@ bool MillGame::reset() return false; } -bool MillGame::start() +bool Position::start() { switch (context.stage) { // 如果游戏已经开始,则返回false @@ -374,7 +374,7 @@ bool MillGame::start() } } -bool MillGame::place(int location, int time_p, int8_t rs) +bool Position::place(int location, int time_p, int8_t rs) { // 如果局面为“结局”,返回false if (context.stage == GAME_OVER) @@ -556,7 +556,7 @@ out: return true; } -bool MillGame::_place(int r, int s, int time_p) +bool Position::_place(int r, int s, int time_p) { // 转换为 location int location = context.board.polarToLocation(r, s); @@ -564,7 +564,7 @@ bool MillGame::_place(int r, int s, int time_p) return place(location, time_p, true); } -bool MillGame::_capture(int r, int s, int time_p) +bool Position::_capture(int r, int s, int time_p) { // 转换为 location int location = context.board.polarToLocation(r, s); @@ -572,7 +572,7 @@ bool MillGame::_capture(int r, int s, int time_p) return capture(location, time_p, 1); } -bool MillGame::capture(int location, int time_p, int8_t cp) +bool Position::capture(int location, int time_p, int8_t cp) { // 如果局面为"未开局"或“结局”,返回false if (context.stage == GAME_NOTSTARTED || context.stage == GAME_OVER) @@ -714,7 +714,7 @@ out: return true; } -bool MillGame::choose(int location) +bool Position::choose(int location) { // 如果局面不是"中局”,返回false if (context.stage != GAME_MOVING) @@ -745,12 +745,12 @@ bool MillGame::choose(int location) return false; } -bool MillGame::choose(int r, int s) +bool Position::choose(int r, int s) { return choose(context.board.polarToLocation(r, s)); } -bool MillGame::giveup(Player loser) +bool Position::giveup(Player loser) { if (context.stage == GAME_NOTSTARTED || context.stage == GAME_OVER || @@ -778,7 +778,7 @@ bool MillGame::giveup(Player loser) } // 打算用个C++的命令行解析库的,简单的没必要,但中文编码有极小概率出问题 -bool MillGame::command(const char *cmd) +bool Position::command(const char *cmd) { int r, t; step_t s; @@ -863,7 +863,7 @@ bool MillGame::command(const char *cmd) return false; } -bool MillGame::command(int move) +bool Position::command(int move) { if (move < 0) { return capture(-move); @@ -880,7 +880,7 @@ bool MillGame::command(int move) return false; } -inline int MillGame::update(int time_p /*= -1*/) +inline int Position::update(int time_p /*= -1*/) { int ret = -1; time_t *player_ms = (context.turn == PLAYER1 ? &elapsedSeconds_1 : &elapsedSeconds_2); @@ -911,13 +911,13 @@ inline int MillGame::update(int time_p /*= -1*/) } // 是否分出胜负 -bool MillGame::win() +bool Position::win() { return win(false); } // 是否分出胜负 -bool MillGame::win(bool forceDraw) +bool Position::win(bool forceDraw) { if (context.stage == GAME_OVER) { return true; @@ -1043,7 +1043,7 @@ bool MillGame::win(bool forceDraw) } // 计算玩家1和玩家2的棋子活动能力之差 -int MillGame::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnBoard_1, int nPiecesOnBoard_2, bool includeFobidden) +int Position::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnBoard_1, int nPiecesOnBoard_2, bool includeFobidden) { int *board = context.board.locations; int mobility1 = 0; @@ -1066,7 +1066,7 @@ int MillGame::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnB return diff; } -void MillGame::cleanForbiddenPoints() +void Position::cleanForbiddenPoints() { int location = 0; @@ -1082,7 +1082,7 @@ void MillGame::cleanForbiddenPoints() } } -enum Player MillGame::changeTurn() +enum Player Position::changeTurn() { // 设置轮到谁走 context.turn = (context.turn == PLAYER1) ? PLAYER2 : PLAYER1; @@ -1090,7 +1090,7 @@ enum Player MillGame::changeTurn() return context.turn; } -void MillGame::setTips() +void Position::setTips() { switch (context.stage) { case GAME_NOTSTARTED: @@ -1156,7 +1156,7 @@ void MillGame::setTips() } } -void MillGame::getElapsedTime(time_t &p1_ms, time_t &p2_ms) +void Position::getElapsedTime(time_t &p1_ms, time_t &p2_ms) { update(); @@ -1174,7 +1174,7 @@ void MillGame::getElapsedTime(time_t &p1_ms, time_t &p2_ms) * 0位:轮流标识,0为先手,1为后手 */ -void MillGame::constructHash() +void Position::constructHash() { context.hash = 0; @@ -1182,7 +1182,7 @@ void MillGame::constructHash() memcpy(context.zobrist, zobrist0, sizeof(hash_t) * Board::N_LOCATIONS * POINT_TYPE_COUNT); } -hash_t MillGame::getHash() +hash_t Position::getHash() { // TODO: 每次获取哈希值时更新 hash 值低8位,放在此处调用不优雅 updateHashMisc(); @@ -1190,7 +1190,7 @@ hash_t MillGame::getHash() return context.hash; } -hash_t MillGame::updateHash(int location) +hash_t Position::updateHash(int location) { // PieceType is board_[location] @@ -1203,12 +1203,12 @@ hash_t MillGame::updateHash(int location) return context.hash; } -hash_t MillGame::revertHash(int location) +hash_t Position::revertHash(int location) { return updateHash(location); } -hash_t MillGame::updateHashMisc() +hash_t Position::updateHashMisc() { // 清除标记位 context.hash &= static_cast(~0xFF); @@ -1224,7 +1224,7 @@ hash_t MillGame::updateHashMisc() } context.hash |= static_cast(context.nPiecesNeedRemove) << 2; - context.hash |= static_cast(context.nPiecesInHand_1) << 4; // TODO: 或许换 game.stage 也可以? + context.hash |= static_cast(context.nPiecesInHand_1) << 4; // TODO: 或许换 position.stage 也可以? return context.hash; } diff --git a/src/game/millgame.h b/src/game/millgame.h index f4e74d9b..7c38606f 100644 --- a/src/game/millgame.h +++ b/src/game/millgame.h @@ -19,8 +19,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#ifndef MILLGAME_H -#define MILLGAME_H +#ifndef POSITION_H +#define POSITION_H #include #include @@ -36,7 +36,7 @@ using namespace std; // 棋局结构体,算法相关,包含当前棋盘数据 // 单独分离出来供AI判断局面用,生成置换表时使用 -class GameContext +class PositionContext { public: Board board; @@ -48,7 +48,7 @@ public: hash_t zobrist[Board::N_LOCATIONS][POINT_TYPE_COUNT]{}; // 局面阶段标识 - enum GameStage stage; + enum PositionStage stage; // 轮流状态标识 enum Player turn; @@ -75,9 +75,9 @@ public: }; // 棋类(在数据模型内,玩家只分先后手,不分黑白) -// 注意:MillGame类不是线程安全的! -// 所以不能跨线程修改MillGame类的静态成员变量,切记! -class MillGame +// 注意:Position 类不是线程安全的! +// 所以不能跨线程修改 Position 类的静态成员变量,切记! +class Position { // AI友元类 friend class MillGameAi_ab; @@ -111,14 +111,14 @@ private: void constructHash(); public: - explicit MillGame(); - virtual ~MillGame(); + explicit Position(); + virtual ~Position(); // 拷贝构造函数 - explicit MillGame(const MillGame &); + explicit Position(const Position &); // 运算符重载 - MillGame &operator=(const MillGame &); + Position &operator=(const Position &); // 设置配置 bool configure(bool giveUpIfMostLose, bool randomMove); @@ -188,7 +188,7 @@ public: } // 获取局面阶段标识 - enum GameStage getStage() const + enum PositionStage getStage() const { return context.stage; } @@ -328,7 +328,7 @@ public: public: /* TODO: move to private */ // 棋局上下文 - GameContext context; + PositionContext context; // 当前使用的规则 struct Rule currentRule @@ -404,4 +404,4 @@ private: string tips; }; -#endif /* MILLGAME_H */ +#endif /* POSITION_H */ diff --git a/src/game/types.h b/src/game/types.h index 25befed2..53bd4ee3 100644 --- a/src/game/types.h +++ b/src/game/types.h @@ -66,7 +66,7 @@ enum Player : uint8_t }; // 局面阶段标识 -enum GameStage : uint16_t +enum PositionStage : uint16_t { GAME_NONE = 0x0000, GAME_NOTSTARTED = 0x0001, // 未开局 diff --git a/src/ui/qt/gamecontroller.cpp b/src/ui/qt/gamecontroller.cpp index fe360c07..4513d56e 100644 --- a/src/ui/qt/gamecontroller.cpp +++ b/src/ui/qt/gamecontroller.cpp @@ -117,9 +117,9 @@ const QMap GameController::getActions() void GameController::gameStart() { - game_.configure(giveUpIfMostLose_, randomMove_); - game_.start(); - gameTemp = game_; + position_.configure(giveUpIfMostLose_, randomMove_); + position_.start(); + dummyPosition = position_; // 每隔100毫秒调用一次定时器处理函数 if (timeID == 0) { @@ -137,15 +137,15 @@ void GameController::gameReset() timeID = 0; // 棋未下完,则算对手得分 - if (game_.getStage() == GAME_MOVING && - game_.whoWin() == PLAYER_NOBODY) { + if (position_.getStage() == GAME_MOVING && + position_.whoWin() == PLAYER_NOBODY) { giveUp(); } // 重置游戏 - game_.configure(giveUpIfMostLose_, randomMove_); - game_.reset(); - gameTemp = game_; + position_.configure(giveUpIfMostLose_, randomMove_); + position_.reset(); + dummyPosition = position_; // 停掉线程 if (!isAutoRestart) { @@ -161,7 +161,7 @@ void GameController::gameReset() currentPiece = nullptr; // 重新绘制棋盘 - scene.setDiagonal(game_.getRule()->hasObliqueLines); + scene.setDiagonal(position_.getRule()->hasObliqueLines); // 绘制所有棋子,放在起始位置 // 0: 先手第1子; 1:后手第1子 @@ -170,7 +170,7 @@ void GameController::gameReset() PieceItem::Models md; PieceItem *newP; - for (int i = 0; i < game_.getRule()->nTotalPiecesEachSide; i++) { + for (int i = 0; i < position_.getRule()->nTotalPiecesEachSide; i++) { // 先手的棋子 md = isInverted ? PieceItem::whitePiece : PieceItem::blackPiece; newP = new PieceItem; @@ -179,7 +179,7 @@ void GameController::gameReset() newP->setNum(i + 1); // 如果重复三连不可用,则显示棋子序号,九连棋专用玩法 - if (!(game_.getRule()->allowRemovePiecesRepeatedly)) + if (!(position_.getRule()->allowRemovePiecesRepeatedly)) newP->setShowNum(true); pieceList.append(newP); @@ -193,7 +193,7 @@ void GameController::gameReset() newP->setNum(i + 1); // 如果重复三连不可用,则显示棋子序号,九连棋专用玩法 - if (!(game_.getRule()->allowRemovePiecesRepeatedly)) + if (!(position_.getRule()->allowRemovePiecesRepeatedly)) newP->setShowNum(true); pieceList.append(newP); @@ -201,7 +201,7 @@ void GameController::gameReset() } // 读取规则限时要求 - timeLimit = game_.getRule()->maxTimeLedToLose; + timeLimit = position_.getRule()->maxTimeLedToLose; // 如果规则不要求计时,则time1和time2表示已用时间 if (timeLimit <= 0) { @@ -215,7 +215,7 @@ void GameController::gameReset() // 更新棋谱 manualListModel.removeRows(0, manualListModel.rowCount()); manualListModel.insertRow(0); - manualListModel.setData(manualListModel.index(0), game_.getCmdLine()); + manualListModel.setData(manualListModel.index(0), position_.getCmdLine()); currentRow = 0; // 发出信号通知主窗口更新LCD显示 @@ -224,13 +224,13 @@ void GameController::gameReset() emit time2Changed(qtime.toString("hh:mm:ss")); // 发信号更新状态栏 - message = QString::fromStdString(game_.getTips()); + message = QString::fromStdString(position_.getTips()); emit statusBarChanged(message); // 更新比分 LCD 显示 - emit score1Changed(QString::number(game_.score_1, 10)); - emit score2Changed(QString::number(game_.score_2, 10)); - emit scoreDrawChanged(QString::number(game_.score_draw, 10)); + emit score1Changed(QString::number(position_.score_1, 10)); + emit score2Changed(QString::number(position_.score_2, 10)); + emit scoreDrawChanged(QString::number(position_.score_draw, 10)); // 播放音效 //playSound(":/sound/resources/sound/newgame.wav"); @@ -275,8 +275,8 @@ void GameController::setRule(int ruleNo, step_t stepLimited /*= -1*/, int timeLi } // 设置模型规则,重置游戏 - game_.setContext(&RULES[ruleNo], stepsLimit, timeLimit); - gameTemp = game_; + position_.setContext(&RULES[ruleNo], stepsLimit, timeLimit); + dummyPosition = position_; // 重置游戏 gameReset(); @@ -284,11 +284,11 @@ void GameController::setRule(int ruleNo, step_t stepLimited /*= -1*/, int timeLi void GameController::setEngine1(bool arg) { - game_.configure(giveUpIfMostLose_, randomMove_); + position_.configure(giveUpIfMostLose_, randomMove_); isAiPlayer1 = arg; if (arg) { - ai1.setAi(game_); + ai1.setAi(position_); if (ai1.isRunning()) ai1.resume(); else @@ -300,11 +300,11 @@ void GameController::setEngine1(bool arg) void GameController::setEngine2(bool arg) { - game_.configure(giveUpIfMostLose_, randomMove_); + position_.configure(giveUpIfMostLose_, randomMove_); isAiPlayer2 = arg; if (arg) { - ai2.setAi(game_); + ai2.setAi(position_); if (ai2.isRunning()) ai2.resume(); else @@ -325,8 +325,8 @@ void GameController::setAiDepthTime(depth_t depth1, int time1, depth_t depth2, i ai2.wait(); } - ai1.setAi(game_, depth1, time1); - ai2.setAi(game_, depth2, time2); + ai1.setAi(position_, depth1, time1); + ai2.setAi(position_, depth2, time2); if (isAiPlayer1) { ai1.start(); @@ -398,13 +398,13 @@ void GameController::flip() ai2.wait(); } - game_.context.board.mirror(game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); - game_.context.board.rotate(180, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); - gameTemp = game_; + position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation); + position_.context.board.rotate(180, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation); + dummyPosition = position_; // 更新棋谱 int row = 0; - for (const auto &str : *(game_.getCmdList())) { + for (const auto &str : *(position_.getCmdList())) { manualListModel.setData(manualListModel.index(row++), str.c_str()); } @@ -414,8 +414,8 @@ void GameController::flip() else stageChange(currentRow, true); - ai1.setAi(game_); - ai2.setAi(game_); + ai1.setAi(position_); + ai2.setAi(position_); if (isAiPlayer1) { ai1.start(); @@ -438,13 +438,13 @@ void GameController::mirror() ai2.wait(); } - game_.context.board.mirror(game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); - gameTemp = game_; + position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation); + dummyPosition = position_; // 更新棋谱 int row = 0; - for (const auto &str : *(game_.getCmdList())) { + for (const auto &str : *(position_.getCmdList())) { manualListModel.setData(manualListModel.index(row++), str.c_str()); } @@ -456,8 +456,8 @@ void GameController::mirror() else stageChange(currentRow, true); - ai1.setAi(game_); - ai2.setAi(game_); + ai1.setAi(position_); + ai2.setAi(position_); if (isAiPlayer1) { ai1.start(); @@ -480,13 +480,13 @@ void GameController::turnRight() ai2.wait(); } - game_.context.board.rotate(-90, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); - gameTemp = game_; + position_.context.board.rotate(-90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation); + dummyPosition = position_; // 更新棋谱 int row = 0; - for (const auto &str : *(game_.getCmdList())) { + for (const auto &str : *(position_.getCmdList())) { manualListModel.setData(manualListModel.index(row++), str.c_str()); } @@ -496,8 +496,8 @@ void GameController::turnRight() else stageChange(currentRow, true); - ai1.setAi(game_); - ai2.setAi(game_); + ai1.setAi(position_); + ai2.setAi(position_); if (isAiPlayer1) { ai1.start(); @@ -520,20 +520,20 @@ void GameController::turnLeft() ai2.wait(); } - game_.context.board.rotate(90, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); - gameTemp = game_; + position_.context.board.rotate(90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation); + dummyPosition = position_; // 更新棋谱 int row = 0; - for (const auto &str : *(game_.getCmdList())) { + for (const auto &str : *(position_.getCmdList())) { manualListModel.setData(manualListModel.index(row++), str.c_str()); } // 刷新显示 updateScence(); - ai1.setAi(game_); - ai2.setAi(game_); + ai1.setAi(position_); + ai2.setAi(position_); if (isAiPlayer1) { ai1.start(); } @@ -548,7 +548,7 @@ void GameController::timerEvent(QTimerEvent *event) static QTime qt1, qt2; // 玩家的已用时间 - game_.getElapsedTime(remainingTime1, remainingTime2); + position_.getElapsedTime(remainingTime1, remainingTime2); // 如果规则要求计时,则time1和time2表示倒计时 if (timeLimit > 0) { @@ -564,7 +564,7 @@ void GameController::timerEvent(QTimerEvent *event) emit time2Changed(qt2.toString("hh:mm:ss")); // 如果胜负已分 - if (game_.whoWin() != PLAYER_NOBODY) { + if (position_.whoWin() != PLAYER_NOBODY) { // 停止计时 killTimer(timeID); @@ -572,7 +572,7 @@ void GameController::timerEvent(QTimerEvent *event) timeID = 0; // 发信号更新状态栏 - message = QString::fromStdString(game_.getTips()); + message = QString::fromStdString(position_.getTips()); emit statusBarChanged(message); // 弹框 @@ -609,8 +609,8 @@ void GameController::timerEvent(QTimerEvent *event) bool GameController::isAIsTurn() { - return ((game_.whosTurn() == PLAYER1 && isAiPlayer1) || - (game_.whosTurn() == PLAYER2 && isAiPlayer2)); + return ((position_.whosTurn() == PLAYER1 && isAiPlayer1) || + (position_.whosTurn() == PLAYER2 && isAiPlayer2)); } // 关键槽函数,根据QGraphicsScene的信号和状态来执行选子、落子或去子 @@ -643,17 +643,17 @@ bool GameController::actionPiece(QPointF pos) if (QMessageBox::Ok == msgBox.exec()) { #endif /* !MOBILE_APP_UI */ - game_ = gameTemp; + position_ = dummyPosition; manualListModel.removeRows(currentRow + 1, manualListModel.rowCount() - currentRow - 1); // 如果再决出胜负后悔棋,则重新启动计时 - if (game_.whoWin() == PLAYER_NOBODY) { + if (position_.whoWin() == PLAYER_NOBODY) { // 重新启动计时 timeID = startTimer(100); // 发信号更新状态栏 - message = QString::fromStdString(game_.getTips()); + message = QString::fromStdString(position_.getTips()); emit statusBarChanged(message); #ifndef MOBILE_APP_UI } @@ -664,7 +664,7 @@ bool GameController::actionPiece(QPointF pos) } // 如果未开局则开局 - if (game_.getStage() == GAME_NOTSTARTED) + if (position_.getStage() == GAME_NOTSTARTED) gameStart(); // 判断执行选子、落子或去子 @@ -672,10 +672,10 @@ bool GameController::actionPiece(QPointF pos) PieceItem *piece = nullptr; QGraphicsItem *item = scene.itemAt(pos, QTransform()); - switch (game_.getAction()) { + switch (position_.getAction()) { case ACTION_PLACE: - if (game_._place(r, s)) { - if (game_.getAction() == ACTION_CAPTURE) { + if (position_._place(r, s)) { + if (position_.getAction() == ACTION_CAPTURE) { // 播放成三音效 playSound(":/sound/resources/sound/capture.wav"); } else { @@ -693,7 +693,7 @@ bool GameController::actionPiece(QPointF pos) piece = qgraphicsitem_cast(item); if (!piece) break; - if (game_.choose(r, s)) { + if (position_.choose(r, s)) { // 播放选子音效 playSound(":/sound/resources/sound/choose.wav"); result = true; @@ -704,7 +704,7 @@ bool GameController::actionPiece(QPointF pos) break; case ACTION_CAPTURE: - if (game_._capture(r, s)) { + if (position_._capture(r, s)) { // 播放音效 playSound(":/sound/resources/sound/remove.wav"); result = true; @@ -721,7 +721,7 @@ bool GameController::actionPiece(QPointF pos) if (result) { // 发信号更新状态栏 - message = QString::fromStdString(game_.getTips()); + message = QString::fromStdString(position_.getTips()); emit statusBarChanged(message); // 将新增的棋谱行插入到ListModel @@ -729,7 +729,7 @@ bool GameController::actionPiece(QPointF pos) int k = 0; // 输出命令行 - for (const auto & i : *(game_.getCmdList())) { + for (const auto & i : *(position_.getCmdList())) { // 跳过已添加的,因标准list容器没有下标 if (k++ <= currentRow) continue; @@ -739,16 +739,16 @@ bool GameController::actionPiece(QPointF pos) // 播放胜利或失败音效 #ifndef DONOT_PLAY_WIN_SOUND - if (game_.whoWin() != PLAYER_NOBODY && + if (position_.whoWin() != PLAYER_NOBODY && (manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over.")) playSound(":/sound/resources/sound/win.wav"); #endif // AI设置 - if (&game_ == &(this->game_)) { + if (&position_ == &(this->position_)) { // 如果还未决出胜负 - if (game_.whoWin() == PLAYER_NOBODY) { - if (game_.whosTurn() == PLAYER1) { + if (position_.whoWin() == PLAYER_NOBODY) { + if (position_.whosTurn() == PLAYER1) { if (isAiPlayer1) { ai1.resume(); } @@ -768,7 +768,7 @@ bool GameController::actionPiece(QPointF pos) ai2.stop(); // 弹框 - //message = QString::fromStdString(game_.getTips()); + //message = QString::fromStdString(position_.getTips()); //QMessageBox::about(NULL, "游戏结果", message); } } @@ -782,11 +782,11 @@ bool GameController::giveUp() { bool result = false; - if (game_.whosTurn() == PLAYER1) { - result = game_.giveup(PLAYER1); + if (position_.whosTurn() == PLAYER1) { + result = position_.giveup(PLAYER1); } - else if (game_.whosTurn() == PLAYER2) { - result = game_.giveup(PLAYER2); + else if (position_.whosTurn() == PLAYER2) { + result = position_.giveup(PLAYER2); } if (result) { @@ -795,14 +795,14 @@ bool GameController::giveUp() int k = 0; // 输出命令行 - for (const auto & i : *(game_.getCmdList())) { + for (const auto & i : *(position_.getCmdList())) { // 跳过已添加的,因标准list容器没有下标 if (k++ <= currentRow) continue; manualListModel.insertRow(++currentRow); manualListModel.setData(manualListModel.index(currentRow), i.c_str()); } - if (game_.whoWin() != PLAYER_NOBODY) + if (position_.whoWin() != PLAYER_NOBODY) playSound(":/sound/resources/sound/loss.wav"); } @@ -824,7 +824,7 @@ bool GameController::command(const QString &cmd, bool update /* = true */) // 声音 QString sound; - switch (game_.getAction()) { + switch (position_.getAction()) { case ACTION_CHOOSE: case ACTION_PLACE: sound = ":/sound/resources/sound/drog.wav"; @@ -837,44 +837,44 @@ bool GameController::command(const QString &cmd, bool update /* = true */) } // 如果未开局则开局 - if (game_.getStage() == GAME_NOTSTARTED) { + if (position_.getStage() == GAME_NOTSTARTED) { gameStart(); } - if (!game_.command(cmd.toStdString().c_str())) + if (!position_.command(cmd.toStdString().c_str())) return false; - if (sound == ":/sound/resources/sound/drog.wav" && game_.getAction() == ACTION_CAPTURE) { + if (sound == ":/sound/resources/sound/drog.wav" && position_.getAction() == ACTION_CAPTURE) { sound = ":/sound/resources/sound/capture.wav"; } if (update) { playSound(sound); - updateScence(game_); + updateScence(position_); } // 发信号更新状态栏 - message = QString::fromStdString(game_.getTips()); + message = QString::fromStdString(position_.getTips()); emit statusBarChanged(message); // 对于新开局 - if (game_.getCmdList()->size() <= 1) { + if (position_.getCmdList()->size() <= 1) { manualListModel.removeRows(0, manualListModel.rowCount()); manualListModel.insertRow(0); - manualListModel.setData(manualListModel.index(0), game_.getCmdLine()); + manualListModel.setData(manualListModel.index(0), position_.getCmdLine()); currentRow = 0; } // 对于当前局 else { currentRow = manualListModel.rowCount() - 1; // 跳过已添加行,迭代器不支持+运算符,只能一个个++ - auto i = (game_.getCmdList()->begin()); - for (int r = 0; i != (game_.getCmdList())->end(); i++) { + auto i = (position_.getCmdList()->begin()); + for (int r = 0; i != (position_.getCmdList())->end(); i++) { if (r++ > currentRow) break; } // 将新增的棋谱行插入到ListModel - while (i != game_.getCmdList()->end()) { + while (i != position_.getCmdList()->end()) { manualListModel.insertRow(++currentRow); manualListModel.setData(manualListModel.index(currentRow), (*i++).c_str()); } @@ -882,17 +882,17 @@ bool GameController::command(const QString &cmd, bool update /* = true */) // 播放胜利或失败音效 #ifndef DONOT_PLAY_WIN_SOUND - if (game_.whoWin() != PLAYER_NOBODY && + if (position_.whoWin() != PLAYER_NOBODY && (manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over.")) { playSound(":/sound/resources/sound/win.wav"); } #endif // AI设置 - if (&game_ == &(this->game_)) { + if (&position_ == &(this->position_)) { // 如果还未决出胜负 - if (game_.whoWin() == PLAYER_NOBODY) { - if (game_.whosTurn() == PLAYER1) { + if (position_.whoWin() == PLAYER_NOBODY) { + if (position_.whosTurn() == PLAYER1) { if (isAiPlayer1) { ai1.resume(); } @@ -925,7 +925,7 @@ bool GameController::command(const QString &cmd, bool update /* = true */) #ifdef MESSAGEBOX_ENABLE // 弹框 - message = QString::fromStdString(game_.getTips()); + message = QString::fromStdString(position_.getTips()); QMessageBox::about(NULL, "游戏结果", message); #endif } @@ -958,24 +958,24 @@ bool GameController::stageChange(int row, bool forceUpdate) for (int i = 0; i <= row; i++) { loggerDebug("%s\n", mlist.at(i).toStdString().c_str()); - gameTemp.command(mlist.at(i).toStdString().c_str()); + dummyPosition.command(mlist.at(i).toStdString().c_str()); } // 下面这步关键,会让悔棋者承担时间损失 - gameTemp.setStartTime(game_.getStartTimeb()); + dummyPosition.setStartTime(position_.getStartTimeb()); // 刷新棋局场景 - updateScence(gameTemp); + updateScence(dummyPosition); return true; } bool GameController::updateScence() { - return updateScence(game_); + return updateScence(position_); } -bool GameController::updateScence(MillGame &game) +bool GameController::updateScence(Position &game) { const int *board = game.getBoard(); QPointF pos; diff --git a/src/ui/qt/gamecontroller.h b/src/ui/qt/gamecontroller.h index aff6c63c..97544164 100644 --- a/src/ui/qt/gamecontroller.h +++ b/src/ui/qt/gamecontroller.h @@ -192,7 +192,7 @@ public slots: // 更新棋局显示,每步后执行才能刷新局面 bool updateScence(); - bool updateScence(MillGame &game); + bool updateScence(Position &game); // 显示网络配置窗口 void showNetworkWindow(); @@ -204,10 +204,10 @@ protected: private: // 棋对象的数据模型 - MillGame game_; + Position position_; // 棋对象的数据模型(临时) - MillGame gameTemp; + Position dummyPosition; // 2个AI的线程 AiThread ai1, ai2;