endgame: refactor

Known Issue:
After the previous series of code refactoring,
it still cannot work normally, but it can work normally
in the early stage.
This commit is contained in:
Calcitem 2020-12-31 12:22:48 +08:00
parent b3577d6b78
commit 096af01919
9 changed files with 58 additions and 68 deletions

View File

@ -97,7 +97,6 @@
//#define ENDGAME_LEARNING //#define ENDGAME_LEARNING
//#define ENDGAME_LEARNING_FORCE //#define ENDGAME_LEARNING_FORCE
//#define ENDGAME_LEARNING_DEBUG
#define THREEFOLD_REPETITION #define THREEFOLD_REPETITION

View File

@ -31,21 +31,20 @@
using namespace std; using namespace std;
using namespace CTSL; using namespace CTSL;
// TODO: uint8_t static const int SAVE_ENDGAME_EVERY_N_GAMES = 256;
enum endgame_t : uint32_t
enum class EndGameType : uint32_t
{ {
ENDGAME_NONE, none,
ENDGAME_PLAYER_BLACK_WIN, blackWin,
ENDGAME_PLAYER_WHITE_WIN, whiteWin,
ENDGAME_DRAW, draw,
}; };
//#pragma pack (push, 1)
struct Endgame struct Endgame
{ {
endgame_t type; EndGameType type;
}; };
//#pragma pack(pop)
extern HashMap<Key, Endgame> endgameHashMap; extern HashMap<Key, Endgame> endgameHashMap;

View File

