ai: 搜索时不再生成结点而是遍历着法数组即可

修改后,即便是关闭预取,也能提速 15%。
This commit is contained in:
Calcitem 2020-05-05 01:54:38 +08:00
parent b8cd08e204
commit 6399e03a36
9 changed files with 250 additions and 174 deletions

View File

@ -20,7 +20,7 @@
#include "evaluate.h"
#ifdef ALPHABETA_AI
value_t Evaluation::getValue(Position *position, Node *node)
value_t Evaluation::getValue(Position *position)
{
// 初始评估值为0对先手有利则增大对后手有利则减小
value_t value = VALUE_ZERO;
@ -29,12 +29,6 @@ value_t Evaluation::getValue(Position *position, Node *node)
int nPiecesOnBoardDiff;
int nPiecesNeedRemove;
#ifdef DEBUG_AB_TREE
node->phase = position->phase;
node->action = position->action;
node->evaluated = true;
#endif
switch (position->phase) {
case PHASE_READY:
break;
@ -43,16 +37,10 @@ value_t Evaluation::getValue(Position *position, Node *node)
// 按手中的棋子计分不要break;
nPiecesInHandDiff = position->nPiecesInHand[BLACK] - position->nPiecesInHand[WHITE];
value += nPiecesInHandDiff * VALUE_EACH_PIECE_INHAND;
#ifdef DEBUG_AB_TREE
node->nPiecesInHandDiff = nPiecesInHandDiff;
#endif
// 按场上棋子计分
nPiecesOnBoardDiff = position->nPiecesOnBoard[BLACK] - position->nPiecesOnBoard[WHITE];
value += nPiecesOnBoardDiff * VALUE_EACH_PIECE_ONBOARD;
#ifdef DEBUG_AB_TREE
node->nPiecesOnBoardDiff = nPiecesOnBoardDiff;
#endif
switch (position->action) {
// 选子和落子使用相同的评价方法
@ -65,9 +53,6 @@ value_t Evaluation::getValue(Position *position, Node *node)
nPiecesNeedRemove = (position->sideToMove == PLAYER_BLACK) ?
position->nPiecesNeedRemove : -(position->nPiecesNeedRemove);
value += nPiecesNeedRemove * VALUE_EACH_PIECE_PLACING_NEEDREMOVE;
#ifdef DEBUG_AB_TREE
node->nPiecesNeedRemove = nPiecesNeedRemove;
#endif
break;
default:
break;
@ -96,9 +81,6 @@ value_t Evaluation::getValue(Position *position, Node *node)
nPiecesNeedRemove = (position->sideToMove == PLAYER_BLACK) ?
position->nPiecesNeedRemove : -(position->nPiecesNeedRemove);
value += nPiecesNeedRemove * VALUE_EACH_PIECE_MOVING_NEEDREMOVE;
#ifdef DEBUG_AB_TREE
node->nPiecesNeedRemove = nPiecesNeedRemove;
#endif
break;
default:
break;
@ -144,8 +126,6 @@ value_t Evaluation::getValue(Position *position, Node *node)
value = -value;
}
// 赋值返回
node->value = value;
return value;
}
#endif // ALPHABETA_AI

View File

@ -32,7 +32,7 @@ public:
Evaluation &operator=(const Evaluation &) = delete;
static value_t getValue(Position *Position, Node *node);
static value_t getValue(Position *Position);
// 评估子力
#ifdef EVALUATE_ENABLE

View File

@ -442,7 +442,7 @@ void MoveList::shuffle()
/// generate<LEGAL> generates all the legal moves in the given position
//template<>
ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
ExtMove *generate(/* TODO: const */ Position *position, ExtMove *moveList)
{
square_t square;
player_t opponent;
@ -451,24 +451,24 @@ ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
ExtMove *cur = moveList;
// 列出所有合法的下一招
switch (position.action) {
switch (position->action) {
// 对于选子和落子动作
case ACTION_CHOOSE:
case ACTION_PLACE:
// 对于摆子阶段
if (position.phase & (PHASE_PLACING | PHASE_READY)) {
if (position->phase & (PHASE_PLACING | PHASE_READY)) {
for (move_t i : MoveList::movePriorityTable) {
square = static_cast<square_t>(i);
// 如果已经有子占据, 继续检索
if (position.board.locations[square]) {
if (position->board.locations[square]) {
continue;
}
#ifdef MCTS_AI
moves.push_back((move_t)square);
#else // MCTS_AI
if (position.phase != PHASE_READY) {
if (position->phase != PHASE_READY) {
*cur++ = ((move_t)square);
} else {
// 若为先手,则抢占星位
@ -486,24 +486,24 @@ ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
}
// 对于移子阶段
if (position.phase & PHASE_MOVING) {
if (position->phase & PHASE_MOVING) {
square_t newSquare, oldSquare;
// 尽量走理论上较差的位置的棋子
for (int i = Board::MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
oldSquare = static_cast<square_t>(MoveList::movePriorityTable[i]);
if (!position.choose(oldSquare)) {
if (!position->choose(oldSquare)) {
continue;
}
if (position.nPiecesOnBoard[position.sideId] > rule.nPiecesAtLeast ||
if (position->nPiecesOnBoard[position->sideId] > rule.nPiecesAtLeast ||
!rule.allowFlyWhenRemainThreePieces) {
// 对于棋盘上还有3个子以上或不允许飞子的情况要求必须在着法表中
for (int direction = DIRECTION_BEGIN; direction < DIRECTIONS_COUNT; direction++) {
// 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中
newSquare = static_cast<square_t>(MoveList::moveTable[oldSquare][direction]);
if (newSquare && !position.board.locations[newSquare]) {
if (newSquare && !position->board.locations[newSquare]) {
move_t m = move_t((oldSquare << 8) + newSquare);
*cur++ = ((move_t)m);
}
@ -511,7 +511,7 @@ ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
} else {
// 对于棋盘上还有不到3个字但允许飞子的情况不要求在着法表中是空位就行
for (newSquare = SQ_BEGIN; newSquare < SQ_END; newSquare = static_cast<square_t>(newSquare + 1)) {
if (!position.board.locations[newSquare]) {
if (!position->board.locations[newSquare]) {
move_t m = move_t((oldSquare << 8) + newSquare);
*cur++ = ((move_t)m);
}
@ -523,13 +523,13 @@ ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
// 对于吃子动作
case ACTION_CAPTURE:
opponent = Player::getOpponent(position.sideToMove);
opponent = Player::getOpponent(position->sideToMove);
if (position.board.isAllInMills(opponent)) {
if (position->board.isAllInMills(opponent)) {
// 全成三的情况
for (int i = Board::MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
square = static_cast<square_t>(MoveList::movePriorityTable[i]);
if (position.board.locations[square] & opponent) {
if (position->board.locations[square] & opponent) {
*cur++ = ((move_t)-square);
}
}
@ -539,8 +539,8 @@ ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
// 不是全成三的情况
for (int i = Board::MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
square = static_cast<square_t>(MoveList::movePriorityTable[i]);
if (position.board.locations[square] & opponent) {
if (rule.allowRemoveMill || !position.board.inHowManyMills(square, PLAYER_NOBODY)) {
if (position->board.locations[square] & opponent) {
if (rule.allowRemoveMill || !position->board.inHowManyMills(square, PLAYER_NOBODY)) {
*cur++ = ((move_t)-square);
}
}
@ -552,6 +552,6 @@ ExtMove *generate(/* TODO: const */ Position &position, ExtMove *moveList)
break;
}
return moveList;
return cur;
}

View File

@ -24,16 +24,20 @@
#include "position.h"
#include "search.h"
class Position;
enum GenType
{
CAPTURES,
LEGAL
};
struct ExtMove
class ExtMove
{
public:
move_t move;
value_t value;
rating_t rating;
operator move_t() const
{
@ -52,11 +56,12 @@ struct ExtMove
inline bool operator < (const ExtMove &first, const ExtMove &second)
{
return first.value < second.value;
//return first.value < second.value;
return first.rating < second.rating;
}
//template <GenType>
ExtMove *generate(const Position &pos, ExtMove *moveList);
ExtMove *generate(Position *pos, ExtMove *moveList);
/// The MoveList struct is a simple wrapper around generate(). It sometimes comes
/// in handy to use this class instead of the low level generate() function.
@ -85,9 +90,9 @@ public:
};
//explicit MoveList(const Position &pos) : last(generate<T>(pos, moveList))
explicit MoveList(const Position &pos) : last(generate(pos, moveList))
{
}
// explicit MoveList(const Position &pos) : last(generate(pos, moveList))
// {
// }
const ExtMove *begin() const
{

View File

@ -22,13 +22,151 @@
#include "types.h"
#include "config.h"
MovePicker::MovePicker()
// partial_insertion_sort() sorts moves in descending order up to and including
// a given limit. The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove *begin, ExtMove *end, int limit)
{
for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p)
if (p->value >= limit) {
ExtMove tmp = *p, *q;
*p = *++sortedEnd;
for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
*q = *(q - 1);
*q = tmp;
}
}
MovePicker::MovePicker(Position *pos, ExtMove *extMove)
{
position = pos;
cur = extMove;
#ifdef HOSTORY_HEURISTIC
clearHistoryScore();
#endif
}
void MovePicker::score()
{
while (cur++->move != MOVE_NONE) {
move_t m = cur->move;
square_t sq = SQ_0;
square_t sqsrc = SQ_0;
if (m > 0) {
if (m & 0x1f00) {
// 走子
sqsrc = static_cast<square_t>(m >> 8);
}
// 摆子或走子
sq = static_cast<square_t>(m & 0x00ff);
} else {
// 吃子
sq = static_cast<square_t>((-m) & 0x00ff);
}
// 若为走子之前的统计故走棋阶段可能会从 @-0-@ 走成 0-@-@, 并未成三,所以需要传值 sqsrc 进行判断
int nMills = position->board.inHowManyMills(sq, position->sideToMove, sqsrc);
int nopponentMills = 0;
#ifdef SORT_MOVE_WITH_HUMAN_KNOWLEDGES
// TODO: rule.allowRemoveMultiPieces 以及 适配打三棋之外的其他规则
if (m > 0) {
// 在任何阶段, 都检测落子点是否能使得本方成三
if (nMills > 0) {
#ifdef ALPHABETA_AI
cur->rating += static_cast<rating_t>(RATING_ONE_MILL * nMills);
#endif
} else if (position->getPhase() == PHASE_PLACING) {
// 在摆棋阶段, 检测落子点是否能阻止对方成三
nopponentMills = position->board.inHowManyMills(sq, position->opponent);
#ifdef ALPHABETA_AI
cur->rating += static_cast<rating_t>(RATING_BLOCK_ONE_MILL * nopponentMills);
#endif
}
#if 1
else if (position->getPhase() == PHASE_MOVING) {
// 在走棋阶段, 检测落子点是否能阻止对方成三
nopponentMills = position->board.inHowManyMills(sq, position->opponent);
if (nopponentMills) {
int nPlayerPiece = 0;
int nOpponentPiece = 0;
int nForbidden = 0;
int nEmpty = 0;
position->board.getSurroundedPieceCount(sq, position->sideId,
nPlayerPiece, nOpponentPiece, nForbidden, nEmpty);
#ifdef ALPHABETA_AI
if (sq % 2 == 0 && nOpponentPiece == 3) {
cur->rating += static_cast<rating_t>(RATING_BLOCK_ONE_MILL * nopponentMills);
} else if (sq % 2 == 1 && nOpponentPiece == 2 && rule.nTotalPiecesEachSide == 12) {
cur->rating += static_cast<rating_t>(RATING_BLOCK_ONE_MILL * nopponentMills);
}
#endif
}
}
#endif
//newNode->rating += static_cast<rating_t>(nForbidden); // 摆子阶段尽量往禁点旁边落子
// 对于12子棋, 白方第2着走星点的重要性和成三一样重要 (TODO)
#ifdef ALPHABETA_AI
if (rule.nTotalPiecesEachSide == 12 &&
position->getPiecesOnBoardCount(2) < 2 && // patch: 仅当白方第2着时
Board::isStar(static_cast<square_t>(m))) {
cur->rating += RATING_STAR_SQUARE;
}
#endif
} else if (m < 0) {
int nPlayerPiece = 0;
int nOpponentPiece = 0;
int nForbidden = 0;
int nEmpty = 0;
position->board.getSurroundedPieceCount(sq, position->sideId,
nPlayerPiece, nOpponentPiece, nForbidden, nEmpty);
#ifdef ALPHABETA_AI
if (nMills > 0) {
// 吃子点处于我方的三连中
//newNode->rating += static_cast<rating_t>(RATING_CAPTURE_ONE_MILL * nMills);
if (nOpponentPiece == 0) {
// 吃子点旁边没有对方棋子则优先考虑
cur->rating += static_cast<rating_t>(1);
if (nPlayerPiece > 0) {
// 且吃子点旁边有我方棋子则更优先考虑
cur->rating += static_cast<rating_t>(nPlayerPiece);
}
}
}
// 吃子点处于对方的三连中
nopponentMills = position->board.inHowManyMills(sq, position->opponent);
if (nopponentMills) {
if (nOpponentPiece >= 2) {
// 旁边对方的子较多, 则倾向不吃
cur->rating -= static_cast<rating_t>(nOpponentPiece);
if (nPlayerPiece == 0) {
// 如果旁边无我方棋子, 则更倾向不吃
cur->rating -= static_cast<rating_t>(1);
}
}
}
// 优先吃活动力强的棋子
cur->rating += static_cast<rating_t>(nEmpty);
#endif
}
#endif // SORT_MOVE_WITH_HUMAN_KNOWLEDGES
}
}
#ifdef HOSTORY_HEURISTIC
score_t MovePicker::getHistoryScore(move_t move)
{

View File

@ -22,11 +22,26 @@
#include "stack.h"
#include "types.h"
#include "movegen.h"
#include "position.h"
class Position;
class ExtMove;
void partial_insertion_sort(ExtMove *begin, ExtMove *end, int limit);
class MovePicker
{
enum PickType
{
Next, Best
};
public:
MovePicker();
MovePicker(Position *position, ExtMove *cur);
MovePicker(const MovePicker &) = delete;
MovePicker &operator=(const MovePicker &) = delete;
// move_t nextMove(bool skipQuiets = false);
#ifdef HOSTORY_HEURISTIC
// TODO: Fix size
@ -38,6 +53,22 @@ public:
void setHistoryScore(move_t move, depth_t depth);
void clearHistoryScore();
#endif // HOSTORY_HEURISTIC
public:
void score();
ExtMove *begin()
{
return cur;
}
// ExtMove *end()
// {
// return endMoves;
// }
Position *position;
ExtMove *cur;
};
#endif // MOVEPICK_H

View File

@ -52,7 +52,7 @@ AIAlgorithm::AIAlgorithm()
{
state = new StateInfo();
st = new StateInfo();
movePicker = new MovePicker();
//movePicker = new MovePicker();
memmgr.memmgr_init();
@ -215,50 +215,6 @@ Node *Node::addChild(
newNode->parent = this;
ai->nodeCount++;
#ifdef DEBUG_AB_TREE
newNode->id = nodeCount;
#endif
#ifdef DEBUG_AB_TREE
newNode->hash = 0;
#endif
#ifdef DEBUG_AB_TREE
#ifdef TRANSPOSITION_TABLE_ENABLE
newNode->isHash = false;
#endif
#endif
#ifdef DEBUG_AB_TREE
newNode->root = root;
newNode->phase = st->position.phase;
newNode->action = st->position.action;
newNode->evaluated = false;
newNode->nPiecesInHandDiff = std::numeric_limits<int>::max();
newNode->nPiecesOnBoardDiff = std::numeric_limits<int>::max();
newNode->nPiecesNeedRemove = std::numeric_limits<int>::max();
newNode->alpha = -VALUE_INFINITE;
newNode->beta = VALUE_INFINITE;
newNode->visited = false;
int r, s;
char cmd[32] = { 0 };
if (move < 0) {
st->position.board.squareToPolar(static_cast<square_t>(-move), r, s);
sprintf(cmd, "-(%1u,%1u)", r, s);
} else if (move & 0x7f00) {
int r1, s1;
st->position.board.squareToPolar(static_cast<square_t>(move >> 8), r1, s1);
st->position.board.squareToPolar(static_cast<square_t>(move & 0x00ff), r, s);
sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s);
} else {
st->position.board.squareToPolar(static_cast<square_t>(move & 0x007f), r, s);
sprintf(cmd, "(%1u,%1u)", r, s);
}
strcpy(newNode->cmd, cmd);
#endif // DEBUG_AB_TREE
children[childrenSize] = newNode;
childrenSize++;
@ -756,7 +712,7 @@ value_t AIAlgorithm::MTDF(value_t firstguess, depth_t depth)
beta = g;
}
g = search(depth, beta - VALUE_MTDF_WINDOW, beta, root);
g = search(depth, beta - VALUE_MTDF_WINDOW, beta);
if (g < beta) {
upperbound = g; // fail low
@ -768,13 +724,11 @@ value_t AIAlgorithm::MTDF(value_t firstguess, depth_t depth)
return g;
}
value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *node)
value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta)
{
assert(node != nullptr);
// 评价值
value_t value;
node->value = -VALUE_INFINITE;
value_t value, current;
current = -VALUE_INFINITE;
// 临时增加的深度,克服水平线效应用
depth_t epsilon;
@ -797,18 +751,18 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
findEndgameHash(hash, endgame)) {
switch (endgame.type) {
case ENDGAME_PLAYER_BLACK_WIN:
node->value = VALUE_WIN;
node->value += depth;
current = VALUE_WIN;
current += depth;
break;
case ENDGAME_PLAYER_WHITE_WIN:
node->value = -VALUE_WIN;
node->value -= depth;
current = -VALUE_WIN;
current -= depth;
break;
default:
break;
}
return node->value;
return current;
}
#endif /* ENDGAME_LEARNING */
@ -816,10 +770,6 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
// 哈希类型
enum TT::HashType hashf = TT::hashfALPHA;
#ifdef DEBUG_AB_TREE
node->hash = hash;
#endif
TT::HashType type = TT::hashfEMPTY;
value_t probeVal = TT::probeHash(hash, depth, alpha, beta, type
@ -838,14 +788,14 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
#ifdef DEBUG_AB_TREE
node->isHash = true;
#endif
node->value = probeVal;
current = probeVal;
#if 0
// TODO: 有必要针对深度微调 value?
if (position->turn == PLAYER_BLACK)
node->value += hashValue.depth - depth;
current += hashValue.depth - depth;
else
node->value -= hashValue.depth - depth;
current -= hashValue.depth - depth;
#endif
#ifdef TT_MOVE_ENABLE
@ -854,7 +804,7 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
// }
#endif // TT_MOVE_ENABLE
return node->value;
return current;
}
#ifdef TRANSPOSITION_TABLE_DEBUG
else {
@ -865,20 +815,6 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
//hashMapMutex.unlock();
#endif /* TRANSPOSITION_TABLE_ENABLE */
#ifdef DEBUG_AB_TREE
node->depth = depth;
node->root = root;
// node->player = position->turn;
// 初始化
node->isLeaf = false;
node->isTimeout = false;
node->visited = true;
#ifdef TRANSPOSITION_TABLE_ENABLE
node->isHash = false;
node->hash = 0;
#endif // TRANSPOSITION_TABLE_ENABLE
#endif // DEBUG_AB_TREE
#if 0
if (position->phase == PHASE_PLACING && depth == 1 && st->position->nPiecesNeedRemove > 0) {
depth--;
@ -889,14 +825,13 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
depth <= 0 ||
unlikely(requiredQuit)) {
// 局面评估
node->value = Evaluation::getValue(position, node);
evaluatedNodeCount++;
current = Evaluation::getValue(position);
// 为争取速胜value 值 +- 深度
if (node->value > 0) {
node->value += depth;
if (current > 0) {
current += depth;
} else {
node->value -= depth;
current -= depth;
}
#ifdef DEBUG_AB_TREE
@ -922,7 +857,7 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
undoNullMove();
if (value >= beta) {
node->value = beta;
current = beta;
return beta;
}
}
@ -932,7 +867,7 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
#ifdef TRANSPOSITION_TABLE_ENABLE
// 记录确切的哈希值
TT::recordHash(node->value,
TT::recordHash(current,
depth,
TT::hashfEXACT,
hash
@ -942,36 +877,30 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
);
#endif
return node->value;
return current;
}
// 生成子节点树,即生成每个合理的着法
if (node->childrenSize == 0) {
int moveCount = st->position->generateMoves(moves);
ExtMove extMoves[MAX_MOVES];
memset(extMoves, 0, sizeof(extMoves));
ExtMove *end = generate(st->position, extMoves);
MovePicker mp(st->position, extMoves);
mp.score();
st->position->generateChildren(moves, this, node
#ifdef TT_MOVE_ENABLE
, ttMove
#endif // TT_MOVE_ENABLE
);
partial_insertion_sort(extMoves, end, -100);
ExtMove *cur = extMoves;
if (node == root && moveCount == 1) {
best = moves[0];
return node->value;
}
int nchild = end - cur;
if (nchild == 1 && depth == originDepth) {
bestMove = extMoves[0].move;
bestValue = VALUE_STRONG;
return bestValue;
}
// 排序子节点树
sortMoves(node);
assert(node->childrenSize != 0);
int nchild = node->childrenSize;
#ifdef TRANSPOSITION_TABLE_ENABLE
#ifdef PREFETCH_SUPPORT
for (int i = 0; i < nchild; i++) {
TT::prefetchHash(st->position->getNextMainHash(node->children[i]->move));
TT::prefetchHash(st->position->getNextMainHash(extMoves[i].move));
}
#ifdef PREFETCH_DEBUG
@ -987,7 +916,7 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
// 棋局入栈保存,以便后续撤销着法
stashPosition();
player_t before = st->position->sideToMove;
move_t m = node->children[i]->move;
move_t m = extMoves[i].move;
doMove(m);
player_t after = st->position->sideToMove;
@ -1023,16 +952,16 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
}
#else
if (after != before) {
value = -search(depth - 1 + epsilon, -beta, -alpha, node->children[i]);
value = -search(depth - 1 + epsilon, -beta, -alpha);
} else {
value = search(depth - 1 + epsilon, alpha, beta, node->children[i]);
value = search(depth - 1 + epsilon, alpha, beta);
}
#endif // PVS_AI
undoMove();
if (value >= node->value) {
node->value = value;
if (value >= current) {
current = value;
if (value > alpha) {
#ifdef TRANSPOSITION_TABLE_ENABLE
@ -1049,7 +978,7 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
#ifdef TRANSPOSITION_TABLE_ENABLE
hashf = TT::hashfBETA;
#endif
node->value = beta;
current = beta;
goto out;
}
}
@ -1062,21 +991,16 @@ out:
node->beta = beta;
#endif
// 删除“孙子”节点,防止层数较深的时候节点树太大
#ifndef DONOT_DELETE_TREE
deleteSubTree(node);
#endif // DONOT_DELETE_TREE
if (gameOptions.getIDSEnabled()) {
#ifdef IDS_ADD_VALUE
node->children[0]->value += 1;
node->value += 1;
current += 1;
#endif /* IDS_ADD_VALUE */
}
#ifdef TRANSPOSITION_TABLE_ENABLE
// 记录不一定确切的哈希值
TT::recordHash(node->value,
TT::recordHash(current,
depth,
hashf,
hash
@ -1091,7 +1015,7 @@ out:
#endif
// 返回
return node->value;
return current;
}
#endif // ALPHABETA_AI
@ -1130,6 +1054,8 @@ void AIAlgorithm::undoNullMove()
#ifdef ALPHABETA_AI
const char* AIAlgorithm::nextMove()
{
return moveToCommand(best);
char charChoose = '*';
if (!root->childrenSize) {
@ -1189,11 +1115,9 @@ const char* AIAlgorithm::nextMove()
}
}
loggerDebug("Evaluated: %llu / %llu = %llu%%\n", evaluatedNodeCount, nodeCount, evaluatedNodeCount * 100 / nodeCount);
memmgr.memmgr_print_stats();
nodeCount = 0;
evaluatedNodeCount = 0;
#ifdef TRANSPOSITION_TABLE_ENABLE
#ifdef TRANSPOSITION_TABLE_DEBUG
@ -1272,4 +1196,4 @@ void AIAlgorithm::loadEndgameFileToHashMap()
const QString filename = "endgame.txt";
endgameHashMap.load(filename);
}
#endif // ENDGAME_LEARNING
#endif // ENDGAME_LEARNING

View File

@ -53,6 +53,7 @@ class AIAlgorithm;
class StateInfo;
class Node;
class Position;
class MovePicker;
using namespace std;
using namespace CTSL;
@ -270,7 +271,7 @@ public: /* TODO: Move to private or protected */
#endif /* EVALUATE_ENABLE */
// Alpha-Beta剪枝算法
value_t search(depth_t depth, value_t alpha, value_t beta, Node *node);
value_t search(depth_t depth, value_t alpha, value_t beta);
// MTD(f)
value_t MTDF(value_t firstguess, depth_t depth);
@ -298,9 +299,6 @@ private:
// 根节点
Node *root {nullptr};
// 评估过的结点个数
size_t evaluatedNodeCount {0};
// 局面数据栈
#ifdef USE_STD_STACK
stack<Position, vector<Position> > positionStack;

View File

@ -309,7 +309,7 @@ public:
| / | \ |
29 ----- 28 ----- 27
*/
move_t move{ MOVE_NONE };
move_t move { MOVE_NONE };
// 选中的棋子在board中的位置
square_t currentSquare{};