ai: tt: 完全去除 bestMove 相关参数

内存占用由 409M 缩小到 285M。
自对弈时长几乎无变化。
This commit is contained in:
Calcitem 2020-01-25 09:23:50 +08:00
parent 9e206cf972
commit f2e4f00a5a
7 changed files with 130 additions and 27 deletions

View File

@ -88,6 +88,7 @@
#define CLEAR_TRANSPOSITION_TABLE
#define TRANSPOSITION_TABLE_FAKE_CLEAN
#define TRANSPOSITION_TABLE_CUTDOWN
//#define BEST_MOVE_ENABLE
//#define TRANSPOSITION_TABLE_DEBUG
#endif

View File

@ -24,8 +24,14 @@
#include "misc.h"
#include "option.h"
void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
Node *parent, Node *root, move_t bestMove)
void MoveList::generate(AIAlgorithm &ai,
Game &tempGame,
Node *parent,
Node *root
#ifdef BEST_MOVE_ENABLE
, move_t bestMove
#endif // BEST_MOVE_ENABLE
)
{
square_t square = SQ_0;
player_t opponent = PLAYER_NOBODY;
@ -47,11 +53,19 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
// 否则如果是空位
if (tempGame.position.phase != PHASE_READY || parent != root) {
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)square, bestMove);
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)square
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
} else {
// 若为先手,则抢占星位
if (Board::isStar(square)) {
ai.addNode(parent, VALUE_INFINITE, RATING_STAR_SQUARE, (move_t)square, bestMove);
ai.addNode(parent, VALUE_INFINITE, RATING_STAR_SQUARE, (move_t)square
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
}
}
}
@ -78,7 +92,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
newSquare = static_cast<square_t>(moveTable[oldSquare][direction]);
if (newSquare && !tempGame.boardLocations[newSquare]) {
move_t move = move_t((oldSquare << 8) + newSquare);
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move, bestMove); // (12%)
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
}
}
} else {
@ -86,7 +104,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
for (newSquare = SQ_BEGIN; newSquare < SQ_END; newSquare = static_cast<square_t>(newSquare + 1)) {
if (!tempGame.boardLocations[newSquare]) {
move_t move = move_t((oldSquare << 8) + newSquare);
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move, bestMove);
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
}
}
}
@ -103,7 +125,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
for (int i = Board::MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
square = static_cast<square_t>(movePriorityTable[i]);
if (tempGame.boardLocations[square] & opponent) {
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square, bestMove);
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
}
}
break;
@ -114,7 +140,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
square = static_cast<square_t>(movePriorityTable[i]);
if (tempGame.boardLocations[square] & opponent) {
if (rule.allowRemoveMill || !tempGame.position.board.inHowManyMills(square)) {
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square, bestMove);
ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
}
}
}

View File

@ -32,9 +32,14 @@ public:
MoveList &operator=(const MoveList &) = delete;
// 生成所有合法的着法并建立子节点
static void generate(AIAlgorithm &ai, Game &tempGame,
Node *parent, Node *root,
move_t bestMove);
static void generate(AIAlgorithm &ai,
Game &tempGame,
Node *parent,
Node *root
#ifdef BEST_MOVE_ENABLE
, move_t bestMove
#endif // BEST_MOVE_ENABLE
);
// 生成着法表
static void create();

View File

