优化 addNode 函数性能

Release 自对弈一方的时间从30s缩短到15s
某个着法深度为8时,从原来的 47.405 s 缩短到 34.072 s,节省 30 % 耗时
This commit is contained in:
CalciteM 2019-07-07 21:37:06 +08:00
parent 96e9ae565f
commit d32ff9bbff
1 changed files with 20 additions and 21 deletions

View File

@ -41,7 +41,7 @@ void NineChessAi_ab::buildRoot()
struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, int move, enum NineChess::Player player) struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, int move, enum NineChess::Player player)
{ {
Node *newNode = new Node; Node *newNode = new Node; // (10%)
newNode->parent = parent; newNode->parent = parent;
newNode->value = value; newNode->value = value;
newNode->move = move; newNode->move = move;
@ -49,7 +49,7 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in
nodeCount++; nodeCount++;
newNode->id = nodeCount; newNode->id = nodeCount;
newNode->rand = rand() % 24; newNode->rand = rand() % 24; // (1%)
newNode->pruned = false; newNode->pruned = false;
@ -67,29 +67,28 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in
newNode->result = 0; newNode->result = 0;
newNode->isHash = false; newNode->isHash = false;
newNode->visited = false; newNode->visited = false;
#endif
int c, p; int c, p;
char cmd[32] = { 0 }; char cmd[32] = { 0 };
if (move < 0) { if (move < 0) {
chessTemp.pos2cp(-move, c, p); chessTemp.pos2cp(-move, c, p);
sprintf(cmd, "-(%1u,%1u)", c, p); sprintf(cmd, "-(%1u,%1u)", c, p); // (3%)
} else if (move & 0x7f00) { } else if (move & 0x7f00) {
int c1, p1; int c1, p1;
chessTemp.pos2cp(move >> 8, c1, p1); chessTemp.pos2cp(move >> 8, c1, p1);
chessTemp.pos2cp(move & 0x00ff, c, p); chessTemp.pos2cp(move & 0x00ff, c, p);
sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", c1, p1, c, p); sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", c1, p1, c, p); // (7%)
} else { } else {
chessTemp.pos2cp(move & 0x007f, c, p); chessTemp.pos2cp(move & 0x007f, c, p);
sprintf(cmd, "(%1u,%1u)", c, p); sprintf(cmd, "(%1u,%1u)", c, p); // (12%)
} }
#ifdef DEBUG_AB_TREE
newNode->cmd = cmd; newNode->cmd = cmd;
#endif #endif
if (parent) if (parent)
parent->children.push_back(newNode); parent->children.push_back(newNode); // (7%)
return newNode; return newNode;
} }
@ -144,7 +143,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
addNode(node, INF_VALUE, pos, chessTemp.context.turn); addNode(node, INF_VALUE, pos, chessTemp.context.turn);
} }
} else { } else {
addNode(node, 0, pos, chessTemp.context.turn); addNode(node, 0, pos, chessTemp.context.turn); // (24%)
} }
} }
} }
@ -174,7 +173,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
newPos = chessTemp.moveTable[oldPos][moveDirection]; newPos = chessTemp.moveTable[oldPos][moveDirection];
if (newPos && !chessTemp.board_[newPos]) { if (newPos && !chessTemp.board_[newPos]) {
int move = (oldPos << 8) + newPos; int move = (oldPos << 8) + newPos;
addNode(node, 0, move, chessTemp.context.turn); addNode(node, 0, move, chessTemp.context.turn); // (12%)
} }
} }
} else { } else {
@ -206,7 +205,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
pos = movePriorityTable[i]; pos = movePriorityTable[i];
if (chessTemp.board_[pos] & opponent) { if (chessTemp.board_[pos] & opponent) {
if (chessTemp.getRule()->allowRemoveMill || !chessTemp.isInMills(pos)) { if (chessTemp.getRule()->allowRemoveMill || !chessTemp.isInMills(pos)) {
addNode(node, 0, -pos, chessTemp.context.turn); addNode(node, 0, -pos, chessTemp.context.turn); // (6%)
} }
} }
} }
@ -251,9 +250,9 @@ void NineChessAi_ab::sortLegalMoves(Node *node)
#else #else
if (chessTemp.whosTurn() == NineChess::PLAYER1) { if (chessTemp.whosTurn() == NineChess::PLAYER1) {
node->children.sort([](Node *n1, Node *n2) {return n1->value > n2->value; }); node->children.sort([](Node *n1, Node *n2) {return n1->value > n2->value; }); // (6%)
} else { } else {
node->children.sort([](Node *n1, Node *n2) { return n1->value < n2->value; }); node->children.sort([](Node *n1, Node *n2) { return n1->value < n2->value; }); // (6%)
} }
#if 0 #if 0
@ -670,7 +669,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
} }
// 生成子节点树,即生成每个合理的着法 // 生成子节点树,即生成每个合理的着法
generateLegalMoves(node); generateLegalMoves(node); // (43%)
// 排序子节点树 // 排序子节点树
//sortChildren(node); //sortChildren(node);
@ -681,10 +680,10 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
for (auto child : node->children) { for (auto child : node->children) {
// 上下文入栈保存,以便后续撤销着法 // 上下文入栈保存,以便后续撤销着法
contextStack.push(chessTemp.context); contextStack.push(chessTemp.context); // (7%)
// 执行着法 // 执行着法
chessTemp.command(child->move); chessTemp.command(child->move); // (13%)
#ifdef DEAL_WITH_HORIZON_EFFECT #ifdef DEAL_WITH_HORIZON_EFFECT
// 克服“水平线效应”: 若遇到吃子,则搜索深度增加 // 克服“水平线效应”: 若遇到吃子,则搜索深度增加
@ -697,10 +696,10 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
#endif #endif
// 递归 Alpha-Beta 剪枝 // 递归 Alpha-Beta 剪枝
value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child); value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child); // (98%)
// 上下文弹出栈,撤销着法 // 上下文弹出栈,撤销着法
chessTemp.context = contextStack.top(); chessTemp.context = contextStack.top(); // (5%)
contextStack.pop(); contextStack.pop();
if (chessTemp.whosTurn() == NineChess::PLAYER1) { if (chessTemp.whosTurn() == NineChess::PLAYER1) {
@ -753,8 +752,8 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
#ifndef DEBUG_AB_TREE #ifndef DEBUG_AB_TREE
for (auto child : node->children) { for (auto child : node->children) {
for (auto grandChild : child->children) for (auto grandChild : child->children)
deleteTree(grandChild); deleteTree(grandChild); // (9%)
child->children.clear(); child->children.clear(); // (3%)
} }
#endif #endif
@ -775,7 +774,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
#endif #endif
// 排序子节点树 // 排序子节点树
sortLegalMoves(node); sortLegalMoves(node); // (13%)
// 返回 // 返回
return node->value; return node->value;