ai: tt: 完全去除 bestMove 相关参数
内存占用由 409M 缩小到 285M。 自对弈时长几乎无变化。
This commit is contained in:
parent
9e206cf972
commit
f2e4f00a5a
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
// 返回
|
// 返回
|
||||||
|
|
|
@ -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:
|
||||||
// 对合法的着法降序排序
|
// 对合法的着法降序排序
|
||||||
|
|
|
@ -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;
|
||||||
|
|
21
src/ai/tt.h
21
src/ai/tt.h
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue