parent
b8cd08e204
commit
6399e03a36
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -309,7 +309,7 @@ public:
|
|||
| / | \ |
|
||||
29 ----- 28 ----- 27
|
||||
*/
|
||||
move_t move{ MOVE_NONE };
|
||||
move_t move { MOVE_NONE };
|
||||
|
||||
// 选中的棋子在board中的位置
|
||||
square_t currentSquare{};
|
||||
|
|
Loading…
Reference in New Issue