From 8d844cd919ba08786adef56280b34a889f532844 Mon Sep 17 00:00:00 2001 From: Calcitem Date: Sun, 3 May 2020 13:16:30 +0800 Subject: [PATCH] =?UTF-8?q?BEST=5FMOVE=5FENABLE=20=E6=94=B9=E4=B8=BA=20TT?= =?UTF-8?q?=5FMOVE=5FENABLE=20=E5=B9=B6=E5=AE=8C=E5=96=84=E9=83=A8?= =?UTF-8?q?=E5=88=86=E4=BB=A3=E7=A0=81=20(=E6=9C=AA=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 目前在开启后,700盘自对弈显示速度为关闭时的 96.5%, 和关闭时对战600盘,胜率相差 0.8% 左右,可以认为相当。 暂未开启此宏。 --- include/config.h | 2 +- src/ai/mcts.cpp | 12 +++---- src/ai/movegen.cpp | 12 +++---- src/ai/movepick.cpp | 23 +++++++++++++ src/ai/movepick.h | 78 +++++++++++++++++++++++++++++++++++++++++++ src/ai/search.cpp | 54 +++++++++++++++--------------- src/ai/search.h | 12 +++---- src/ai/tt.cpp | 24 ++++++------- src/ai/tt.h | 18 +++++----- src/base/aithread.cpp | 2 +- src/game/position.h | 6 ++-- 11 files changed, 171 insertions(+), 72 deletions(-) create mode 100644 src/ai/movepick.cpp create mode 100644 src/ai/movepick.h diff --git a/include/config.h b/include/config.h index 5db8f312..f0cac4c4 100644 --- a/include/config.h +++ b/include/config.h @@ -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 diff --git a/src/ai/mcts.cpp b/src/ai/mcts.cpp index 14231469..6e683f10 100644 --- a/src/ai/mcts.cpp +++ b/src/ai/mcts.cpp @@ -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; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/ai/movegen.cpp b/src/ai/movegen.cpp index cc9f892e..f1008abb 100644 --- a/src/ai/movegen.cpp +++ b/src/ai/movegen.cpp @@ -30,9 +30,9 @@ void StateInfo::generateChildren(const Stack &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 &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 ); } diff --git a/src/ai/movepick.cpp b/src/ai/movepick.cpp new file mode 100644 index 00000000..f7d33c64 --- /dev/null +++ b/src/ai/movepick.cpp @@ -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 + + 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 . +*/ + +#include "movepick.h" +#include "option.h" +#include "types.h" +#include "config.h" diff --git a/src/ai/movepick.h b/src/ai/movepick.h new file mode 100644 index 00000000..afe03573 --- /dev/null +++ b/src/ai/movepick.h @@ -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 + + 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 . +*/ + +#ifndef MOVEPICK_H +#define MOVEPICK_H + +#include "stack.h" +#include "types.h" + +// TODO: Fix size +typedef Stack PlaceHistory; +typedef Stack CaptureHistory; +typedef Stack 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 diff --git a/src/ai/search.cpp b/src/ai/search.cpp index e36f15fa..423c404c 100644 --- a/src/ai/search.cpp +++ b/src/ai/search.cpp @@ -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 = '*'; diff --git a/src/ai/search.h b/src/ai/search.h index 2a9eb8ef..18c0ec37 100644 --- a/src/ai/search.h +++ b/src/ai/search.h @@ -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 // 暂存局面 diff --git a/src/ai/tt.cpp b/src/ai/tt.cpp index b3f56c86..a7896f57 100644 --- a/src/ai/tt.cpp +++ b/src/ai/tt.cpp @@ -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; diff --git a/src/ai/tt.h b/src/ai/tt.h index 6c7aee7c..9d5a7578 100644 --- a/src/ai/tt.h +++ b/src/ai/tt.h @@ -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 ); // 清空置换表 diff --git a/src/base/aithread.cpp b/src/base/aithread.cpp index 72538df2..3ed6c44d 100644 --- a/src/base/aithread.cpp +++ b/src/base/aithread.cpp @@ -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(); diff --git a/src/game/position.h b/src/game/position.h index 6cccaf54..8617bf06 100644 --- a/src/game/position.h +++ b/src/game/position.h @@ -242,9 +242,9 @@ public: void generateChildren(const Stack &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 ); // 着法生成