@ -167,7 +167,11 @@ depth_t AIAlgorithm::changeDepth(depth_t origDepth)
void AIAlgorithm::buildRoot()
{
root = addNode(nullptr, VALUE_ZERO, RATING_ZERO, MOVE_NONE, MOVE_NONE);
root = addNode(nullptr, VALUE_ZERO, RATING_ZERO, MOVE_NONE
#ifdef BEST_MOVE_ENABLE
, MOVE_NONE
#endif // BEST_MOVE_ENABLE
);
root->sideToMove = PLAYER_NOBODY;
assert(root != nullptr);
@ -177,8 +181,10 @@ Node *AIAlgorithm::addNode(
Node *parent,
const value_t &value,
const rating_t &rating,
const move_t &move,
const move_t &bestMove
const move_t &move
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
)
{
Node *newNode = (Node *)memmgr.memmgr_alloc(sizeof(Node));
@ -253,13 +259,13 @@ Node *AIAlgorithm::addNode(
parent->children[parent->childrenSize] = newNode;
parent->childrenSize++;
#if 0
#ifdef BEST_MOVE_ENABLE
// 如果启用了置换表并且不是叶子结点
if (move == bestMove && move != 0) {
newNode->rating += RATING_TT;
return newNode;
}
#endif
#endif // BEST_MOVE_ENABLE
// 若没有启用置换表,或启用了但为叶子节点,则 bestMove 为0
square_t sq = SQ_0;
@ -660,8 +666,10 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
// 临时增加的深度,克服水平线效应用
depth_t epsilon = 0;
#ifdef BEST_MOVE_ENABLE
// 子节点的最优着法
move_t bestMove = MOVE_NONE;
#endif // BEST_MOVE_ENABLE
#if defined (TRANSPOSITION_TABLE_ENABLE) || defined(ENDGAME_LEARNING)
// 获取哈希值
@ -701,7 +709,11 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
TT::HashType type = TT::hashfEMPTY;
value_t probeVal = TT::probeHash(hash, depth, alpha, beta, bestMove, type);
value_t probeVal = TT::probeHash(hash, depth, alpha, beta, type
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
if (probeVal != VALUE_UNKNOWN) {
#ifdef DEBUG_MODE
@ -779,14 +791,25 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
#ifdef TRANSPOSITION_TABLE_ENABLE
// 记录确切的哈希值
TT::recordHash(node->value, depth, TT::hashfEXACT, hash, MOVE_NONE);
TT::recordHash(node->value,
depth,
TT::hashfEXACT,
hash
#ifdef BEST_MOVE_ENABLE
, MOVE_NONE
#endif // BEST_MOVE_ENABLE
);
#endif
return node->value;
}
// 生成子节点树,即生成每个合理的着法
MoveList::generate(*this, tempGame, node, root, bestMove);
MoveList::generate(*this, tempGame, node, root
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
);
// 排序子节点树
sortMoves(node);
@ -926,7 +949,14 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
#ifdef TRANSPOSITION_TABLE_ENABLE
// 记录不一定确切的哈希值
TT::recordHash(node->value, depth, hashf, hash, node->children[0]->move);
TT::recordHash(node->value,
depth,
hashf,
hash
#ifdef BEST_MOVE_ENABLE
, node->children[0]->move
#endif // BEST_MOVE_ENABLE
);
#endif /* TRANSPOSITION_TABLE_ENABLE */
// 返回

View File

@ -162,8 +162,14 @@ public:
public: /* TODO: Move to private or protected */
// 增加新节点
Node *addNode(Node *parent, const value_t &value, const rating_t &rating,
const move_t &move, const move_t &bestMove);
Node *addNode(Node *parent,
const value_t &value,
const rating_t &rating,
const move_t &move
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
);
protected:
// 对合法的着法降序排序

View File

@ -31,7 +31,11 @@ value_t TT::probeHash(const hash_t &hash,
const depth_t &depth,
const value_t &alpha,
const value_t &beta,
move_t &bestMove, HashType &type)
HashType &type
#ifdef BEST_MOVE_ENABLE
, move_t &bestMove
#endif // BEST_MOVE_ENABLE
)
{
HashValue hashValue{};
@ -69,7 +73,11 @@ value_t TT::probeHash(const hash_t &hash,
}
out:
#ifdef BEST_MOVE_ENABLE
bestMove = hashValue.bestMove;
#endif // BEST_MOVE_ENABLE
return VALUE_UNKNOWN;
}
@ -105,8 +113,11 @@ bool TT::findHash(const hash_t &hash, TT::HashValue &hashValue)
int TT::recordHash(const value_t &value,
const depth_t &depth,
const TT::HashType &type,
const hash_t &hash,
const move_t &bestMove)
const hash_t &hash
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
)
{
// 同样深度或更深时替换
// 注意: 每走一步以前都必须把散列表中所有的标志项置为 hashfEMPTY
@ -130,7 +141,10 @@ int TT::recordHash(const value_t &value,
hashValue.value = value;
hashValue.depth = depth;
hashValue.type = type;
#ifdef BEST_MOVE_ENABLE
hashValue.bestMove = bestMove;
#endif // BEST_MOVE_ENABLE
#ifdef TRANSPOSITION_TABLE_FAKE_CLEAN
hashValue.age = transpositionTableAge;

View File

@ -53,15 +53,32 @@ public:
#ifdef TRANSPOSITION_TABLE_FAKE_CLEAN
uint8_t age;
#endif // TRANSPOSITION_TABLE_FAKE_CLEAN
#ifdef BEST_MOVE_ENABLE
move_t bestMove;
#endif // BEST_MOVE_ENABLE
};
// 查找哈希表
static bool findHash(const hash_t &hash, HashValue &hashValue);
static value_t probeHash(const hash_t &hash, const depth_t &depth, const value_t &alpha, const value_t &beta, move_t &bestMove, HashType &type);
static value_t probeHash(const hash_t &hash,
const depth_t &depth,
const value_t &alpha,
const value_t &beta,
HashType &type
#ifdef BEST_MOVE_ENABLE
, move_t &bestMove
#endif // BEST_MOVE_ENABLE
);
// 插入哈希表
static int recordHash(const value_t &value, const depth_t &depth, const HashType &type, const hash_t &hash, const move_t &bestMove);
static int recordHash(const value_t &value,
const depth_t &depth,
const HashType &type,
const hash_t &hash
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
);
// 清空置换表
static void clear();