BEST_MOVE_ENABLE 改为 TT_MOVE_ENABLE 并完善部分代码 (未完成)

目前在开启后,700盘自对弈显示速度为关闭时的 96.5%,
和关闭时对战600盘,胜率相差 0.8% 左右,可以认为相当。

暂未开启此宏。
This commit is contained in:
Calcitem 2020-05-03 13:16:30 +08:00
parent 2e10e9d380
commit 8d844cd919
11 changed files with 171 additions and 72 deletions

View File

@ -90,7 +90,7 @@
#define CLEAR_TRANSPOSITION_TABLE
#define TRANSPOSITION_TABLE_FAKE_CLEAN
//#define TRANSPOSITION_TABLE_CUTDOWN
//#define BEST_MOVE_ENABLE
//#define TT_MOVE_ENABLE
//#define TRANSPOSITION_TABLE_DEBUG
#endif

View File

@ -402,7 +402,7 @@ move_t AIAlgorithm::computeMove(StateInfo state,
// Find the node with the highest score.
double bestScore = -1;
move_t bestMove = move_t();
move_t ttMove = move_t();
for (auto iter : visits) {
auto move = iter.first;
@ -412,7 +412,7 @@ move_t AIAlgorithm::computeMove(StateInfo state,
// https://en.wikipedia.org/wiki/Beta_distribution
double expectedSuccessRate = (w + 1) / (v + 2);
if (expectedSuccessRate > bestScore) {
bestMove = move;
ttMove = move;
bestScore = expectedSuccessRate;
}
@ -424,10 +424,10 @@ move_t AIAlgorithm::computeMove(StateInfo state,
}
if (options.verbose) {
auto best_wins = wins[bestMove];
auto best_visits = visits[bestMove];
auto best_wins = wins[ttMove];
auto best_visits = visits[ttMove];
cerr << "----" << endl;
cerr << "Best: " << bestMove
cerr << "Best: " << ttMove
<< " (" << 100.0 * best_visits / double(gamesPlayed) << "% visits)"
<< " (" << 100.0 * best_wins / best_visits << "% wins)" << endl;
}
@ -441,7 +441,7 @@ move_t AIAlgorithm::computeMove(StateInfo state,
}
#endif
return bestMove;
return ttMove;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -30,9 +30,9 @@
void StateInfo::generateChildren(const Stack<move_t, MOVE_COUNT> &moves,
AIAlgorithm *ai,
Node *node
#ifdef BEST_MOVE_ENABLE
, move_t bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, move_t ttMove
#endif // TT_MOVE_ENABLE
)
{
int size = moves.size();
@ -48,9 +48,9 @@ void StateInfo::generateChildren(const Stack<move_t, MOVE_COUNT> &moves,
for (int i = 0; i < size; i++) {
node->addChild(moves[i], ai, this
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, ttMove
#endif // TT_MOVE_ENABLE
);
}

23
src/ai/movepick.cpp Normal file
View File

@ -0,0 +1,23 @@
/*
Sanmill, a mill game playing engine derived from NineChess 1.5
Copyright (C) 2015-2018 liuweilhy (NineChess author)
Copyright (C) 2019-2020 Calcitem <calcitem@outlook.com>
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "movepick.h"
#include "option.h"
#include "types.h"
#include "config.h"

78
src/ai/movepick.h Normal file
View File

@ -0,0 +1,78 @@
/*
Sanmill, a mill game playing engine derived from NineChess 1.5
Copyright (C) 2015-2018 liuweilhy (NineChess author)
Copyright (C) 2019-2020 Calcitem <calcitem@outlook.com>
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOVEPICK_H
#define MOVEPICK_H
#include "stack.h"
#include "types.h"
// TODO: Fix size
typedef Stack<score_t, 64> PlaceHistory;
typedef Stack<score_t, 64> CaptureHistory;
typedef Stack<score_t, 10240> MoveHistory;
class MovePicker
{
public:
static PlaceHistory placeHistory;
static CaptureHistory captureHistory;
static MoveHistory moveHistory;
static score_t getHistoryScore(move_t move)
{
score_t ret;
if (move < 0) {
ret = placeHistory[-move];
} else if (move & 0x7f00) {
ret = moveHistory[move];
} else {
ret = placeHistory[move & 0x007f];
}
return ret;
}
static void setHistoryScore(move_t move, depth_t depth)
{
if (move == MOVE_NONE) {
return;
}
score_t score = 1 << depth;
if (move < 0) {
placeHistory[-move] += score;
} else if (move & 0x7f00) {
moveHistory[move] += score;
} else {
moveHistory[move & 0x007f] += score;
}
}
static void clearHistoryScore()
{
placeHistory.clear();
captureHistory.clear();
moveHistory.clear();
}
};
#endif // MOVEPICK_H

View File

@ -178,19 +178,15 @@ void AIAlgorithm::buildRoot()
#endif // ALPHABETA_AI
root->sideToMove = PLAYER_NOBODY;
#ifdef BEST_MOVE_ENABLE
root->bestMove = MOVE_NONE;
#endif // BEST_MOVE_ENABLE
}
Node *Node::addChild(
const move_t &m,
AIAlgorithm *ai,
StateInfo *st
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, const move_t &ttMove
#endif // TT_MOVE_ENABLE
)
{
Node *newNode = (Node *)ai->memmgr.memmgr_alloc(sizeof(Node));
@ -261,15 +257,15 @@ Node *Node::addChild(
children[childrenSize] = newNode;
childrenSize++;
#ifdef BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
// 如果启用了置换表并且不是叶子结点
if (move == bestMove && move != 0) {
if (move == ttMove && move != 0) {
newNode->rating += RATING_TT;
return newNode;
}
#endif // BEST_MOVE_ENABLE
#endif // TT_MOVE_ENABLE
// 若没有启用置换表,或启用了但为叶子节点,则 bestMove 为0
// 若没有启用置换表,或启用了但为叶子节点,则 ttMove 为0
square_t sq = SQ_0;
if (m > 0) {
@ -677,10 +673,10 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
// 临时增加的深度,克服水平线效应用
depth_t epsilon;
#ifdef BEST_MOVE_ENABLE
// 子节点的最优着法
move_t bestMove = MOVE_NONE;
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
// 置换表中读取到的最优着法
move_t ttMove = MOVE_NONE;
#endif // TT_MOVE_ENABLE
#if defined (TRANSPOSITION_TABLE_ENABLE) || defined(ENDGAME_LEARNING)
// 获取哈希值
@ -721,9 +717,9 @@ 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, type
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, ttMove
#endif // TT_MOVE_ENABLE
);
if (probeVal != VALUE_UNKNOWN) {
@ -746,6 +742,12 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
node->value -= hashValue.depth - depth;
#endif
#ifdef TT_MOVE_ENABLE
// if (ttMove != MOVE_NONE) {
// best = ttMove;
// }
#endif // TT_MOVE_ENABLE
return node->value;
}
#ifdef TRANSPOSITION_TABLE_DEBUG
@ -819,9 +821,9 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
depth,
TT::hashfEXACT,
hash
#ifdef BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, MOVE_NONE
#endif // BEST_MOVE_ENABLE
#endif // TT_MOVE_ENABLE
);
#endif
@ -833,9 +835,9 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
int moveSize = st->generateMoves(moves);
st->generateChildren(moves, this, node
#ifdef BEST_MOVE_ENABLE
, bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, ttMove
#endif // TT_MOVE_ENABLE
);
if (node == root && moveSize == 1) {
@ -963,9 +965,9 @@ out:
depth,
hashf,
hash
#ifdef BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, best
#endif // BEST_MOVE_ENABLE
#endif // TT_MOVE_ENABLE
);
#endif /* TRANSPOSITION_TABLE_ENABLE */
@ -1007,7 +1009,7 @@ void AIAlgorithm::undoNullMove()
}
#ifdef ALPHABETA_AI
const char* AIAlgorithm::bestMove()
const char* AIAlgorithm::ttMove()
{
char charChoose = '*';

View File

@ -78,9 +78,9 @@ public:
const move_t &move,
AIAlgorithm *ai,
StateInfo *st
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, const move_t &ttMove
#endif // TT_MOVE_ENABLE
);
#ifdef MCTS_AI
@ -115,10 +115,6 @@ public:
move_t move { MOVE_NONE };
int childrenSize { 0 };
#ifdef BEST_MOVE_ENABLE
move_t bestMove;
#endif // BEST_MOVE_ENABLE
#ifdef ALPHABETA_AI
value_t value { VALUE_UNKNOWN };
rating_t rating { RATING_ZERO };
@ -182,7 +178,7 @@ public:
int search(depth_t depth);
// 返回最佳走法的命令行
const char *bestMove();
const char *ttMove();
#endif // ALPHABETA_AI
// 暂存局面

View File

@ -32,9 +32,9 @@ value_t TT::probeHash(const hash_t &hash,
const value_t &alpha,
const value_t &beta,
HashType &type
#ifdef BEST_MOVE_ENABLE
, move_t &bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, move_t &ttMove
#endif // TT_MOVE_ENABLE
)
{
HashValue hashValue{};
@ -76,9 +76,9 @@ value_t TT::probeHash(const hash_t &hash,
out:
#ifdef BEST_MOVE_ENABLE
bestMove = hashValue.bestMove;
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
ttMove = hashValue.ttMove;
#endif // TT_MOVE_ENABLE
return VALUE_UNKNOWN;
}
@ -121,9 +121,9 @@ int TT::recordHash(const value_t &value,
const depth_t &depth,
const TT::HashType &type,
const hash_t &hash
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, const move_t &ttMove
#endif // TT_MOVE_ENABLE
)
{
// 同样深度或更深时替换
@ -149,9 +149,9 @@ int TT::recordHash(const value_t &value,
hashValue.depth = depth;
hashValue.type = type;
#ifdef BEST_MOVE_ENABLE
hashValue.bestMove = bestMove;
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
hashValue.ttMove = ttMove;
#endif // TT_MOVE_ENABLE
#ifdef TRANSPOSITION_TABLE_FAKE_CLEAN
hashValue.age = transpositionTableAge;

View File

@ -53,9 +53,9 @@ 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
#ifdef TT_MOVE_ENABLE
move_t ttMove;
#endif // TT_MOVE_ENABLE
};
// 查找哈希表
@ -65,9 +65,9 @@ public:
const value_t &alpha,
const value_t &beta,
HashType &type
#ifdef BEST_MOVE_ENABLE
, move_t &bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, move_t &ttMove
#endif // TT_MOVE_ENABLE
);
// 插入哈希表
@ -75,9 +75,9 @@ public:
const depth_t &depth,
const HashType &type,
const hash_t &hash
#ifdef BEST_MOVE_ENABLE
, const move_t &bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, const move_t &ttMove
#endif // TT_MOVE_ENABLE
);
// 清空置换表

View File

@ -139,7 +139,7 @@ void AiThread::run()
strCommand = "draw";
emitCommand();
} else {
strCommand = ai.bestMove();
strCommand = ai.ttMove();
if (strCommand && strcmp(strCommand, "error!") != 0) {
loggerDebug("Computer: %s\n\n", strCommand);
emitCommand();

View File

@ -242,9 +242,9 @@ public:
void generateChildren(const Stack<move_t, MOVE_COUNT> &moves,
AIAlgorithm *ai,
Node *node
#ifdef BEST_MOVE_ENABLE
, move_t bestMove
#endif // BEST_MOVE_ENABLE
#ifdef TT_MOVE_ENABLE
, move_t ttMove
#endif // TT_MOVE_ENABLE
);
// 着法生成