parent
c4ba910072
commit
c9ec23603a
|
@ -74,7 +74,7 @@
|
|||
|
||||
//#define RAPID_GAME
|
||||
|
||||
//#define BOOK_LEARNING
|
||||
#define ENDGAME_LEARNING
|
||||
|
||||
#define THREEFOLD_REPETITION
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ INCLUDEPATH += src/game
|
|||
INCLUDEPATH += src/ui/qt
|
||||
|
||||
SOURCES += \
|
||||
src/ai/endgame.cpp \
|
||||
src/ai/evaluate.cpp \
|
||||
src/ai/movegen.cpp \
|
||||
src/ai/tt.cpp \
|
||||
|
@ -47,6 +48,7 @@ HEADERS += \
|
|||
include/config.h \
|
||||
include/version.h \
|
||||
include/version.h.template \
|
||||
src/ai/endgame.h \
|
||||
src/ai/evaluate.h \
|
||||
src/ai/movegen.h \
|
||||
src/ai/tt.h \
|
||||
|
@ -59,7 +61,6 @@ HEADERS += \
|
|||
src/base/stackalloc.h \
|
||||
src/base/thread.h \
|
||||
src/ai/search.h \
|
||||
src/ai/zobrist.h \
|
||||
src/base/zobrist.h \
|
||||
src/game/board.h \
|
||||
src/game/player.h \
|
||||
|
|
|
@ -441,6 +441,7 @@
|
|||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</AdditionalInputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="src\ai\endgame.h" />
|
||||
<ClInclude Include="src\ai\evaluate.h" />
|
||||
<ClInclude Include="src\ai\movegen.h" />
|
||||
<ClInclude Include="src\ai\search.h" />
|
||||
|
@ -692,6 +693,7 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\ai\endgame.cpp" />
|
||||
<ClCompile Include="src\ai\evaluate.cpp" />
|
||||
<ClCompile Include="src\ai\movegen.cpp" />
|
||||
<ClCompile Include="src\ai\search.cpp" />
|
||||
|
|
|
@ -117,6 +117,9 @@
|
|||
<ClInclude Include="src\base\zobrist.h">
|
||||
<Filter>base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ai\endgame.h">
|
||||
<Filter>ai</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
|
@ -335,6 +338,9 @@
|
|||
<ClCompile Include="src\base\zobrist.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ai\endgame.cpp">
|
||||
<Filter>ai</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="millgame.rc">
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (C) 2018-2019 MillGame authors
|
||||
*
|
||||
* Authors: liuweilhy <liuweilhy@163.com>
|
||||
* Calcitem <calcitem@outlook.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "endgame.h"
|
||||
|
||||
#ifdef ENDGAME_LEARNING
|
||||
static constexpr int endgameHashsize = 0x1000000; // 16M
|
||||
HashMap<hash_t, Endgame> endgameHashMap(endgameHashsize);
|
||||
#endif // ENDGAME_LEARNING
|
|
@ -0,0 +1,56 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (C) 2018-2019 MillGame authors
|
||||
*
|
||||
* Authors: liuweilhy <liuweilhy@163.com>
|
||||
* Calcitem <calcitem@outlook.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef ENDGAME_H
|
||||
#define ENDGAME_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENDGAME_LEARNING
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "types.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CTSL;
|
||||
|
||||
enum endgame_t : uint8_t
|
||||
{
|
||||
ENDGAME_NONE,
|
||||
ENDGAME_PLAYER_1_WIN,
|
||||
ENDGAME_PLAYER_2_WIN,
|
||||
ENDGAME_DRAW,
|
||||
};
|
||||
|
||||
//#pragma pack (push, 1)
|
||||
struct Endgame
|
||||
{
|
||||
endgame_t type;
|
||||
};
|
||||
//#pragma pack(pop)
|
||||
|
||||
extern HashMap<hash_t, Endgame> endgameHashMap;
|
||||
|
||||
#endif // ENDGAME_LEARNING
|
||||
|
||||
#endif // ENDGAME_H
|
|
@ -40,49 +40,49 @@ public:
|
|||
#ifdef EVALUATE_ENABLE
|
||||
|
||||
#ifdef EVALUATE_MATERIAL
|
||||
static value_t evaluateMaterial(MillGameAi_ab::Node *node)
|
||||
static value_t evaluateMaterial(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVALUATE_SPACE
|
||||
static value_t evaluateSpace(MillGameAi_ab::Node *node)
|
||||
static value_t evaluateSpace(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVALUATE_MOBILITY
|
||||
static value_t evaluateMobility(MillGameAi_ab::Node *node)
|
||||
static value_t evaluateMobility(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVALUATE_TEMPO
|
||||
static value_t evaluateTempo(MillGameAi_ab::Node *node)
|
||||
static value_t evaluateTempo(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVALUATE_THREAT
|
||||
static value_t evaluateThreat(MillGameAi_ab::Node *node)
|
||||
static value_t evaluateThreat(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVALUATE_SHAPE
|
||||
static value_t evaluateShape(MillGameAi_ab::Node *node)
|
||||
static value_t evaluateShape(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EVALUATE_MOTIF
|
||||
static value_t MillGameAi_ab::evaluateMotif(MillGameAi_ab::Node *node)
|
||||
static value_t AIAlgorithm::evaluateMotif(AIAlgorithm::Node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -29,16 +29,11 @@
|
|||
#include "movegen.h"
|
||||
#include "hashmap.h"
|
||||
#include "tt.h"
|
||||
#include "endgame.h"
|
||||
#include "types.h"
|
||||
|
||||
using namespace CTSL;
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
static constexpr int bookHashsize = 0x1000000; // 16M
|
||||
HashMap<hash_t, MillGameAi_ab::HashValue> bookHashMap(bookHashsize);
|
||||
vector<hash_t> openingBook;
|
||||
#endif // BOOK_LEARNING
|
||||
|
||||
// 用于检测重复局面 (Position)
|
||||
vector<hash_t> history;
|
||||
|
||||
|
@ -79,11 +74,19 @@ depth_t AIAlgorithm::changeDepth(depth_t origDepth)
|
|||
12, 12, 13, 14, /* 20 ~ 23 */
|
||||
};
|
||||
|
||||
#ifdef ENDGAME_LEARNING
|
||||
const depth_t movingDiffDepthTable[] = {
|
||||
0, 0, 0, /* 0 ~ 2 */
|
||||
0, 0, 0, 0, 0, /* 3 ~ 7 */
|
||||
0, 0, 0, 0, 0 /* 8 ~ 12 */
|
||||
};
|
||||
#else
|
||||
const depth_t movingDiffDepthTable[] = {
|
||||
0, 0, 0, /* 0 ~ 2 */
|
||||
11, 10, 9, 8, 7, /* 3 ~ 7 */
|
||||
6, 5, 4, 3, 2 /* 8 ~ 12 */
|
||||
};
|
||||
#endif /* ENDGAME_LEARNING */
|
||||
|
||||
if ((tempGame.position.phase) & (PHASE_PLACING)) {
|
||||
d = placingDepthTable[tempGame.getPiecesInHandCount(1)];
|
||||
|
@ -288,11 +291,11 @@ void AIAlgorithm::setGame(const Game &game)
|
|||
TranspositionTable::clear();
|
||||
#endif // TRANSPOSITION_TABLE_ENABLE
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
// TODO: 规则改变时清空学习表
|
||||
//clearBookHashMap();
|
||||
//openingBook.clear();
|
||||
#endif // BOOK_LEARNING
|
||||
#ifdef ENDGAME_LEARNING
|
||||
// TODO: 规则改变时清空残局库
|
||||
//clearEndgameHashMap();
|
||||
//endgameList.clear();
|
||||
#endif // ENDGAME_LEARNING
|
||||
|
||||
history.clear();
|
||||
}
|
||||
|
@ -332,19 +335,6 @@ int AIAlgorithm::search(depth_t depth)
|
|||
auto timeStart = chrono::steady_clock::now();
|
||||
chrono::steady_clock::time_point timeEnd;
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
if (position_.getPhase() == GAME_PLACING)
|
||||
{
|
||||
if (position_.position.nPiecesInHand[1] <= 10) {
|
||||
// 开局库只记录摆棋阶段最后的局面
|
||||
openingBook.push_back(position_.getHash());
|
||||
} else {
|
||||
// 暂时在此处清空开局库
|
||||
openingBook.clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef THREEFOLD_REPETITION
|
||||
static int nRepetition = 0;
|
||||
|
||||
|
@ -415,18 +405,37 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
|
|||
// 子节点的最优着法
|
||||
move_t bestMove = MOVE_NONE;
|
||||
|
||||
#if ((defined TRANSPOSITION_TABLE_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 哈希类型
|
||||
enum TranspositionTable::HashType hashf = TranspositionTable::hashfALPHA;
|
||||
|
||||
#if defined (TRANSPOSITION_TABLE_ENABLE) || defined(ENDGAME_LEARNING)
|
||||
// 获取哈希值
|
||||
hash_t hash = tempGame.getHash();
|
||||
#endif
|
||||
|
||||
#ifdef ENDGAME_LEARNING
|
||||
// 检索残局库
|
||||
Endgame endgame;
|
||||
|
||||
if (findEndgameHash(hash, endgame)) {
|
||||
switch (endgame.type) {
|
||||
case ENDGAME_PLAYER_1_WIN:
|
||||
node->value = VALUE_WIN;
|
||||
case ENDGAME_PLAYER_2_WIN:
|
||||
node->value = -VALUE_WIN;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return node->value;
|
||||
}
|
||||
#endif /* ENDGAME_LEARNING */
|
||||
|
||||
#ifdef TRANSPOSITION_TABLE_ENABLE
|
||||
// 哈希类型
|
||||
enum TranspositionTable::HashType hashf = TranspositionTable::hashfALPHA;
|
||||
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->hash = hash;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TRANSPOSITION_TABLE_ENABLE
|
||||
TranspositionTable::HashType type = TranspositionTable::hashfEMPTY;
|
||||
|
||||
value_t probeVal = TranspositionTable::probeHash(hash, depth, alpha, beta, bestMove, type);
|
||||
|
@ -455,7 +464,7 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
|
|||
#endif
|
||||
|
||||
return node->value;
|
||||
}
|
||||
}
|
||||
|
||||
//hashMapMutex.unlock();
|
||||
#endif /* TRANSPOSITION_TABLE_ENABLE */
|
||||
|
@ -515,16 +524,6 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
// 检索开局库
|
||||
if (position->phase == GAME_PLACING && findBookHash(hash, hashValue)) {
|
||||
if (position->turn == ???) {
|
||||
// TODO:
|
||||
node->value += 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TRANSPOSITION_TABLE_ENABLE
|
||||
// 记录确切的哈希值
|
||||
TranspositionTable::recordHash(node->value, depth, TranspositionTable::hashfEXACT, hash, MOVE_NONE);
|
||||
|
@ -702,6 +701,13 @@ const char* AIAlgorithm::bestMove()
|
|||
|
||||
// 自动认输
|
||||
if (isMostLose) {
|
||||
#ifdef ENDGAME_LEARNING
|
||||
Endgame endgame;
|
||||
endgame.type = game_.position.sideToMove == PLAYER_1 ?
|
||||
ENDGAME_PLAYER_2_WIN : ENDGAME_PLAYER_1_WIN;
|
||||
recordEndgameHash(this->game_.getHash(), endgame);
|
||||
#endif /* ENDGAME_LEARNING */
|
||||
|
||||
sprintf(cmdline, "Player%d give up!", game_.position.sideId);
|
||||
return cmdline;
|
||||
}
|
||||
|
@ -760,58 +766,37 @@ const char *AIAlgorithm::moveToCommand(move_t move)
|
|||
return cmdline;
|
||||
}
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
|
||||
bool AIAlgorithm::findBookHash(hash_t hash, HashValue &hashValue)
|
||||
#ifdef ENDGAME_LEARNING
|
||||
bool AIAlgorithm::findEndgameHash(hash_t hash, Endgame &endgame)
|
||||
{
|
||||
return bookHashMap.find(hash, hashValue);
|
||||
return endgameHashMap.find(hash, endgame);
|
||||
}
|
||||
|
||||
int AIAlgorithm::recordBookHash(hash_t hash, const HashValue &hashValue)
|
||||
int AIAlgorithm::recordEndgameHash(hash_t hash, const Endgame &endgame)
|
||||
{
|
||||
//hashMapMutex.lock();
|
||||
bookHashMap.insert(hash, hashValue);
|
||||
endgameHashMap.insert(hash, endgame);
|
||||
//hashMapMutex.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AIAlgorithm::clearBookHashMap()
|
||||
void AIAlgorithm::clearEndgameHashMap()
|
||||
{
|
||||
//hashMapMutex.lock();
|
||||
bookHashMap.clear();
|
||||
endgameHashMap.clear();
|
||||
//hashMapMutex.unlock();
|
||||
}
|
||||
|
||||
void AIAlgorithm::recordOpeningBookToHashMap()
|
||||
void AIAlgorithm::recordEndgameHashMapToFile()
|
||||
{
|
||||
HashValue hashValue;
|
||||
hash_t hash = 0;
|
||||
|
||||
for (auto iter = openingBook.begin(); iter != openingBook.end(); ++iter)
|
||||
{
|
||||
#if 0
|
||||
if (findBookHash(*iter, hashValue))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
memset(&hashValue, 0, sizeof(HashValue));
|
||||
hash = *iter;
|
||||
recordBookHash(hash, hashValue); // 暂时使用直接覆盖策略
|
||||
}
|
||||
|
||||
openingBook.clear();
|
||||
const QString filename = "endgame.txt";
|
||||
endgameHashMap.dump(filename);
|
||||
}
|
||||
|
||||
void AIAlgorithm::recordOpeningBookHashMapToFile()
|
||||
void AIAlgorithm::loadEndgameFileToHashMap()
|
||||
{
|
||||
const QString bookFileName = "opening-book.txt";
|
||||
bookHashMap.dump(bookFileName);
|
||||
const QString filename = "endgame.txt";
|
||||
endgameHashMap.load(filename);
|
||||
}
|
||||
|
||||
void AIAlgorithm::loadOpeningBookFileToHashMap()
|
||||
{
|
||||
const QString bookFileName = "opening-book.txt";
|
||||
bookHashMap.load(bookFileName);
|
||||
}
|
||||
#endif // BOOK_LEARNING
|
||||
#endif // ENDGAME_LEARNING
|
||||
|
|
|
@ -36,7 +36,10 @@
|
|||
#include <array>
|
||||
|
||||
#include "position.h"
|
||||
#include "tt.h"
|
||||
#include "hashmap.h"
|
||||
#include "endgame.h"
|
||||
#include "types.h"
|
||||
|
||||
#ifdef MEMORY_POOL
|
||||
#include "MemoryPool.h"
|
||||
|
@ -111,7 +114,7 @@ public:
|
|||
// 返回最佳走法的命令行
|
||||
const char *bestMove();
|
||||
|
||||
#if ((defined TRANSPOSITION_TABLE_ENABLE) || (defined BOOK_LEARNING))
|
||||
#ifdef TRANSPOSITION_TABLE_ENABLE
|
||||
// 清空哈希表
|
||||
void clearTranspositionTable();
|
||||
#endif
|
||||
|
@ -120,14 +123,14 @@ public:
|
|||
static bool nodeLess(const Node *first, const Node *second);
|
||||
static bool nodeGreater(const Node *first, const Node *second);
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
bool findBookHash(hash_t hash, HashValue &hashValue);
|
||||
static int recordBookHash(hash_t hash, const HashValue &hashValue);
|
||||
void clearBookHashMap();
|
||||
static void recordOpeningBookToHashMap();
|
||||
static void recordOpeningBookHashMapToFile();
|
||||
static void loadOpeningBookFileToHashMap();
|
||||
#endif // BOOK_LEARNING
|
||||
#ifdef ENDGAME_LEARNING
|
||||
bool findEndgameHash(hash_t hash, Endgame &endgame);
|
||||
static int recordEndgameHash(hash_t hash, const Endgame &endgame);
|
||||
void clearEndgameHashMap();
|
||||
static void recordEndgameHashMapToFile();
|
||||
static void loadEndgameFileToHashMap();
|
||||
#endif // ENDGAME_LEARNING
|
||||
|
||||
|
||||
public: /* TODO: Move to private or protected */
|
||||
// 增加新节点
|
||||
|
|
|
@ -34,9 +34,9 @@ Game::Game()
|
|||
// 创建哈希数据
|
||||
constructHash();
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
// TODO: 开局库文件被加载了多次
|
||||
MillGameAi_ab::loadOpeningBookFileToHashMap();
|
||||
#ifdef ENDGAME_LEARNING
|
||||
// TODO: 残局文件被加载了多次
|
||||
AIAlgorithm::loadEndgameFileToHashMap();
|
||||
#endif
|
||||
|
||||
// 默认选择第1号规则,即“打三棋”
|
||||
|
@ -886,9 +886,6 @@ bool Game::win(bool forceDraw)
|
|||
position.phase = PHASE_GAMEOVER;
|
||||
sprintf(cmdline, "Player%d win!", o);
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
#ifdef BOOK_LEARNING
|
||||
MillGameAi_ab::recordOpeningBookToHashMap(); // TODO: 目前是对"双方"失败都记录到开局库
|
||||
#endif /* BOOK_LEARNING */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -922,9 +919,6 @@ bool Game::win(bool forceDraw)
|
|||
int winnerId = Player::toId(winner);
|
||||
sprintf(cmdline, "Player%d no way to go. Player%d win!", position.sideId, winnerId);
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
#ifdef BOOK_LEARNING
|
||||
MillGameAi_ab::recordOpeningBookToHashMap(); // TODO: 目前是对所有的失败记录到开局库
|
||||
#endif /* BOOK_LEARNING */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -98,9 +98,9 @@ GameController::~GameController()
|
|||
delete ai[1];
|
||||
delete ai[2];
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
MillGameAi_ab::recordOpeningBookHashMapToFile();
|
||||
#endif /* BOOK_LEARNING */
|
||||
#ifdef ENDGAME_LEARNING
|
||||
AIAlgorithm::recordEndgameHashMapToFile();
|
||||
#endif /* ENDGAME_LEARNING */
|
||||
}
|
||||
|
||||
const QMap<int, QStringList> GameController::getActions()
|
||||
|
|
Loading…
Reference in New Issue