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 CLEAR_TRANSPOSITION_TABLE
#define TRANSPOSITION_TABLE_FAKE_CLEAN #define TRANSPOSITION_TABLE_FAKE_CLEAN
#define TRANSPOSITION_TABLE_CUTDOWN #define TRANSPOSITION_TABLE_CUTDOWN
//#define BEST_MOVE_ENABLE
//#define TRANSPOSITION_TABLE_DEBUG //#define TRANSPOSITION_TABLE_DEBUG
#endif #endif

View File

@ -24,8 +24,14 @@
#include "misc.h" #include "misc.h"
#include "option.h" #include "option.h"
void MoveList::generate(AIAlgorithm &ai, Game &tempGame, void MoveList::generate(AIAlgorithm &ai,
Node *parent, Node *root, move_t bestMove) Game &tempGame,
Node *parent,
Node *root
#ifdef BEST_MOVE_ENABLE
, move_t bestMove
#endif // BEST_MOVE_ENABLE
)
{ {
square_t square = SQ_0; square_t square = SQ_0;
player_t opponent = PLAYER_NOBODY; player_t opponent = PLAYER_NOBODY;
@ -47,11 +53,19 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
// 否则如果是空位 // 否则如果是空位
if (tempGame.position.phase != PHASE_READY || parent != root) { 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 { } else {
// 若为先手,则抢占星位 // 若为先手,则抢占星位
if (Board::isStar(square)) { 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]); newSquare = static_cast<square_t>(moveTable[oldSquare][direction]);
if (newSquare && !tempGame.boardLocations[newSquare]) { if (newSquare && !tempGame.boardLocations[newSquare]) {
move_t move = move_t((oldSquare << 8) + 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 { } 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)) { for (newSquare = SQ_BEGIN; newSquare < SQ_END; newSquare = static_cast<square_t>(newSquare + 1)) {
if (!tempGame.boardLocations[newSquare]) { if (!tempGame.boardLocations[newSquare]) {
move_t move = move_t((oldSquare << 8) + 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--) { for (int i = Board::MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
square = static_cast<square_t>(movePriorityTable[i]); square = static_cast<square_t>(movePriorityTable[i]);
if (tempGame.boardLocations[square] & opponent) { 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; break;
@ -114,7 +140,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame,
square = static_cast<square_t>(movePriorityTable[i]); square = static_cast<square_t>(movePriorityTable[i]);
if (tempGame.boardLocations[square] & opponent) { if (tempGame.boardLocations[square] & opponent) {
if (rule.allowRemoveMill || !tempGame.position.board.inHowManyMills(square)) { 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; MoveList &operator=(const MoveList &) = delete;
// 生成所有合法的着法并建立子节点 // 生成所有合法的着法并建立子节点
static void generate(AIAlgorithm &ai, Game &tempGame, static void generate(AIAlgorithm &ai,
Node *parent, Node *root, Game &tempGame,
move_t bestMove); Node *parent,
Node *root
#ifdef BEST_MOVE_ENABLE
, move_t bestMove
#endif // BEST_MOVE_ENABLE
);
// 生成着法表 // 生成着法表
static void create(); static void create();

View File

@ -167,7 +167,11 @@ depth_t AIAlgorithm::changeDepth(depth_t origDepth)
void AIAlgorithm::buildRoot() 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; root->sideToMove = PLAYER_NOBODY;
assert(root != nullptr); assert(root != nullptr);
@ -177,8 +181,10 @@ Node *AIAlgorithm::addNode(
Node *parent, Node *parent,
const value_t &value, const value_t &value,
const rating_t &rating, const rating_t &rating,
const move_t &move, const move_t &move
const move_t &bestMove #ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
) )
{ {
Node *newNode = (Node *)memmgr.memmgr_alloc(sizeof(Node)); Node *newNode = (Node *)memmgr.memmgr_alloc(sizeof(Node));
@ -253,13 +259,13 @@ Node *AIAlgorithm::addNode(
parent->children[parent->childrenSize] = newNode; parent->children[parent->childrenSize] = newNode;
parent->childrenSize++; parent->childrenSize++;
#if 0 #ifdef BEST_MOVE_ENABLE
// 如果启用了置换表并且不是叶子结点 // 如果启用了置换表并且不是叶子结点
if (move == bestMove && move != 0) { if (move == bestMove && move != 0) {
newNode->rating += RATING_TT; newNode->rating += RATING_TT;
return newNode; return newNode;
} }
#endif #endif // BEST_MOVE_ENABLE
// 若没有启用置换表,或启用了但为叶子节点,则 bestMove 为0 // 若没有启用置换表,或启用了但为叶子节点,则 bestMove 为0
square_t sq = SQ_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; depth_t epsilon = 0;
#ifdef BEST_MOVE_ENABLE
// 子节点的最优着法 // 子节点的最优着法
move_t bestMove = MOVE_NONE; move_t bestMove = MOVE_NONE;
#endif // BEST_MOVE_ENABLE
#if defined (TRANSPOSITION_TABLE_ENABLE) || defined(ENDGAME_LEARNING) #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; 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) { if (probeVal != VALUE_UNKNOWN) {
#ifdef DEBUG_MODE #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 #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 #endif
return node->value; 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); 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 #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 */ #endif /* TRANSPOSITION_TABLE_ENABLE */
// 返回 // 返回

View File

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

View File

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

View File

@ -53,15 +53,32 @@ public:
#ifdef TRANSPOSITION_TABLE_FAKE_CLEAN #ifdef TRANSPOSITION_TABLE_FAKE_CLEAN
uint8_t age; uint8_t age;
#endif // TRANSPOSITION_TABLE_FAKE_CLEAN #endif // TRANSPOSITION_TABLE_FAKE_CLEAN
#ifdef BEST_MOVE_ENABLE
move_t bestMove; move_t bestMove;
#endif // BEST_MOVE_ENABLE
}; };
// 查找哈希表 // 查找哈希表
static bool findHash(const hash_t &hash, HashValue &hashValue); 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(); static void clear();