@ -79,7 +79,7 @@ public:
#endif #endif
} }
bool getLearnEndgameEnabled() bool isEndgameLearningEnabled()
{ {
#ifdef ENDGAME_LEARNING_FORCE #ifdef ENDGAME_LEARNING_FORCE
return true; return true;

View File

@ -169,7 +169,7 @@ Position::Position()
reset(); reset();
score[BLACK] = score[WHITE] = score_draw = nPlayed = 0; score[BLACK] = score[WHITE] = score_draw = gamesPlayedCount = 0;
} }
@ -693,7 +693,7 @@ int Position::piece_on_board_count()
return pieceOnBoardCount[BLACK] + pieceOnBoardCount[WHITE]; return pieceOnBoardCount[BLACK] + pieceOnBoardCount[WHITE];
} }
int Position::get_piece_in_hand_count() int Position::piece_in_hand_count()
{ {
pieceInHandCount[BLACK] = rule.piecesCount - pieceOnBoardCount[BLACK]; pieceInHandCount[BLACK] = rule.piecesCount - pieceOnBoardCount[BLACK];
pieceInHandCount[WHITE] = rule.piecesCount - pieceOnBoardCount[WHITE]; pieceInHandCount[WHITE] = rule.piecesCount - pieceOnBoardCount[WHITE];
@ -736,8 +736,9 @@ bool Position::reset()
currentSquare = SQ_0; currentSquare = SQ_0;
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
if (gameOptions.getLearnEndgameEnabled() && nPlayed != 0 && nPlayed % 256 == 0) { if (gameOptions.isEndgameLearningEnabled() &&
Thread::recordEndgameHashMapToFile(); gamesPlayedCount > 0 && gamesPlayedCount % SAVE_ENDGAME_EVERY_N_GAMES == 0) {
Thread::saveEndgameHashMapToFile();
} }
#endif /* ENDGAME_LEARNING */ #endif /* ENDGAME_LEARNING */

View File

@ -145,7 +145,7 @@ public:
static void print_board(); static void print_board();
int piece_on_board_count(); int piece_on_board_count();
int get_piece_in_hand_count(); int piece_in_hand_count();
int piece_on_board_count(Color c); int piece_on_board_count(Color c);
int piece_in_hand_count(Color c); int piece_in_hand_count(Color c);
@ -203,7 +203,7 @@ public:
static Bitboard millTableBB[SQUARE_NB][LD_NB]; static Bitboard millTableBB[SQUARE_NB][LD_NB];
Square currentSquare; Square currentSquare;
int nPlayed { 0 }; int gamesPlayedCount { 0 };
char cmdline[64] { '\0' }; char cmdline[64] { '\0' };

View File

@ -233,14 +233,14 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
Endgame endgame; Endgame endgame;
if (gameOptions.getLearnEndgameEnabled() && if (gameOptions.isEndgameLearningEnabled() &&
Thread::findEndgameHash(posKey, endgame)) { Thread::probeEndgameHash(posKey, endgame)) {
switch (endgame.type) { switch (endgame.type) {
case ENDGAME_PLAYER_BLACK_WIN: case EndGameType::blackWin:
bestValue = VALUE_MATE; bestValue = VALUE_MATE;
bestValue += depth; bestValue += depth;
break; break;
case ENDGAME_PLAYER_WHITE_WIN: case EndGameType::whiteWin:
bestValue = -VALUE_MATE; bestValue = -VALUE_MATE;
bestValue -= depth; bestValue -= depth;
break; break;

View File

@ -424,15 +424,15 @@ Depth Thread::adjustDepth()
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
const Depth movingDiffDepthTable[] = { const Depth movingDiffDepthTable[] = {
0, 0, 0, /* 0 ~ 2 */ 0, 0, 0, /* 0 ~ 2 */
0, 0, 0, 0, 0, /* 3 ~ 7 */ 0, 0, 0, 0, 0, /* 3 ~ 7 */
0, 0, 0, 0, 0 /* 8 ~ 12 */ 0, 0, 0, 0, 0 /* 8 ~ 12 */
}; };
#else #else
const Depth movingDiffDepthTable[] = { const Depth movingDiffDepthTable[] = {
0, 0, 0, /* 0 ~ 2 */ 0, 0, 0, /* 0 ~ 2 */
11, 11, 10, 9, 8, /* 3 ~ 7 */ 11, 11, 10, 9, 8, /* 3 ~ 7 */
7, 6, 5, 4, 3 /* 8 ~ 12 */ 7, 6, 5, 4, 3 /* 8 ~ 12 */
}; };
#endif /* ENDGAME_LEARNING */ #endif /* ENDGAME_LEARNING */
@ -506,12 +506,6 @@ void Thread::clearTT()
#ifdef TRANSPOSITION_TABLE_ENABLE #ifdef TRANSPOSITION_TABLE_ENABLE
TranspositionTable::clear(); TranspositionTable::clear();
#endif // TRANSPOSITION_TABLE_ENABLE #endif // TRANSPOSITION_TABLE_ENABLE
#ifdef ENDGAME_LEARNING
// TODO: ??????????
//clearEndgameHashMap();
//endgameList.clear();
#endif // ENDGAME_LEARNING
} }
} }
@ -548,13 +542,13 @@ string Thread::nextMove()
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
// Check if very weak // Check if very weak
if (gameOptions.getLearnEndgameEnabled()) { if (gameOptions.isEndgameLearningEnabled()) {
if (bestValue <= -VALUE_KNOWN_WIN) { if (bestValue <= -VALUE_KNOWN_WIN) {
Endgame endgame; Endgame endgame;
endgame.type = state->position->playerSideToMove == PLAYER_BLACK ? endgame.type = state->position->playerSideToMove == PLAYER_BLACK ?
ENDGAME_PLAYER_WHITE_WIN : ENDGAME_PLAYER_BLACK_WIN; whiteWin : blackWin;
Key endgameHash = position->key(); // TODO: Do not generate hash repeately Key endgameHash = position->key(); // TODO: Do not generate hash repeately
recordEndgameHash(endgameHash, endgame); saveEndgameHash(endgameHash, endgame);
} }
} }
#endif /* ENDGAME_LEARNING */ #endif /* ENDGAME_LEARNING */
@ -591,31 +585,28 @@ string Thread::nextMove()
} }
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
bool Thread::findEndgameHash(Key posKey, Endgame &endgame) bool Thread::probeEndgameHash(Key posKey, Endgame &endgame)
{ {
return endgameHashMap.find(posKey, endgame); return endgameHashMap.find(posKey, endgame);
} }
int Thread::recordEndgameHash(Key posKey, const Endgame &endgame) int Thread::saveEndgameHash(Key posKey, const Endgame &endgame)
{ {
//hashMapMutex.lock();
Key hashValue = endgameHashMap.insert(posKey, endgame); Key hashValue = endgameHashMap.insert(posKey, endgame);
unsigned addr = hashValue * (sizeof(posKey) + sizeof(endgame)); unsigned addr = hashValue * (sizeof(posKey) + sizeof(endgame));
//hashMapMutex.unlock();
loggerDebug("[endgame] Record 0x%08I32x (%d) to Endgame Hash map, TTEntry: 0x%08I32x, Address: 0x%08I32x\n", posKey, endgame.type, hashValue, addr); loggerDebug("[endgame] Record 0x%08I32x (%d) to Endgame hash map, TTEntry: 0x%08I32x, Address: 0x%08I32x\n",
posKey, endgame.type, hashValue, addr);
return 0; return 0;
} }
void Thread::clearEndgameHashMap() void Thread::clearEndgameHashMap()
{ {
//hashMapMutex.lock();
endgameHashMap.clear(); endgameHashMap.clear();
//hashMapMutex.unlock();
} }
void Thread::recordEndgameHashMapToFile() void Thread::saveEndgameHashMapToFile()
{ {
const string filename = "endgame.txt"; const string filename = "endgame.txt";
endgameHashMap.dump(filename); endgameHashMap.dump(filename);

View File

@ -94,10 +94,10 @@ public:
#endif #endif
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
static bool findEndgameHash(Key key, Endgame &endgame); static bool probeEndgameHash(Key key, Endgame &endgame);
static int recordEndgameHash(Key key, const Endgame &endgame); static int saveEndgameHash(Key key, const Endgame &endgame);
void clearEndgameHashMap(); void clearEndgameHashMap();
static void recordEndgameHashMapToFile(); static void saveEndgameHashMapToFile();
static void loadEndgameFileToHashMap(); static void loadEndgameFileToHashMap();
#endif // ENDGAME_LEARNING #endif // ENDGAME_LEARNING

View File

@ -106,8 +106,8 @@ Game::Game(
#endif // NET_FIGHT_SUPPORT #endif // NET_FIGHT_SUPPORT
#ifdef ENDGAME_LEARNING_FORCE #ifdef ENDGAME_LEARNING_FORCE
if (gameOptions.getLearnEndgameEnabled()) { if (gameOptions.isEndgameLearningEnabled()) {
AIAlgorithm::loadEndgameFileToHashMap(); Thread::loadEndgameFileToHashMap();
} }
#endif #endif
@ -129,8 +129,8 @@ Game::~Game()
deleteAiThreads(); deleteAiThreads();
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
if (gameOptions.getLearnEndgameEnabled()) { if (gameOptions.isEndgameLearningEnabled()) {
Thread::recordEndgameHashMapToFile(); Thread::saveEndgameHashMapToFile();
} }
#endif /* ENDGAME_LEARNING */ #endif /* ENDGAME_LEARNING */
@ -286,18 +286,18 @@ void Game::gameReset()
emit statusBarChanged(message); emit statusBarChanged(message);
// 更新比分 LCD 显示 // 更新比分 LCD 显示
emit nGamesPlayedChanged(QString::number(position.nPlayed, 10)); emit nGamesPlayedChanged(QString::number(position.gamesPlayedCount, 10));
emit score1Changed(QString::number(position.score[BLACK], 10)); emit score1Changed(QString::number(position.score[BLACK], 10));
emit score2Changed(QString::number(position.score[WHITE], 10)); emit score2Changed(QString::number(position.score[WHITE], 10));
emit scoreDrawChanged(QString::number(position.score_draw, 10)); emit scoreDrawChanged(QString::number(position.score_draw, 10));
// 更新胜率 LCD 显示 // 更新胜率 LCD 显示
position.nPlayed = position.score[BLACK] + position.score[WHITE] + position.score_draw; position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0; int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
if (position.nPlayed != 0) { if (position.gamesPlayedCount != 0) {
winningRate_1 = position.score[BLACK] * 10000 / position.nPlayed; winningRate_1 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
winningRate_2 = position.score[WHITE] * 10000 / position.nPlayed; winningRate_2 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
winningRate_draw = position.score_draw * 10000 / position.nPlayed; winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
} }
emit winningRate1Changed(QString::number(winningRate_1, 10)); emit winningRate1Changed(QString::number(winningRate_1, 10));
@ -559,7 +559,7 @@ void Game::setLearnEndgame(bool enabled)
gameOptions.setLearnEndgameEnabled(enabled); gameOptions.setLearnEndgameEnabled(enabled);
#ifdef ENDGAME_LEARNING #ifdef ENDGAME_LEARNING
if (gameOptions.getLearnEndgameEnabled()) { if (gameOptions.isEndgameLearningEnabled()) {
Thread::loadEndgameFileToHashMap(); Thread::loadEndgameFileToHashMap();
} }
#endif #endif
@ -1364,12 +1364,12 @@ bool Game::updateScence(Position &p)
emit scoreDrawChanged(QString::number(p.score_draw, 10)); emit scoreDrawChanged(QString::number(p.score_draw, 10));
// 更新胜率 LCD 显示 // 更新胜率 LCD 显示
position.nPlayed = position.score[BLACK] + position.score[WHITE] + position.score_draw; position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0; int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
if (position.nPlayed != 0) { if (position.gamesPlayedCount != 0) {
winningRate_1 = position.score[BLACK] * 10000 / position.nPlayed; winningRate_1 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
winningRate_2 = position.score[WHITE] * 10000 / position.nPlayed; winningRate_2 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
winningRate_draw = position.score_draw * 10000 / position.nPlayed; winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
} }
emit winningRate1Changed(QString::number(winningRate_1, 10)); emit winningRate1Changed(QString::number(winningRate_1, 10));
@ -1450,16 +1450,16 @@ void Game::saveScore()
textStream << "" << endl; textStream << "" << endl;
position.nPlayed = position.score[BLACK] + position.score[WHITE] + position.score_draw; position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
if (position.nPlayed == 0) { if (position.gamesPlayedCount == 0) {
goto out; goto out;
} }
textStream << "Sum\t" + QString::number(position.nPlayed) << endl; textStream << "Sum\t" + QString::number(position.gamesPlayedCount) << endl;
textStream << "Black\t" + QString::number(position.score[BLACK]) + "\t" + QString::number(position.score[BLACK] * 10000 / position.nPlayed) << endl; textStream << "Black\t" + QString::number(position.score[BLACK]) + "\t" + QString::number(position.score[BLACK] * 10000 / position.gamesPlayedCount) << endl;
textStream << "White\t" + QString::number(position.score[WHITE]) + "\t" + QString::number(position.score[WHITE] * 10000 / position.nPlayed) << endl; textStream << "White\t" + QString::number(position.score[WHITE]) + "\t" + QString::number(position.score[WHITE] * 10000 / position.gamesPlayedCount) << endl;
textStream << "Draw\t" + QString::number(position.score_draw) + "\t" + QString::number(position.score_draw * 10000 / position.nPlayed) << endl; textStream << "Draw\t" + QString::number(position.score_draw) + "\t" + QString::number(position.score_draw * 10000 / position.gamesPlayedCount) << endl;
out: out:
file.flush(); file.flush();