refactor: 使用 position 表示"局面"的意思

相关文件名暂未修改.
This commit is contained in:
CalciteM Team 2019-09-13 00:23:24 +08:00
parent 4b4c754050
commit 073f4ffa01
14 changed files with 299 additions and 299 deletions

View File

@ -21,7 +21,7 @@
#include "evaluate.h" #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对先手有利则增大对后手有利则减小 // 初始评估值为0对先手有利则增大对后手有利则减小
value_t value = 0; value_t value = 0;
@ -31,31 +31,31 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
int nPiecesNeedRemove = 0; int nPiecesNeedRemove = 0;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->stage = gameContext->stage; node->stage = positionContext->stage;
node->action = gameContext->action; node->action = positionContext->action;
node->evaluated = true; node->evaluated = true;
#endif #endif
switch (gameContext->stage) { switch (positionContext->stage) {
case GAME_NOTSTARTED: case GAME_NOTSTARTED:
break; break;
case GAME_PLACING: case GAME_PLACING:
// 按手中的棋子计分不要break; // 按手中的棋子计分不要break;
nPiecesInHandDiff = gameContext->nPiecesInHand_1 - gameContext->nPiecesInHand_2; nPiecesInHandDiff = positionContext->nPiecesInHand_1 - positionContext->nPiecesInHand_2;
value += nPiecesInHandDiff * 50; value += nPiecesInHandDiff * 50;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->nPiecesInHandDiff = nPiecesInHandDiff; node->nPiecesInHandDiff = nPiecesInHandDiff;
#endif #endif
// 按场上棋子计分 // 按场上棋子计分
nPiecesOnBoardDiff = gameContext->nPiecesOnBoard_1 - gameContext->nPiecesOnBoard_2; nPiecesOnBoardDiff = positionContext->nPiecesOnBoard_1 - positionContext->nPiecesOnBoard_2;
value += nPiecesOnBoardDiff * 100; value += nPiecesOnBoardDiff * 100;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->nPiecesOnBoardDiff = nPiecesOnBoardDiff; node->nPiecesOnBoardDiff = nPiecesOnBoardDiff;
#endif #endif
switch (gameContext->action) { switch (positionContext->action) {
// 选子和落子使用相同的评价方法 // 选子和落子使用相同的评价方法
case ACTION_CHOOSE: case ACTION_CHOOSE:
case ACTION_PLACE: case ACTION_PLACE:
@ -63,8 +63,8 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
// 如果形成去子状态每有一个可去的子算100分 // 如果形成去子状态每有一个可去的子算100分
case ACTION_CAPTURE: case ACTION_CAPTURE:
nPiecesNeedRemove = (gameContext->turn == PLAYER1) ? nPiecesNeedRemove = (positionContext->turn == PLAYER1) ?
gameContext->nPiecesNeedRemove : -(gameContext->nPiecesNeedRemove); positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove);
value += nPiecesNeedRemove * 100; value += nPiecesNeedRemove * 100;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->nPiecesNeedRemove = nPiecesNeedRemove; node->nPiecesNeedRemove = nPiecesNeedRemove;
@ -78,14 +78,14 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
case GAME_MOVING: case GAME_MOVING:
// 按场上棋子计分 // 按场上棋子计分
value += gameContext->nPiecesOnBoard_1 * 100 - gameContext->nPiecesOnBoard_2 * 100; value += positionContext->nPiecesOnBoard_1 * 100 - positionContext->nPiecesOnBoard_2 * 100;
#ifdef EVALUATE_MOBILITY #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 */ #endif /* EVALUATE_MOBILITY */
switch (gameContext->action) { switch (positionContext->action) {
// 选子和落子使用相同的评价方法 // 选子和落子使用相同的评价方法
case ACTION_CHOOSE: case ACTION_CHOOSE:
case ACTION_PLACE: case ACTION_PLACE:
@ -93,8 +93,8 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
// 如果形成去子状态每有一个可去的子算128分 // 如果形成去子状态每有一个可去的子算128分
case ACTION_CAPTURE: case ACTION_CAPTURE:
nPiecesNeedRemove = (gameContext->turn == PLAYER1) ? nPiecesNeedRemove = (positionContext->turn == PLAYER1) ?
gameContext->nPiecesNeedRemove : -(gameContext->nPiecesNeedRemove); positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove);
value += nPiecesNeedRemove * 128; value += nPiecesNeedRemove * 128;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->nPiecesNeedRemove = nPiecesNeedRemove; node->nPiecesNeedRemove = nPiecesNeedRemove;
@ -109,9 +109,9 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
// 终局评价最简单 // 终局评价最简单
case GAME_OVER: case GAME_OVER:
// 布局阶段闷棋判断 // 布局阶段闷棋判断
if (gameContext->nPiecesOnBoard_1 + gameContext->nPiecesOnBoard_2 >= if (positionContext->nPiecesOnBoard_1 + positionContext->nPiecesOnBoard_2 >=
Board::N_SEATS * Board::N_RINGS) { Board::N_SEATS * Board::N_RINGS) {
if (gameTemp.getRule()->isStartingPlayerLoseWhenBoardFull) { if (dummyPosition.getRule()->isStartingPlayerLoseWhenBoardFull) {
// winner = PLAYER2; // winner = PLAYER2;
value -= 10000; value -= 10000;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
@ -123,11 +123,11 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
} }
// 走棋阶段被闷判断 // 走棋阶段被闷判断
if (gameContext->action == ACTION_CHOOSE && if (positionContext->action == ACTION_CHOOSE &&
gameTemp.context.board.isAllSurrounded(gameContext->turn, gameTemp.currentRule, gameContext->nPiecesOnBoard_1, gameContext->nPiecesOnBoard_2, gameContext->turn) && dummyPosition.context.board.isAllSurrounded(positionContext->turn, dummyPosition.currentRule, positionContext->nPiecesOnBoard_1, positionContext->nPiecesOnBoard_2, positionContext->turn) &&
gameTemp.getRule()->isLoseWhenNoWay) { dummyPosition.getRule()->isLoseWhenNoWay) {
// 规则要求被“闷”判负,则对手获胜 // 规则要求被“闷”判负,则对手获胜
if (gameContext->turn == PLAYER1) { if (positionContext->turn == PLAYER1) {
value -= 10000; value -= 10000;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->result = -2; 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; value -= 10000;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->result = -1; node->result = -1;
#endif #endif
} else if (gameContext->nPiecesOnBoard_2 < gameTemp.getRule()->nPiecesAtLeast) { } else if (positionContext->nPiecesOnBoard_2 < dummyPosition.getRule()->nPiecesAtLeast) {
value += 10000; value += 10000;
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->result = 1; node->result = 1;

View File

@ -34,7 +34,7 @@ public:
Evaluation &operator=(const Evaluation &) = delete; 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 #ifdef EVALUATE_ENABLE

View File

@ -23,7 +23,7 @@
#include "movegen.h" #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, MillGameAi_ab::Node *node, MillGameAi_ab::Node *rootNode,
move_t bestMove) move_t bestMove)
{ {
@ -32,23 +32,23 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
size_t newCapacity = 24; size_t newCapacity = 24;
// 留足余量空间避免多次重新分配,此动作本身也占用 CPU/内存 开销 // 留足余量空间避免多次重新分配,此动作本身也占用 CPU/内存 开销
switch (gameTemp.getStage()) { switch (dummyPosition.getStage()) {
case GAME_PLACING: case GAME_PLACING:
if (gameTemp.getAction() == ACTION_CAPTURE) { if (dummyPosition.getAction() == ACTION_CAPTURE) {
if (gameTemp.whosTurn() == PLAYER1) if (dummyPosition.whosTurn() == PLAYER1)
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_2()); newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_2());
else else
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_1()); newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_1());
} else { } else {
newCapacity = static_cast<size_t>(gameTemp.getPiecesInHandCount_1() + gameTemp.getPiecesInHandCount_2()); newCapacity = static_cast<size_t>(dummyPosition.getPiecesInHandCount_1() + dummyPosition.getPiecesInHandCount_2());
} }
break; break;
case GAME_MOVING: case GAME_MOVING:
if (gameTemp.getAction() == ACTION_CAPTURE) { if (dummyPosition.getAction() == ACTION_CAPTURE) {
if (gameTemp.whosTurn() == PLAYER1) if (dummyPosition.whosTurn() == PLAYER1)
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_2()); newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_2());
else else
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_1()); newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_1());
} else { } else {
newCapacity = 6; 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_CHOOSE:
case ACTION_PLACE: case ACTION_PLACE:
// 对于摆子阶段 // 对于摆子阶段
if (gameTemp.context.stage & (GAME_PLACING | GAME_NOTSTARTED)) { if (dummyPosition.context.stage & (GAME_PLACING | GAME_NOTSTARTED)) {
for (int i : movePriorityTable) { for (int i : movePriorityTable) {
location = i; location = i;
if (gameTemp.board_[location]) { if (dummyPosition.board_[location]) {
continue; continue;
} }
if (gameTemp.context.stage != GAME_NOTSTARTED || node != rootNode) { if (dummyPosition.context.stage != GAME_NOTSTARTED || node != rootNode) {
ai_ab.addNode(node, 0, location, bestMove, gameTemp.context.turn); ai_ab.addNode(node, 0, location, bestMove, dummyPosition.context.turn);
} else { } else {
// 若为先手,则抢占星位 // 若为先手,则抢占星位
if (MillGame::isStarPoint(location)) { if (Position::isStarPoint(location)) {
ai_ab.addNode(node, MillGameAi_ab::INF_VALUE, location, bestMove, gameTemp.context.turn); 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; int newLocation, oldLocation;
// 尽量走理论上较差的位置的棋子 // 尽量走理论上较差的位置的棋子
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) { for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
oldLocation = movePriorityTable[i]; oldLocation = movePriorityTable[i];
if (!gameTemp.choose(oldLocation)) { if (!dummyPosition.choose(oldLocation)) {
continue; continue;
} }
if ((gameTemp.context.turn == PLAYER1 && if ((dummyPosition.context.turn == PLAYER1 &&
(gameTemp.context.nPiecesOnBoard_1 > gameTemp.currentRule.nPiecesAtLeast || !gameTemp.currentRule.allowFlyWhenRemainThreePieces)) || (dummyPosition.context.nPiecesOnBoard_1 > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces)) ||
(gameTemp.context.turn == PLAYER2 && (dummyPosition.context.turn == PLAYER2 &&
(gameTemp.context.nPiecesOnBoard_2 > gameTemp.currentRule.nPiecesAtLeast || !gameTemp.currentRule.allowFlyWhenRemainThreePieces))) { (dummyPosition.context.nPiecesOnBoard_2 > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces))) {
// 对于棋盘上还有3个子以上或不允许飞子的情况要求必须在着法表中 // 对于棋盘上还有3个子以上或不允许飞子的情况要求必须在着法表中
for (int moveDirection = MOVE_DIRECTION_CLOCKWISE; moveDirection <= MOVE_DIRECTION_OUTWARD; moveDirection++) { for (int moveDirection = MOVE_DIRECTION_CLOCKWISE; moveDirection <= MOVE_DIRECTION_OUTWARD; moveDirection++) {
// 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中 // 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中
newLocation = moveTable[oldLocation][moveDirection]; newLocation = moveTable[oldLocation][moveDirection];
if (newLocation && !gameTemp.board_[newLocation]) { if (newLocation && !dummyPosition.board_[newLocation]) {
int move = (oldLocation << 8) + 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 { } else {
// 对于棋盘上还有不到3个字但允许飞子的情况不要求在着法表中是空位就行 // 对于棋盘上还有不到3个字但允许飞子的情况不要求在着法表中是空位就行
for (newLocation = Board::LOCATION_BEGIN; newLocation < Board::LOCATION_END; newLocation++) { for (newLocation = Board::LOCATION_BEGIN; newLocation < Board::LOCATION_END; newLocation++) {
if (!gameTemp.board_[newLocation]) { if (!dummyPosition.board_[newLocation]) {
int move = (oldLocation << 8) + 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: 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--) { for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
location = movePriorityTable[i]; location = movePriorityTable[i];
if (gameTemp.board_[location] & opponent) { if (dummyPosition.board_[location] & opponent) {
ai_ab.addNode(node, 0, -location, bestMove, gameTemp.context.turn); ai_ab.addNode(node, 0, -location, bestMove, dummyPosition.context.turn);
} }
} }
break; 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--) { for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
location = movePriorityTable[i]; location = movePriorityTable[i];
if (gameTemp.board_[location] & opponent) { if (dummyPosition.board_[location] & opponent) {
if (gameTemp.getRule()->allowRemoveMill || !gameTemp.context.board.inHowManyMills(location)) { if (dummyPosition.getRule()->allowRemoveMill || !dummyPosition.context.board.inHowManyMills(location)) {
ai_ab.addNode(node, 0, -location, bestMove, gameTemp.context.turn); 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 #if 1
const int moveTable_obliqueLine[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = { const int moveTable_obliqueLine[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = {
@ -356,7 +356,7 @@ void MoveList::createMoveTable(MillGame &game)
}; };
#endif #endif
if (game.currentRule.hasObliqueLines) { if (position.currentRule.hasObliqueLines) {
memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable)); memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable));
} else { } else {
memcpy(moveTable, moveTable_noObliqueLine, sizeof(moveTable)); memcpy(moveTable, moveTable_noObliqueLine, sizeof(moveTable));
@ -379,14 +379,14 @@ void MoveList::createMoveTable(MillGame &game)
#endif #endif
} }
void MoveList::shuffleMovePriorityTable(MillGame & game) void MoveList::shuffleMovePriorityTable(Position &position)
{ {
array<int, 4> movePriorityTable0 = { 17, 19, 21, 23 }; // 中圈四个顶点 (星位) array<int, 4> movePriorityTable0 = { 17, 19, 21, 23 }; // 中圈四个顶点 (星位)
array<int, 8> movePriorityTable1 = { 25, 27, 29, 31, 9, 11, 13, 15 }; // 外圈和内圈四个顶点 array<int, 8> movePriorityTable1 = { 25, 27, 29, 31, 9, 11, 13, 15 }; // 外圈和内圈四个顶点
array<int, 4> movePriorityTable2 = { 16, 18, 20, 22 }; // 中圈十字架 array<int, 4> movePriorityTable2 = { 16, 18, 20, 22 }; // 中圈十字架
array<int, 8> movePriorityTable3 = { 24, 26, 28, 30, 8, 10, 12, 14 }; // 外内圈十字架 array<int, 8> movePriorityTable3 = { 24, 26, 28, 30, 8, 10, 12, 14 }; // 外内圈十字架
if (game.getRandomMove() == true) { if (position.getRandomMove() == true) {
uint32_t seed = static_cast<uint32_t>(std::chrono::system_clock::now().time_since_epoch().count()); uint32_t seed = static_cast<uint32_t>(std::chrono::system_clock::now().time_since_epoch().count());
std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed)); std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed));

View File

@ -34,15 +34,15 @@ public:
MoveList &operator=(const MoveList &) = delete; 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, MillGameAi_ab::Node *node, MillGameAi_ab::Node *rootNode,
move_t bestMove); 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 // 着法表 // TODO: Move to private
inline static int moveTable[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = { {0} }; inline static int moveTable[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = { {0} };

View File

@ -57,7 +57,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth)
{ {
depth_t newDepth = originalDepth; depth_t newDepth = originalDepth;
if ((gameTemp.context.stage) & (GAME_PLACING)) { if ((dummyPosition.context.stage) & (GAME_PLACING)) {
#ifdef GAME_PLACING_DYNAMIC_DEPTH #ifdef GAME_PLACING_DYNAMIC_DEPTH
#ifdef DEAL_WITH_HORIZON_EFFECT #ifdef DEAL_WITH_HORIZON_EFFECT
#ifdef TRANSPOSITION_TABLE_ENABLE #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 }; depth_t depthTable[] = { 2, 13, 13, 13, 12, 11, 10, 9, 9, 8, 8, 7, 1 };
#endif #endif
#endif // DEAL_WITH_HORIZON_EFFECT #endif // DEAL_WITH_HORIZON_EFFECT
newDepth = depthTable[gameTemp.getPiecesInHandCount_1()]; newDepth = depthTable[dummyPosition.getPiecesInHandCount_1()];
#elif defined GAME_PLACING_FIXED_DEPTH #elif defined GAME_PLACING_FIXED_DEPTH
newDepth = GAME_PLACING_FIXED_DEPTH; newDepth = GAME_PLACING_FIXED_DEPTH;
#endif // GAME_PLACING_DYNAMIC_DEPTH #endif // GAME_PLACING_DYNAMIC_DEPTH
@ -85,7 +85,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth)
#ifdef GAME_MOVING_FIXED_DEPTH #ifdef GAME_MOVING_FIXED_DEPTH
// 走棋阶段将深度调整 // 走棋阶段将深度调整
if ((gameTemp.context.stage) & (GAME_MOVING)) { if ((dummyPosition.context.stage) & (GAME_MOVING)) {
newDepth = GAME_MOVING_FIXED_DEPTH; newDepth = GAME_MOVING_FIXED_DEPTH;
} }
#endif /* GAME_MOVING_FIXED_DEPTH */ #endif /* GAME_MOVING_FIXED_DEPTH */
@ -141,8 +141,8 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
newNode->root = rootNode; newNode->root = rootNode;
newNode->stage = gameTemp.context.stage; newNode->stage = dummyPosition.context.stage;
newNode->action = gameTemp.context.action; newNode->action = dummyPosition.context.action;
newNode->evaluated = false; newNode->evaluated = false;
newNode->nPiecesInHandDiff = INT_MAX; newNode->nPiecesInHandDiff = INT_MAX;
newNode->nPiecesOnBoardDiff = INT_MAX; newNode->nPiecesOnBoardDiff = INT_MAX;
@ -156,15 +156,15 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
char cmd[32] = { 0 }; char cmd[32] = { 0 };
if (move < 0) { if (move < 0) {
gameTemp.context.board.locationToPolar(-move, r, s); dummyPosition.context.board.locationToPolar(-move, r, s);
sprintf(cmd, "-(%1u,%1u)", r, s); sprintf(cmd, "-(%1u,%1u)", r, s);
} else if (move & 0x7f00) { } else if (move & 0x7f00) {
int r1, s1; int r1, s1;
gameTemp.context.board.locationToPolar(move >> 8, r1, s1); dummyPosition.context.board.locationToPolar(move >> 8, r1, s1);
gameTemp.context.board.locationToPolar(move & 0x00ff, r, s); dummyPosition.context.board.locationToPolar(move & 0x00ff, r, s);
sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s); sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s);
} else { } else {
gameTemp.context.board.locationToPolar(move & 0x007f, r, s); dummyPosition.context.board.locationToPolar(move & 0x007f, r, s);
sprintf(cmd, "(%1u,%1u)", r, s); sprintf(cmd, "(%1u,%1u)", r, s);
} }
@ -176,7 +176,7 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
if (bestMove == 0 || move != bestMove) { if (bestMove == 0 || move != bestMove) {
#ifdef MILL_FIRST #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); parent->children.insert(parent->children.begin(), newNode);
} else { } else {
parent->children.push_back(newNode); 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); std::stable_sort(node->children.begin(), node->children.end(), nodeGreater);
} else { } else {
std::stable_sort(node->children.begin(), node->children.end(), nodeLess); std::stable_sort(node->children.begin(), node->children.end(), nodeLess);
@ -260,10 +260,10 @@ void MillGameAi_ab::deleteTree(Node *node)
#endif #endif
} }
void MillGameAi_ab::setGame(const MillGame &game) void MillGameAi_ab::setPosition(const Position &position)
{ {
// 如果规则改变重建hashmap // 如果规则改变重建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 #ifdef TRANSPOSITION_TABLE_ENABLE
TranspositionTable::clearTranspositionTable(); TranspositionTable::clearTranspositionTable();
#endif // TRANSPOSITION_TABLE_ENABLE #endif // TRANSPOSITION_TABLE_ENABLE
@ -277,9 +277,9 @@ void MillGameAi_ab::setGame(const MillGame &game)
positions.clear(); positions.clear();
} }
this->game_ = game; this->position_ = position;
gameTemp = game; dummyPosition = position;
gameContext = &(gameTemp.context); positionContext = &(dummyPosition.context);
requiredQuit = false; requiredQuit = false;
deleteTree(rootNode); deleteTree(rootNode);
#ifdef MEMORY_POOL #ifdef MEMORY_POOL
@ -313,11 +313,11 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
chrono::steady_clock::time_point timeEnd; chrono::steady_clock::time_point timeEnd;
#ifdef BOOK_LEARNING #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 { } else {
// 暂时在此处清空开局库 // 暂时在此处清空开局库
openingBook.clear(); openingBook.clear();
@ -328,8 +328,8 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
#ifdef THREEFOLD_REPETITION #ifdef THREEFOLD_REPETITION
static int nRepetition = 0; static int nRepetition = 0;
if (game_.getStage() == GAME_MOVING) { if (position_.getStage() == GAME_MOVING) {
hash_t hash = game_.getHash(); hash_t hash = position_.getHash();
if (std::find(positions.begin(), positions.end(), hash) != positions.end()) { if (std::find(positions.begin(), positions.end(), hash) != positions.end()) {
nRepetition++; nRepetition++;
@ -342,13 +342,13 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
} }
} }
if (game_.getStage() == GAME_PLACING) { if (position_.getStage() == GAME_PLACING) {
positions.clear(); positions.clear();
} }
#endif // THREEFOLD_REPETITION #endif // THREEFOLD_REPETITION
// 随机打乱着法顺序 // 随机打乱着法顺序
MoveList::shuffleMovePriorityTable(game_); MoveList::shuffleMovePriorityTable(position_);
#ifdef IDS_SUPPORT #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; enum TranspositionTable::HashType hashf = TranspositionTable::hashfALPHA;
// 获取哈希值 // 获取哈希值
hash_t hash = gameTemp.getHash(); hash_t hash = dummyPosition.getHash();
#ifdef DEBUG_AB_TREE #ifdef DEBUG_AB_TREE
node->hash = hash; node->hash = hash;
#endif #endif
@ -432,7 +432,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
#if 0 #if 0
// TODO: 有必要针对深度微调 value? // TODO: 有必要针对深度微调 value?
if (gameContext->turn == PLAYER1) if (positionContext->turn == PLAYER1)
node->value += hashValue.depth - depth; node->value += hashValue.depth - depth;
else else
node->value -= hashValue.depth - depth; 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 #ifdef DEBUG_AB_TREE
node->depth = depth; node->depth = depth;
node->root = rootNode; node->root = rootNode;
// node->player = gameContext->turn; // node->player = positionContext->turn;
// 初始化 // 初始化
node->isLeaf = false; node->isLeaf = false;
node->isTimeout = 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 #endif // DEBUG_AB_TREE
// 搜索到叶子节点(决胜局面) // TODO: 对哈希进行特殊处理 // 搜索到叶子节点(决胜局面) // 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++; evaluatedNodeCount++;
// 为争取速胜value 值 +- 深度 // 为争取速胜value 值 +- 深度
@ -486,11 +486,11 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
// 搜索到第0层或需要退出 // 搜索到第0层或需要退出
if (!depth || requiredQuit) { if (!depth || requiredQuit) {
// 局面评估 // 局面评估
node->value = Evaluation::getValue(gameTemp, gameContext, node); node->value = Evaluation::getValue(dummyPosition, positionContext, node);
evaluatedNodeCount++; evaluatedNodeCount++;
// 为争取速胜value 值 +- 深度 (有必要?) // 为争取速胜value 值 +- 深度 (有必要?)
if (gameContext->turn == PLAYER1) { if (positionContext->turn == PLAYER1) {
node->value += depth; node->value += depth;
} else { } else {
node->value -= depth; node->value -= depth;
@ -504,8 +504,8 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
#ifdef BOOK_LEARNING #ifdef BOOK_LEARNING
// 检索开局库 // 检索开局库
if (gameContext->stage == GAME_PLACING && findBookHash(hash, hashValue)) { if (positionContext->stage == GAME_PLACING && findBookHash(hash, hashValue)) {
if (gameContext->turn == PLAYER2) { if (positionContext->turn == PLAYER2) {
// 是否需对后手扣分 // TODO: 先后手都处理 // 是否需对后手扣分 // TODO: 先后手都处理
node->value += 1; 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 // 根据演算模型执行 MiniMax 检索,对先手,搜索 Max, 对后手,搜索 Min
minMax = gameTemp.whosTurn() == PLAYER1 ? -INF_VALUE : INF_VALUE; minMax = dummyPosition.whosTurn() == PLAYER1 ? -INF_VALUE : INF_VALUE;
for (auto child : node->children) { 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 #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); value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child);
// 上下文弹出栈,撤销着法 // 上下文弹出栈,撤销着法
gameTemp.context = contextStack.top(); dummyPosition.context = contextStack.top();
contextStack.pop(); 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; // 是否必败 bool isMostLose = true; // 是否必败
Player whosTurn = game_.whosTurn(); Player whosTurn = position_.whosTurn();
for (auto child : rootNode->children) { for (auto child : rootNode->children) {
// TODO: 使用常量代替 // TODO: 使用常量代替
@ -750,15 +750,15 @@ const char *MillGameAi_ab::move2string(move_t move)
int r, s; int r, s;
if (move < 0) { if (move < 0) {
gameTemp.context.board.locationToPolar(-move, r, s); dummyPosition.context.board.locationToPolar(-move, r, s);
sprintf(cmdline, "-(%1u,%1u)", r, s); sprintf(cmdline, "-(%1u,%1u)", r, s);
} else if (move & 0x7f00) { } else if (move & 0x7f00) {
int r1, s1; int r1, s1;
gameTemp.context.board.locationToPolar(move >> 8, r1, s1); dummyPosition.context.board.locationToPolar(move >> 8, r1, s1);
gameTemp.context.board.locationToPolar(move & 0x00ff, r, s); dummyPosition.context.board.locationToPolar(move & 0x00ff, r, s);
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s); sprintf(cmdline, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s);
} else { } else {
gameTemp.context.board.locationToPolar(move & 0x007f, r, s); dummyPosition.context.board.locationToPolar(move & 0x007f, r, s);
sprintf(cmdline, "(%1u,%1u)", r, s); sprintf(cmdline, "(%1u,%1u)", r, s);
} }

View File

@ -75,7 +75,7 @@ public:
bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出 bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出
bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面 bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面
bool visited; // 是否在遍历时访问过 bool visited; // 是否在遍历时访问过
GameStage stage; // 摆棋阶段还是走棋阶段 PositionStage stage; // 摆棋阶段还是走棋阶段
Action action; // 动作状态 Action action; // 动作状态
int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值 int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值
int nPiecesInHandDiff; // 手中的棋子个数和对手的差值 int nPiecesInHandDiff; // 手中的棋子个数和对手的差值
@ -97,7 +97,7 @@ public:
MillGameAi_ab(); MillGameAi_ab();
~MillGameAi_ab(); ~MillGameAi_ab();
void setGame(const MillGame &game); void setPosition(const Position &position);
void quit() void quit()
{ {
@ -185,15 +185,15 @@ protected:
private: private:
// 原始模型 // 原始模型
MillGame game_; Position position_;
// 演算用的模型 // 演算用的模型
MillGame gameTemp; Position dummyPosition;
GameContext *gameContext {}; PositionContext *positionContext {};
// hash 计算时,各种转换用的模型 // hash 计算时,各种转换用的模型
MillGame gameTempShift; Position dummyPositionShift;
// 根节点 // 根节点
Node *rootNode {nullptr}; Node *rootNode {nullptr};
@ -218,9 +218,9 @@ private:
// 局面数据栈 // 局面数据栈
//#ifdef MEMORY_POOL //#ifdef MEMORY_POOL
// StackAlloc<MillGame::GameContext, MemoryPool<MillGame::GameContext> > contextStack; // StackAlloc<MillGame::PositionContext, MemoryPool<MillGame::PositionContext> > contextStack;
//#else //#else
stack<GameContext> contextStack; stack<PositionContext> contextStack;
//#endif //#endif
// 标识,用于跳出剪枝算法,立即返回 // 标识,用于跳出剪枝算法,立即返回

View File

@ -50,17 +50,17 @@ bool TranspositionTable::findHash(hash_t hash, TranspositionTable::HashValue &ha
return iter; return iter;
// 变换局面,查找 hash (废弃) // 变换局面,查找 hash (废弃)
gameTempShift = gameTemp; dummyPositionShift = dummyPosition;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (i) if (i)
gameTempShift.mirror(false); dummyPositionShift.mirror(false);
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
if (j) if (j)
gameTempShift.turn(false); dummyPositionShift.turn(false);
for (int k = 0; k < 4; k++) { for (int k = 0; k < 4; k++) {
gameTempShift.rotate(k * 90, false); dummyPositionShift.rotate(k * 90, false);
iter = hashmap.find(gameTempShift.getHash()); iter = hashmap.find(dummyPositionShift.getHash());
if (iter != hashmap.end()) if (iter != hashmap.end())
return iter; return iter;
} }

View File

@ -26,7 +26,7 @@
AiThread::AiThread(int id, QObject *parent) : AiThread::AiThread(int id, QObject *parent) :
QThread(parent), QThread(parent),
waiting_(false), waiting_(false),
game_(nullptr), position_(nullptr),
aiDepth(2), aiDepth(2),
aiTime(3600) aiTime(3600)
{ {
@ -60,12 +60,12 @@ AiThread::~AiThread()
wait(); wait();
} }
void AiThread::setAi(const MillGame &game) void AiThread::setAi(const Position &position)
{ {
mutex.lock(); mutex.lock();
this->game_ = &game; this->position_ = &position;
ai_ab.setGame(*(this->game_)); ai_ab.setPosition(*(this->position_));
#ifdef TRANSPOSITION_TABLE_ENABLE #ifdef TRANSPOSITION_TABLE_ENABLE
// 新下一盘前清除哈希表 (注意可能同时存在每步之前清除) // 新下一盘前清除哈希表 (注意可能同时存在每步之前清除)
@ -77,11 +77,11 @@ void AiThread::setAi(const MillGame &game)
mutex.unlock(); 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(); mutex.lock();
this->game_ = &game; this->position_ = &position;
ai_ab.setGame(game); ai_ab.setPosition(position);
aiDepth = depth; aiDepth = depth;
aiTime = time; aiTime = time;
mutex.unlock(); mutex.unlock();
@ -107,7 +107,7 @@ void AiThread::run()
while (!isInterruptionRequested()) { while (!isInterruptionRequested()) {
mutex.lock(); mutex.lock();
i = MillGame::playerToId(game_->whosTurn()); i = Position::playerToId(position_->whosTurn());
if (i != id || waiting_) { if (i != id || waiting_) {
pauseCondition.wait(&mutex); pauseCondition.wait(&mutex);
@ -115,7 +115,7 @@ void AiThread::run()
continue; continue;
} }
ai_ab.setGame(*game_); ai_ab.setPosition(*position_);
emit calcStarted(); emit calcStarted();
mutex.unlock(); mutex.unlock();

View File

@ -54,8 +54,8 @@ protected:
public: public:
// AI设置 // AI设置
void setAi(const MillGame &game); void setAi(const Position &position);
void setAi(const MillGame &game, depth_t depth, int time); void setAi(const Position &position, depth_t depth, int time);
Server *getServer() Server *getServer()
{ {
@ -107,7 +107,7 @@ private:
QWaitCondition pauseCondition; QWaitCondition pauseCondition;
// 主线程棋对象的引用 // 主线程棋对象的引用
const MillGame *game_; const Position *position_;
// Alpha-Beta剪枝算法类 // Alpha-Beta剪枝算法类
MillGameAi_ab ai_ab; MillGameAi_ab ai_ab;

View File

@ -24,7 +24,7 @@
#include "search.h" #include "search.h"
#include "movegen.h" #include "movegen.h"
MillGame::MillGame() Position::Position()
{ {
// 单独提出 board 等数据,免得每次都写 context.board; // 单独提出 board 等数据,免得每次都写 context.board;
board_ = context.board.locations; board_ = context.board.locations;
@ -44,40 +44,40 @@ MillGame::MillGame()
score_1 = score_2 = score_draw = 0; 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; return *this;
currentRule = game.currentRule; currentRule = position.currentRule;
context = game.context; context = position.context;
currentStep = game.currentStep; currentStep = position.currentStep;
moveStep = game.moveStep; moveStep = position.moveStep;
randomMove_ = game.randomMove_; randomMove_ = position.randomMove_;
giveUpIfMostLose_ = game.giveUpIfMostLose_; giveUpIfMostLose_ = position.giveUpIfMostLose_;
board_ = context.board.locations; board_ = context.board.locations;
currentLocation = game.currentLocation; currentLocation = position.currentLocation;
winner = game.winner; winner = position.winner;
startTime = game.startTime; startTime = position.startTime;
currentTime = game.currentTime; currentTime = position.currentTime;
elapsedSeconds_1 = game.elapsedSeconds_1; elapsedSeconds_1 = position.elapsedSeconds_1;
elapsedSeconds_2 = game.elapsedSeconds_2; elapsedSeconds_2 = position.elapsedSeconds_2;
move_ = game.move_; move_ = position.move_;
memcpy(cmdline, game.cmdline, sizeof(cmdline)); memcpy(cmdline, position.cmdline, sizeof(cmdline));
cmdlist = game.cmdlist; cmdlist = position.cmdlist;
tips = game.tips; tips = position.tips;
return *this; return *this;
} }
int MillGame::playerToId(enum Player player) int Position::playerToId(enum Player player)
{ {
if (player == PLAYER1) if (player == PLAYER1)
return 1; return 1;
@ -87,7 +87,7 @@ int MillGame::playerToId(enum Player player)
return 0; return 0;
} }
Player MillGame::getOpponent(Player player) Player Position::getOpponent(Player player)
{ {
switch (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; 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, step_t initialStep, int flags, const char *board,
int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove) 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; 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) int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &nPiecesNeedRemove)
{ {
rule = this->currentRule; rule = this->currentRule;
@ -278,7 +278,7 @@ void MillGame::getContext(struct Rule &rule, step_t &step, int &flags,
nPiecesNeedRemove = context.nPiecesNeedRemove; nPiecesNeedRemove = context.nPiecesNeedRemove;
} }
bool MillGame::reset() bool Position::reset()
{ {
if (context.stage == GAME_NOTSTARTED && if (context.stage == GAME_NOTSTARTED &&
elapsedSeconds_1 == elapsedSeconds_2 == 0) { elapsedSeconds_1 == elapsedSeconds_2 == 0) {
@ -351,7 +351,7 @@ bool MillGame::reset()
return false; return false;
} }
bool MillGame::start() bool Position::start()
{ {
switch (context.stage) { switch (context.stage) {
// 如果游戏已经开始则返回false // 如果游戏已经开始则返回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 // 如果局面为“结局”返回false
if (context.stage == GAME_OVER) if (context.stage == GAME_OVER)
@ -556,7 +556,7 @@ out:
return true; return true;
} }
bool MillGame::_place(int r, int s, int time_p) bool Position::_place(int r, int s, int time_p)
{ {
// 转换为 location // 转换为 location
int location = context.board.polarToLocation(r, s); 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); 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 // 转换为 location
int location = context.board.polarToLocation(r, s); 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); 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 // 如果局面为"未开局"或“结局”返回false
if (context.stage == GAME_NOTSTARTED || context.stage == GAME_OVER) if (context.stage == GAME_NOTSTARTED || context.stage == GAME_OVER)
@ -714,7 +714,7 @@ out:
return true; return true;
} }
bool MillGame::choose(int location) bool Position::choose(int location)
{ {
// 如果局面不是"中局”返回false // 如果局面不是"中局”返回false
if (context.stage != GAME_MOVING) if (context.stage != GAME_MOVING)
@ -745,12 +745,12 @@ bool MillGame::choose(int location)
return false; return false;
} }
bool MillGame::choose(int r, int s) bool Position::choose(int r, int s)
{ {
return choose(context.board.polarToLocation(r, s)); return choose(context.board.polarToLocation(r, s));
} }
bool MillGame::giveup(Player loser) bool Position::giveup(Player loser)
{ {
if (context.stage == GAME_NOTSTARTED || if (context.stage == GAME_NOTSTARTED ||
context.stage == GAME_OVER || context.stage == GAME_OVER ||
@ -778,7 +778,7 @@ bool MillGame::giveup(Player loser)
} }
// 打算用个C++的命令行解析库的,简单的没必要,但中文编码有极小概率出问题 // 打算用个C++的命令行解析库的,简单的没必要,但中文编码有极小概率出问题
bool MillGame::command(const char *cmd) bool Position::command(const char *cmd)
{ {
int r, t; int r, t;
step_t s; step_t s;
@ -863,7 +863,7 @@ bool MillGame::command(const char *cmd)
return false; return false;
} }
bool MillGame::command(int move) bool Position::command(int move)
{ {
if (move < 0) { if (move < 0) {
return capture(-move); return capture(-move);
@ -880,7 +880,7 @@ bool MillGame::command(int move)
return false; return false;
} }
inline int MillGame::update(int time_p /*= -1*/) inline int Position::update(int time_p /*= -1*/)
{ {
int ret = -1; int ret = -1;
time_t *player_ms = (context.turn == PLAYER1 ? &elapsedSeconds_1 : &elapsedSeconds_2); 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); return win(false);
} }
// 是否分出胜负 // 是否分出胜负
bool MillGame::win(bool forceDraw) bool Position::win(bool forceDraw)
{ {
if (context.stage == GAME_OVER) { if (context.stage == GAME_OVER) {
return true; return true;
@ -1043,7 +1043,7 @@ bool MillGame::win(bool forceDraw)
} }
// 计算玩家1和玩家2的棋子活动能力之差 // 计算玩家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 *board = context.board.locations;
int mobility1 = 0; int mobility1 = 0;
@ -1066,7 +1066,7 @@ int MillGame::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnB
return diff; return diff;
} }
void MillGame::cleanForbiddenPoints() void Position::cleanForbiddenPoints()
{ {
int location = 0; 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; context.turn = (context.turn == PLAYER1) ? PLAYER2 : PLAYER1;
@ -1090,7 +1090,7 @@ enum Player MillGame::changeTurn()
return context.turn; return context.turn;
} }
void MillGame::setTips() void Position::setTips()
{ {
switch (context.stage) { switch (context.stage) {
case GAME_NOTSTARTED: 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(); update();
@ -1174,7 +1174,7 @@ void MillGame::getElapsedTime(time_t &p1_ms, time_t &p2_ms)
* 001 * 001
*/ */
void MillGame::constructHash() void Position::constructHash()
{ {
context.hash = 0; context.hash = 0;
@ -1182,7 +1182,7 @@ void MillGame::constructHash()
memcpy(context.zobrist, zobrist0, sizeof(hash_t) * Board::N_LOCATIONS * POINT_TYPE_COUNT); memcpy(context.zobrist, zobrist0, sizeof(hash_t) * Board::N_LOCATIONS * POINT_TYPE_COUNT);
} }
hash_t MillGame::getHash() hash_t Position::getHash()
{ {
// TODO: 每次获取哈希值时更新 hash 值低8位放在此处调用不优雅 // TODO: 每次获取哈希值时更新 hash 值低8位放在此处调用不优雅
updateHashMisc(); updateHashMisc();
@ -1190,7 +1190,7 @@ hash_t MillGame::getHash()
return context.hash; return context.hash;
} }
hash_t MillGame::updateHash(int location) hash_t Position::updateHash(int location)
{ {
// PieceType is board_[location] // PieceType is board_[location]
@ -1203,12 +1203,12 @@ hash_t MillGame::updateHash(int location)
return context.hash; return context.hash;
} }
hash_t MillGame::revertHash(int location) hash_t Position::revertHash(int location)
{ {
return updateHash(location); return updateHash(location);
} }
hash_t MillGame::updateHashMisc() hash_t Position::updateHashMisc()
{ {
// 清除标记位 // 清除标记位
context.hash &= static_cast<hash_t>(~0xFF); context.hash &= static_cast<hash_t>(~0xFF);
@ -1224,7 +1224,7 @@ hash_t MillGame::updateHashMisc()
} }
context.hash |= static_cast<hash_t>(context.nPiecesNeedRemove) << 2; context.hash |= static_cast<hash_t>(context.nPiecesNeedRemove) << 2;
context.hash |= static_cast<hash_t>(context.nPiecesInHand_1) << 4; // TODO: 或许换 game.stage 也可以? context.hash |= static_cast<hash_t>(context.nPiecesInHand_1) << 4; // TODO: 或许换 position.stage 也可以?
return context.hash; return context.hash;
} }

View File

@ -19,8 +19,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
#ifndef MILLGAME_H #ifndef POSITION_H
#define MILLGAME_H #define POSITION_H
#include <string> #include <string>
#include <cstring> #include <cstring>
@ -36,7 +36,7 @@ using namespace std;
// 棋局结构体,算法相关,包含当前棋盘数据 // 棋局结构体,算法相关,包含当前棋盘数据
// 单独分离出来供AI判断局面用生成置换表时使用 // 单独分离出来供AI判断局面用生成置换表时使用
class GameContext class PositionContext
{ {
public: public:
Board board; Board board;
@ -48,7 +48,7 @@ public:
hash_t zobrist[Board::N_LOCATIONS][POINT_TYPE_COUNT]{}; hash_t zobrist[Board::N_LOCATIONS][POINT_TYPE_COUNT]{};
// 局面阶段标识 // 局面阶段标识
enum GameStage stage; enum PositionStage stage;
// 轮流状态标识 // 轮流状态标识
enum Player turn; enum Player turn;
@ -75,9 +75,9 @@ public:
}; };
// 棋类(在数据模型内,玩家只分先后手,不分黑白) // 棋类(在数据模型内,玩家只分先后手,不分黑白)
// 注意:MillGame类不是线程安全的! // 注意:Position 类不是线程安全的!
// 所以不能跨线程修改MillGame类的静态成员变量,切记! // 所以不能跨线程修改 Position 类的静态成员变量,切记!
class MillGame class Position
{ {
// AI友元类 // AI友元类
friend class MillGameAi_ab; friend class MillGameAi_ab;
@ -111,14 +111,14 @@ private:
void constructHash(); void constructHash();
public: public:
explicit MillGame(); explicit Position();
virtual ~MillGame(); virtual ~Position();
// 拷贝构造函数 // 拷贝构造函数
explicit MillGame(const MillGame &); explicit Position(const Position &);
// 运算符重载 // 运算符重载
MillGame &operator=(const MillGame &); Position &operator=(const Position &);
// 设置配置 // 设置配置
bool configure(bool giveUpIfMostLose, bool randomMove); bool configure(bool giveUpIfMostLose, bool randomMove);
@ -188,7 +188,7 @@ public:
} }
// 获取局面阶段标识 // 获取局面阶段标识
enum GameStage getStage() const enum PositionStage getStage() const
{ {
return context.stage; return context.stage;
} }
@ -328,7 +328,7 @@ public:
public: /* TODO: move to private */ public: /* TODO: move to private */
// 棋局上下文 // 棋局上下文
GameContext context; PositionContext context;
// 当前使用的规则 // 当前使用的规则
struct Rule currentRule struct Rule currentRule
@ -404,4 +404,4 @@ private:
string tips; string tips;
}; };
#endif /* MILLGAME_H */ #endif /* POSITION_H */

View File

@ -66,7 +66,7 @@ enum Player : uint8_t
}; };
// 局面阶段标识 // 局面阶段标识
enum GameStage : uint16_t enum PositionStage : uint16_t
{ {
GAME_NONE = 0x0000, GAME_NONE = 0x0000,
GAME_NOTSTARTED = 0x0001, // 未开局 GAME_NOTSTARTED = 0x0001, // 未开局

View File

@ -117,9 +117,9 @@ const QMap<int, QStringList> GameController::getActions()
void GameController::gameStart() void GameController::gameStart()
{ {
game_.configure(giveUpIfMostLose_, randomMove_); position_.configure(giveUpIfMostLose_, randomMove_);
game_.start(); position_.start();
gameTemp = game_; dummyPosition = position_;
// 每隔100毫秒调用一次定时器处理函数 // 每隔100毫秒调用一次定时器处理函数
if (timeID == 0) { if (timeID == 0) {
@ -137,15 +137,15 @@ void GameController::gameReset()
timeID = 0; timeID = 0;
// 棋未下完,则算对手得分 // 棋未下完,则算对手得分
if (game_.getStage() == GAME_MOVING && if (position_.getStage() == GAME_MOVING &&
game_.whoWin() == PLAYER_NOBODY) { position_.whoWin() == PLAYER_NOBODY) {
giveUp(); giveUp();
} }
// 重置游戏 // 重置游戏
game_.configure(giveUpIfMostLose_, randomMove_); position_.configure(giveUpIfMostLose_, randomMove_);
game_.reset(); position_.reset();
gameTemp = game_; dummyPosition = position_;
// 停掉线程 // 停掉线程
if (!isAutoRestart) { if (!isAutoRestart) {
@ -161,7 +161,7 @@ void GameController::gameReset()
currentPiece = nullptr; currentPiece = nullptr;
// 重新绘制棋盘 // 重新绘制棋盘
scene.setDiagonal(game_.getRule()->hasObliqueLines); scene.setDiagonal(position_.getRule()->hasObliqueLines);
// 绘制所有棋子,放在起始位置 // 绘制所有棋子,放在起始位置
// 0: 先手第1子 1后手第1子 // 0: 先手第1子 1后手第1子
@ -170,7 +170,7 @@ void GameController::gameReset()
PieceItem::Models md; PieceItem::Models md;
PieceItem *newP; 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; md = isInverted ? PieceItem::whitePiece : PieceItem::blackPiece;
newP = new PieceItem; newP = new PieceItem;
@ -179,7 +179,7 @@ void GameController::gameReset()
newP->setNum(i + 1); newP->setNum(i + 1);
// 如果重复三连不可用,则显示棋子序号,九连棋专用玩法 // 如果重复三连不可用,则显示棋子序号,九连棋专用玩法
if (!(game_.getRule()->allowRemovePiecesRepeatedly)) if (!(position_.getRule()->allowRemovePiecesRepeatedly))
newP->setShowNum(true); newP->setShowNum(true);
pieceList.append(newP); pieceList.append(newP);
@ -193,7 +193,7 @@ void GameController::gameReset()
newP->setNum(i + 1); newP->setNum(i + 1);
// 如果重复三连不可用,则显示棋子序号,九连棋专用玩法 // 如果重复三连不可用,则显示棋子序号,九连棋专用玩法
if (!(game_.getRule()->allowRemovePiecesRepeatedly)) if (!(position_.getRule()->allowRemovePiecesRepeatedly))
newP->setShowNum(true); newP->setShowNum(true);
pieceList.append(newP); pieceList.append(newP);
@ -201,7 +201,7 @@ void GameController::gameReset()
} }
// 读取规则限时要求 // 读取规则限时要求
timeLimit = game_.getRule()->maxTimeLedToLose; timeLimit = position_.getRule()->maxTimeLedToLose;
// 如果规则不要求计时则time1和time2表示已用时间 // 如果规则不要求计时则time1和time2表示已用时间
if (timeLimit <= 0) { if (timeLimit <= 0) {
@ -215,7 +215,7 @@ void GameController::gameReset()
// 更新棋谱 // 更新棋谱
manualListModel.removeRows(0, manualListModel.rowCount()); manualListModel.removeRows(0, manualListModel.rowCount());
manualListModel.insertRow(0); manualListModel.insertRow(0);
manualListModel.setData(manualListModel.index(0), game_.getCmdLine()); manualListModel.setData(manualListModel.index(0), position_.getCmdLine());
currentRow = 0; currentRow = 0;
// 发出信号通知主窗口更新LCD显示 // 发出信号通知主窗口更新LCD显示
@ -224,13 +224,13 @@ void GameController::gameReset()
emit time2Changed(qtime.toString("hh:mm:ss")); emit time2Changed(qtime.toString("hh:mm:ss"));
// 发信号更新状态栏 // 发信号更新状态栏
message = QString::fromStdString(game_.getTips()); message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message); emit statusBarChanged(message);
// 更新比分 LCD 显示 // 更新比分 LCD 显示
emit score1Changed(QString::number(game_.score_1, 10)); emit score1Changed(QString::number(position_.score_1, 10));
emit score2Changed(QString::number(game_.score_2, 10)); emit score2Changed(QString::number(position_.score_2, 10));
emit scoreDrawChanged(QString::number(game_.score_draw, 10)); emit scoreDrawChanged(QString::number(position_.score_draw, 10));
// 播放音效 // 播放音效
//playSound(":/sound/resources/sound/newgame.wav"); //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); position_.setContext(&RULES[ruleNo], stepsLimit, timeLimit);
gameTemp = game_; dummyPosition = position_;
// 重置游戏 // 重置游戏
gameReset(); gameReset();
@ -284,11 +284,11 @@ void GameController::setRule(int ruleNo, step_t stepLimited /*= -1*/, int timeLi
void GameController::setEngine1(bool arg) void GameController::setEngine1(bool arg)
{ {
game_.configure(giveUpIfMostLose_, randomMove_); position_.configure(giveUpIfMostLose_, randomMove_);
isAiPlayer1 = arg; isAiPlayer1 = arg;
if (arg) { if (arg) {
ai1.setAi(game_); ai1.setAi(position_);
if (ai1.isRunning()) if (ai1.isRunning())
ai1.resume(); ai1.resume();
else else
@ -300,11 +300,11 @@ void GameController::setEngine1(bool arg)
void GameController::setEngine2(bool arg) void GameController::setEngine2(bool arg)
{ {
game_.configure(giveUpIfMostLose_, randomMove_); position_.configure(giveUpIfMostLose_, randomMove_);
isAiPlayer2 = arg; isAiPlayer2 = arg;
if (arg) { if (arg) {
ai2.setAi(game_); ai2.setAi(position_);
if (ai2.isRunning()) if (ai2.isRunning())
ai2.resume(); ai2.resume();
else else
@ -325,8 +325,8 @@ void GameController::setAiDepthTime(depth_t depth1, int time1, depth_t depth2, i
ai2.wait(); ai2.wait();
} }
ai1.setAi(game_, depth1, time1); ai1.setAi(position_, depth1, time1);
ai2.setAi(game_, depth2, time2); ai2.setAi(position_, depth2, time2);
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.start(); ai1.start();
@ -398,13 +398,13 @@ void GameController::flip()
ai2.wait(); ai2.wait();
} }
game_.context.board.mirror(game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
game_.context.board.rotate(180, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); position_.context.board.rotate(180, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
gameTemp = game_; dummyPosition = position_;
// 更新棋谱 // 更新棋谱
int row = 0; int row = 0;
for (const auto &str : *(game_.getCmdList())) { for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str()); manualListModel.setData(manualListModel.index(row++), str.c_str());
} }
@ -414,8 +414,8 @@ void GameController::flip()
else else
stageChange(currentRow, true); stageChange(currentRow, true);
ai1.setAi(game_); ai1.setAi(position_);
ai2.setAi(game_); ai2.setAi(position_);
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.start(); ai1.start();
@ -438,13 +438,13 @@ void GameController::mirror()
ai2.wait(); ai2.wait();
} }
game_.context.board.mirror(game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
gameTemp = game_; dummyPosition = position_;
// 更新棋谱 // 更新棋谱
int row = 0; int row = 0;
for (const auto &str : *(game_.getCmdList())) { for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str()); manualListModel.setData(manualListModel.index(row++), str.c_str());
} }
@ -456,8 +456,8 @@ void GameController::mirror()
else else
stageChange(currentRow, true); stageChange(currentRow, true);
ai1.setAi(game_); ai1.setAi(position_);
ai2.setAi(game_); ai2.setAi(position_);
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.start(); ai1.start();
@ -480,13 +480,13 @@ void GameController::turnRight()
ai2.wait(); ai2.wait();
} }
game_.context.board.rotate(-90, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); position_.context.board.rotate(-90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
gameTemp = game_; dummyPosition = position_;
// 更新棋谱 // 更新棋谱
int row = 0; int row = 0;
for (const auto &str : *(game_.getCmdList())) { for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str()); manualListModel.setData(manualListModel.index(row++), str.c_str());
} }
@ -496,8 +496,8 @@ void GameController::turnRight()
else else
stageChange(currentRow, true); stageChange(currentRow, true);
ai1.setAi(game_); ai1.setAi(position_);
ai2.setAi(game_); ai2.setAi(position_);
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.start(); ai1.start();
@ -520,20 +520,20 @@ void GameController::turnLeft()
ai2.wait(); ai2.wait();
} }
game_.context.board.rotate(90, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation); position_.context.board.rotate(90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
gameTemp = game_; dummyPosition = position_;
// 更新棋谱 // 更新棋谱
int row = 0; int row = 0;
for (const auto &str : *(game_.getCmdList())) { for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str()); manualListModel.setData(manualListModel.index(row++), str.c_str());
} }
// 刷新显示 // 刷新显示
updateScence(); updateScence();
ai1.setAi(game_); ai1.setAi(position_);
ai2.setAi(game_); ai2.setAi(position_);
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.start(); ai1.start();
} }
@ -548,7 +548,7 @@ void GameController::timerEvent(QTimerEvent *event)
static QTime qt1, qt2; static QTime qt1, qt2;
// 玩家的已用时间 // 玩家的已用时间
game_.getElapsedTime(remainingTime1, remainingTime2); position_.getElapsedTime(remainingTime1, remainingTime2);
// 如果规则要求计时则time1和time2表示倒计时 // 如果规则要求计时则time1和time2表示倒计时
if (timeLimit > 0) { if (timeLimit > 0) {
@ -564,7 +564,7 @@ void GameController::timerEvent(QTimerEvent *event)
emit time2Changed(qt2.toString("hh:mm:ss")); emit time2Changed(qt2.toString("hh:mm:ss"));
// 如果胜负已分 // 如果胜负已分
if (game_.whoWin() != PLAYER_NOBODY) { if (position_.whoWin() != PLAYER_NOBODY) {
// 停止计时 // 停止计时
killTimer(timeID); killTimer(timeID);
@ -572,7 +572,7 @@ void GameController::timerEvent(QTimerEvent *event)
timeID = 0; timeID = 0;
// 发信号更新状态栏 // 发信号更新状态栏
message = QString::fromStdString(game_.getTips()); message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message); emit statusBarChanged(message);
// 弹框 // 弹框
@ -609,8 +609,8 @@ void GameController::timerEvent(QTimerEvent *event)
bool GameController::isAIsTurn() bool GameController::isAIsTurn()
{ {
return ((game_.whosTurn() == PLAYER1 && isAiPlayer1) || return ((position_.whosTurn() == PLAYER1 && isAiPlayer1) ||
(game_.whosTurn() == PLAYER2 && isAiPlayer2)); (position_.whosTurn() == PLAYER2 && isAiPlayer2));
} }
// 关键槽函数根据QGraphicsScene的信号和状态来执行选子、落子或去子 // 关键槽函数根据QGraphicsScene的信号和状态来执行选子、落子或去子
@ -643,17 +643,17 @@ bool GameController::actionPiece(QPointF pos)
if (QMessageBox::Ok == msgBox.exec()) { if (QMessageBox::Ok == msgBox.exec()) {
#endif /* !MOBILE_APP_UI */ #endif /* !MOBILE_APP_UI */
game_ = gameTemp; position_ = dummyPosition;
manualListModel.removeRows(currentRow + 1, manualListModel.rowCount() - currentRow - 1); manualListModel.removeRows(currentRow + 1, manualListModel.rowCount() - currentRow - 1);
// 如果再决出胜负后悔棋,则重新启动计时 // 如果再决出胜负后悔棋,则重新启动计时
if (game_.whoWin() == PLAYER_NOBODY) { if (position_.whoWin() == PLAYER_NOBODY) {
// 重新启动计时 // 重新启动计时
timeID = startTimer(100); timeID = startTimer(100);
// 发信号更新状态栏 // 发信号更新状态栏
message = QString::fromStdString(game_.getTips()); message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message); emit statusBarChanged(message);
#ifndef MOBILE_APP_UI #ifndef MOBILE_APP_UI
} }
@ -664,7 +664,7 @@ bool GameController::actionPiece(QPointF pos)
} }
// 如果未开局则开局 // 如果未开局则开局
if (game_.getStage() == GAME_NOTSTARTED) if (position_.getStage() == GAME_NOTSTARTED)
gameStart(); gameStart();
// 判断执行选子、落子或去子 // 判断执行选子、落子或去子
@ -672,10 +672,10 @@ bool GameController::actionPiece(QPointF pos)
PieceItem *piece = nullptr; PieceItem *piece = nullptr;
QGraphicsItem *item = scene.itemAt(pos, QTransform()); QGraphicsItem *item = scene.itemAt(pos, QTransform());
switch (game_.getAction()) { switch (position_.getAction()) {
case ACTION_PLACE: case ACTION_PLACE:
if (game_._place(r, s)) { if (position_._place(r, s)) {
if (game_.getAction() == ACTION_CAPTURE) { if (position_.getAction() == ACTION_CAPTURE) {
// 播放成三音效 // 播放成三音效
playSound(":/sound/resources/sound/capture.wav"); playSound(":/sound/resources/sound/capture.wav");
} else { } else {
@ -693,7 +693,7 @@ bool GameController::actionPiece(QPointF pos)
piece = qgraphicsitem_cast<PieceItem *>(item); piece = qgraphicsitem_cast<PieceItem *>(item);
if (!piece) if (!piece)
break; break;
if (game_.choose(r, s)) { if (position_.choose(r, s)) {
// 播放选子音效 // 播放选子音效
playSound(":/sound/resources/sound/choose.wav"); playSound(":/sound/resources/sound/choose.wav");
result = true; result = true;
@ -704,7 +704,7 @@ bool GameController::actionPiece(QPointF pos)
break; break;
case ACTION_CAPTURE: case ACTION_CAPTURE:
if (game_._capture(r, s)) { if (position_._capture(r, s)) {
// 播放音效 // 播放音效
playSound(":/sound/resources/sound/remove.wav"); playSound(":/sound/resources/sound/remove.wav");
result = true; result = true;
@ -721,7 +721,7 @@ bool GameController::actionPiece(QPointF pos)
if (result) { if (result) {
// 发信号更新状态栏 // 发信号更新状态栏
message = QString::fromStdString(game_.getTips()); message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message); emit statusBarChanged(message);
// 将新增的棋谱行插入到ListModel // 将新增的棋谱行插入到ListModel
@ -729,7 +729,7 @@ bool GameController::actionPiece(QPointF pos)
int k = 0; int k = 0;
// 输出命令行 // 输出命令行
for (const auto & i : *(game_.getCmdList())) { for (const auto & i : *(position_.getCmdList())) {
// 跳过已添加的因标准list容器没有下标 // 跳过已添加的因标准list容器没有下标
if (k++ <= currentRow) if (k++ <= currentRow)
continue; continue;
@ -739,16 +739,16 @@ bool GameController::actionPiece(QPointF pos)
// 播放胜利或失败音效 // 播放胜利或失败音效
#ifndef DONOT_PLAY_WIN_SOUND #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.")) (manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over."))
playSound(":/sound/resources/sound/win.wav"); playSound(":/sound/resources/sound/win.wav");
#endif #endif
// AI设置 // AI设置
if (&game_ == &(this->game_)) { if (&position_ == &(this->position_)) {
// 如果还未决出胜负 // 如果还未决出胜负
if (game_.whoWin() == PLAYER_NOBODY) { if (position_.whoWin() == PLAYER_NOBODY) {
if (game_.whosTurn() == PLAYER1) { if (position_.whosTurn() == PLAYER1) {
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.resume(); ai1.resume();
} }
@ -768,7 +768,7 @@ bool GameController::actionPiece(QPointF pos)
ai2.stop(); ai2.stop();
// 弹框 // 弹框
//message = QString::fromStdString(game_.getTips()); //message = QString::fromStdString(position_.getTips());
//QMessageBox::about(NULL, "游戏结果", message); //QMessageBox::about(NULL, "游戏结果", message);
} }
} }
@ -782,11 +782,11 @@ bool GameController::giveUp()
{ {
bool result = false; bool result = false;
if (game_.whosTurn() == PLAYER1) { if (position_.whosTurn() == PLAYER1) {
result = game_.giveup(PLAYER1); result = position_.giveup(PLAYER1);
} }
else if (game_.whosTurn() == PLAYER2) { else if (position_.whosTurn() == PLAYER2) {
result = game_.giveup(PLAYER2); result = position_.giveup(PLAYER2);
} }
if (result) { if (result) {
@ -795,14 +795,14 @@ bool GameController::giveUp()
int k = 0; int k = 0;
// 输出命令行 // 输出命令行
for (const auto & i : *(game_.getCmdList())) { for (const auto & i : *(position_.getCmdList())) {
// 跳过已添加的因标准list容器没有下标 // 跳过已添加的因标准list容器没有下标
if (k++ <= currentRow) if (k++ <= currentRow)
continue; continue;
manualListModel.insertRow(++currentRow); manualListModel.insertRow(++currentRow);
manualListModel.setData(manualListModel.index(currentRow), i.c_str()); manualListModel.setData(manualListModel.index(currentRow), i.c_str());
} }
if (game_.whoWin() != PLAYER_NOBODY) if (position_.whoWin() != PLAYER_NOBODY)
playSound(":/sound/resources/sound/loss.wav"); playSound(":/sound/resources/sound/loss.wav");
} }
@ -824,7 +824,7 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
// 声音 // 声音
QString sound; QString sound;
switch (game_.getAction()) { switch (position_.getAction()) {
case ACTION_CHOOSE: case ACTION_CHOOSE:
case ACTION_PLACE: case ACTION_PLACE:
sound = ":/sound/resources/sound/drog.wav"; 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(); gameStart();
} }
if (!game_.command(cmd.toStdString().c_str())) if (!position_.command(cmd.toStdString().c_str()))
return false; 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"; sound = ":/sound/resources/sound/capture.wav";
} }
if (update) { if (update) {
playSound(sound); playSound(sound);
updateScence(game_); updateScence(position_);
} }
// 发信号更新状态栏 // 发信号更新状态栏
message = QString::fromStdString(game_.getTips()); message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message); emit statusBarChanged(message);
// 对于新开局 // 对于新开局
if (game_.getCmdList()->size() <= 1) { if (position_.getCmdList()->size() <= 1) {
manualListModel.removeRows(0, manualListModel.rowCount()); manualListModel.removeRows(0, manualListModel.rowCount());
manualListModel.insertRow(0); manualListModel.insertRow(0);
manualListModel.setData(manualListModel.index(0), game_.getCmdLine()); manualListModel.setData(manualListModel.index(0), position_.getCmdLine());
currentRow = 0; currentRow = 0;
} }
// 对于当前局 // 对于当前局
else { else {
currentRow = manualListModel.rowCount() - 1; currentRow = manualListModel.rowCount() - 1;
// 跳过已添加行,迭代器不支持+运算符,只能一个个++ // 跳过已添加行,迭代器不支持+运算符,只能一个个++
auto i = (game_.getCmdList()->begin()); auto i = (position_.getCmdList()->begin());
for (int r = 0; i != (game_.getCmdList())->end(); i++) { for (int r = 0; i != (position_.getCmdList())->end(); i++) {
if (r++ > currentRow) if (r++ > currentRow)
break; break;
} }
// 将新增的棋谱行插入到ListModel // 将新增的棋谱行插入到ListModel
while (i != game_.getCmdList()->end()) { while (i != position_.getCmdList()->end()) {
manualListModel.insertRow(++currentRow); manualListModel.insertRow(++currentRow);
manualListModel.setData(manualListModel.index(currentRow), (*i++).c_str()); 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 #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.")) { (manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over.")) {
playSound(":/sound/resources/sound/win.wav"); playSound(":/sound/resources/sound/win.wav");
} }
#endif #endif
// AI设置 // AI设置
if (&game_ == &(this->game_)) { if (&position_ == &(this->position_)) {
// 如果还未决出胜负 // 如果还未决出胜负
if (game_.whoWin() == PLAYER_NOBODY) { if (position_.whoWin() == PLAYER_NOBODY) {
if (game_.whosTurn() == PLAYER1) { if (position_.whosTurn() == PLAYER1) {
if (isAiPlayer1) { if (isAiPlayer1) {
ai1.resume(); ai1.resume();
} }
@ -925,7 +925,7 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
#ifdef MESSAGEBOX_ENABLE #ifdef MESSAGEBOX_ENABLE
// 弹框 // 弹框
message = QString::fromStdString(game_.getTips()); message = QString::fromStdString(position_.getTips());
QMessageBox::about(NULL, "游戏结果", message); QMessageBox::about(NULL, "游戏结果", message);
#endif #endif
} }
@ -958,24 +958,24 @@ bool GameController::stageChange(int row, bool forceUpdate)
for (int i = 0; i <= row; i++) { for (int i = 0; i <= row; i++) {
loggerDebug("%s\n", mlist.at(i).toStdString().c_str()); 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; return true;
} }
bool GameController::updateScence() bool GameController::updateScence()
{ {
return updateScence(game_); return updateScence(position_);
} }
bool GameController::updateScence(MillGame &game) bool GameController::updateScence(Position &game)
{ {
const int *board = game.getBoard(); const int *board = game.getBoard();
QPointF pos; QPointF pos;

View File

@ -192,7 +192,7 @@ public slots:
// 更新棋局显示,每步后执行才能刷新局面 // 更新棋局显示,每步后执行才能刷新局面
bool updateScence(); bool updateScence();
bool updateScence(MillGame &game); bool updateScence(Position &game);
// 显示网络配置窗口 // 显示网络配置窗口
void showNetworkWindow(); void showNetworkWindow();
@ -204,10 +204,10 @@ protected:
private: private:
// 棋对象的数据模型 // 棋对象的数据模型
MillGame game_; Position position_;
// 棋对象的数据模型(临时) // 棋对象的数据模型(临时)
MillGame gameTemp; Position dummyPosition;
// 2个AI的线程 // 2个AI的线程
AiThread ai1, ai2; AiThread ai1, ai2;