代码清理
This commit is contained in:
parent
5aff5d8d29
commit
87ba471531
|
@ -11,18 +11,18 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
class HashNode
|
||||
{
|
||||
public:
|
||||
HashNode()
|
||||
HashNode()
|
||||
#ifndef DISABLE_HASHBUCKET
|
||||
: next(nullptr)
|
||||
#endif
|
||||
{}
|
||||
HashNode(K key_, V value_) :
|
||||
HashNode(K key_, V value_) :
|
||||
#ifndef DISABLE_HASHBUCKET
|
||||
next(nullptr),
|
||||
next(nullptr),
|
||||
#endif
|
||||
key(key_), value(value_)
|
||||
{}
|
||||
~HashNode()
|
||||
~HashNode()
|
||||
{
|
||||
#ifndef DISABLE_HASHBUCKET
|
||||
next = nullptr;
|
||||
|
@ -55,7 +55,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
~HashBucket() //delete the bucket
|
||||
{
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
//Function to find an entry in the bucket matching the key
|
||||
//If key is found, the corresponding value is copied into the parameter "value" and function returns true.
|
||||
|
@ -63,7 +63,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
bool find(const K &key, V &value) const
|
||||
{
|
||||
// A shared mutex is used to enable multiple concurrent reads
|
||||
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
HashNode<K, V> * node = head;
|
||||
#ifdef DISABLE_HASHBUCKET
|
||||
if (node == nullptr) {
|
||||
|
@ -120,14 +120,14 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
}
|
||||
else
|
||||
{
|
||||
prev->next = new HashNode<K, V>(key, value);
|
||||
prev->next = new HashNode<K, V>(key, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node->setValue(value); //Key found in bucket, update the value
|
||||
}
|
||||
#endif // DISABLE_HASHBUCKET
|
||||
#endif // DISABLE_HASHBUCKET
|
||||
}
|
||||
|
||||
//Function to remove an entry from the bucket, if found
|
||||
|
@ -168,7 +168,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
}
|
||||
else
|
||||
{
|
||||
prev->next = node->next;
|
||||
prev->next = node->next;
|
||||
}
|
||||
delete node; //Free up the memory
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
if (head != nullptr)
|
||||
{
|
||||
delete head;
|
||||
}
|
||||
}
|
||||
#else // DISABLE_HASHBUCKET
|
||||
HashNode<K, V> * prev = nullptr;
|
||||
HashNode<K, V> * node = head;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include <QDebug>
|
||||
#include "aithread.h"
|
||||
|
||||
AiThread::AiThread(int id, QObject *parent) :
|
||||
QThread(parent),
|
||||
AiThread::AiThread(int id, QObject *parent) :
|
||||
QThread(parent),
|
||||
chess_(nullptr),
|
||||
waiting_(false),
|
||||
aiDepth(2),
|
||||
waiting_(false),
|
||||
aiDepth(2),
|
||||
aiTime(120)
|
||||
{
|
||||
this->id = id;
|
||||
|
@ -35,7 +35,7 @@ void AiThread::setAi(const NineChess &chess)
|
|||
ai_ab.setChess(*(this->chess_));
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// TODO: 下第二盘时不明原因变慢,临时方案为清除哈希表
|
||||
// 新下一盘前清除哈希表 (注意可能同时存在每步之前清除)
|
||||
ai_ab.clearHashMap();
|
||||
#endif
|
||||
|
||||
|
@ -55,7 +55,7 @@ void AiThread::setAi(const NineChess &chess, int depth, int time)
|
|||
void AiThread::run()
|
||||
{
|
||||
// 测试用数据
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
int iTemp = 0;
|
||||
#endif
|
||||
|
||||
|
@ -84,14 +84,14 @@ void AiThread::run()
|
|||
emit calcStarted();
|
||||
mutex.unlock();
|
||||
|
||||
ai_ab.alphaBetaPruning(aiDepth); // 顶层调用 alphaBetaPruning(aiDepth)
|
||||
ai_ab.alphaBetaPruning(aiDepth); // 顶层调用ab剪枝
|
||||
const char *str = ai_ab.bestMove();
|
||||
qDebug() << "Computer:" << str << "\n";
|
||||
|
||||
if (strcmp(str, "error!"))
|
||||
emit command(str);
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
qDebug() << "Thread" << id << "run" << ++iTemp << "times";
|
||||
#endif
|
||||
|
||||
|
|
|
@ -104,13 +104,13 @@ void BoardItem::paint(QPainter *painter,
|
|||
painter->setPen(fontPen);
|
||||
QFont font;
|
||||
font.setPointSize(4);
|
||||
font.setFamily("Arial");
|
||||
font.setLetterSpacing(QFont::AbsoluteSpacing, 0);
|
||||
font.setFamily("Arial");
|
||||
font.setLetterSpacing(QFont::AbsoluteSpacing, 0);
|
||||
painter->setFont(font);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
char cSeat = '1' + i;
|
||||
QString strSeat(cSeat);
|
||||
QString strSeat(cSeat);
|
||||
painter->drawText(position[(N_RINGS - 1) * N_SEATS + i], strSeat);
|
||||
}
|
||||
#endif // DRAW_SEAT_NUMBER
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
//#define DEBUG
|
||||
//#define DEBUG_MODE
|
||||
|
||||
#define RANDOM_MOVE
|
||||
|
||||
|
@ -17,22 +17,18 @@
|
|||
|
||||
#define MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
#define DONOT_PLAY_SOUND
|
||||
#define DEBUG_AB_TREE
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG
|
||||
//#define AB_RANDOM_SORT_CHILDREN
|
||||
#endif
|
||||
|
||||
//#define DONOT_PLAY_SOUND
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
#define GAME_PLACING_FIXED_DEPTH 3
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
#define GAME_MOVING_FIXED_DEPTH 3
|
||||
#else // DEBUG
|
||||
#ifdef DEAL_WITH_HORIZON_EFFECT
|
||||
|
@ -46,11 +42,11 @@
|
|||
#endif // DEAL_WITH_HORIZON_EFFECT
|
||||
#endif // DEBUG
|
||||
|
||||
#ifndef DEBUG
|
||||
#ifndef DEBUG_MODE
|
||||
#define GAME_PLACING_DYNAMIC_DEPTH
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
#define DRAW_SEAT_NUMBER
|
||||
#endif
|
||||
|
||||
|
@ -67,6 +63,4 @@
|
|||
// 不使用哈希桶
|
||||
#define DISABLE_HASHBUCKET
|
||||
|
||||
//#define RANDOM_BEST_MOVE
|
||||
|
||||
#endif // CONFIG_H
|
|
@ -1,11 +1,11 @@
|
|||
#ifndef HASH_MAP_H_
|
||||
#define HASH_MAP_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include "HashNode.h"
|
||||
#include <mutex>
|
||||
#include "HashNode.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
//By default, the std::hash function will be used
|
||||
//If the hash size is not provided, then a defult size of 1031 will be used
|
||||
//The hash table itself consists of an array of hash buckets.
|
||||
//Each hash bucket is implemented as singly linked list with the head as a dummy node created
|
||||
//Each hash bucket is implemented as singly linked list with the head as a dummy node created
|
||||
//during the creation of the bucket. All the hash buckets are created during the construction of the map.
|
||||
//Locks are taken per bucket, hence multiple threads can write simultaneously in different buckets in the hash map
|
||||
#ifdef HASH_KEY_DISABLE
|
||||
|
@ -48,13 +48,13 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
//Copy and Move of the HashMap are not supported at this moment
|
||||
HashMap(const HashMap&) = delete;
|
||||
HashMap(HashMap&&) = delete;
|
||||
HashMap& operator=(const HashMap&) = delete;
|
||||
HashMap& operator=(const HashMap&) = delete;
|
||||
HashMap& operator=(HashMap&&) = delete;
|
||||
|
||||
|
||||
//Function to find an entry in the hash map matching the key.
|
||||
//If key is found, the corresponding value is copied into the parameter "value" and function returns true.
|
||||
//If key is not found, function returns false.
|
||||
bool find(const K &key, V &value) const
|
||||
bool find(const K &key, V &value) const
|
||||
{
|
||||
size_t hashValue = hashFn(key) & (hashSize - 1) ;
|
||||
#ifdef DISABLE_HASHBUCKET
|
||||
|
@ -66,7 +66,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
#else
|
||||
return hashTable[hashValue].find(key, value);
|
||||
#endif
|
||||
|
@ -74,7 +74,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
|
||||
//Function to insert into the hash map.
|
||||
//If key already exists, update the value, else insert a new node in the bucket with the <key, value> pair.
|
||||
void insert(const K &key, const V &value)
|
||||
void insert(const K &key, const V &value)
|
||||
{
|
||||
size_t hashValue = hashFn(key) & (hashSize - 1);
|
||||
#ifdef DISABLE_HASHBUCKET
|
||||
|
@ -87,7 +87,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
}
|
||||
|
||||
//Function to remove an entry from the bucket, if found
|
||||
void erase(const K &key)
|
||||
void erase(const K &key)
|
||||
{
|
||||
size_t hashValue = hashFn(key) & (hashSize - 1);
|
||||
#ifdef DISABLE_HASHBUCKET
|
||||
|
@ -95,7 +95,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
#else
|
||||
hashTable[hashValue].erase(key);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Function to clean up the hasp map, i.e., remove all entries from it
|
||||
|
@ -109,7 +109,7 @@ namespace CTSL //Concurrent Thread Safe Library
|
|||
(hashTable[i]).clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DISABLE_HASHBUCKET
|
||||
|
|
|
@ -123,7 +123,7 @@ NineChess::NineChess()
|
|||
// 单独提出 board 等数据,免得每次都写 context.board;
|
||||
board_ = context.board;
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
//hash_ = &context.hash;
|
||||
//zobrist_ = &context.zobrist;
|
||||
|
||||
|
@ -376,15 +376,15 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
|||
// 当前棋局(3×8)
|
||||
if (board == nullptr) {
|
||||
memset(context.board, 0, sizeof(context.board));
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
context.hash = 0ull;
|
||||
#endif
|
||||
} else {
|
||||
memcpy(context.board, board, sizeof(context.board));
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
//context.hash = hash;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// 计算盘面子数
|
||||
// 棋局,抽象为一个(5×8)的数组,上下两行留空
|
||||
|
@ -419,11 +419,11 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
|||
context.nPiecesOnBoard_2 > rule->nTotalPiecesEachSide) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (nPiecesInHand_1 < 0 || nPiecesInHand_2 < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
context.nPiecesInHand_1 = rule->nTotalPiecesEachSide - context.nPiecesOnBoard_1;
|
||||
context.nPiecesInHand_2 = rule->nTotalPiecesEachSide - context.nPiecesOnBoard_2;
|
||||
context.nPiecesInHand_1 = std::min(nPiecesInHand_1, context.nPiecesInHand_1);
|
||||
|
@ -489,7 +489,7 @@ void NineChess::getContext(struct Rule &rule, int &step, int &flags,
|
|||
nPiecesInHand_1 = context.nPiecesInHand_1;
|
||||
nPiecesInHand_2 = context.nPiecesInHand_2;
|
||||
num_NeedRemove = context.nPiecesNeedRemove;
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
//hash = context.hash;
|
||||
#endif
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ bool NineChess::reset()
|
|||
// 用时置零
|
||||
elapsedMS_1 = elapsedMS_2 = 0;
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 哈希归零
|
||||
context.hash = 0;
|
||||
#endif
|
||||
|
@ -662,7 +662,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 如非“落子”状态,返回false
|
||||
if (context.action != ACTION_PLACE)
|
||||
return false;
|
||||
|
||||
|
||||
// 转换为 pos
|
||||
int pos = cp2pos(c, p);
|
||||
|
||||
|
@ -693,7 +693,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
|
||||
board_[pos] = piece;
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
move_ = pos;
|
||||
|
@ -703,7 +703,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
cmdlist.push_back(string(cmdline));
|
||||
currentPos = pos;
|
||||
currentStep++;
|
||||
|
||||
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTips();
|
||||
|
@ -784,11 +784,11 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
c, p, player_ms / 60000, (player_ms % 60000) / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
board_[pos] = board_[currentPos];
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
board_[currentPos] = '\x00';
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(currentPos);
|
||||
#endif
|
||||
currentPos = pos;
|
||||
|
@ -860,15 +860,15 @@ bool NineChess::capture(int c, int p, long time_p /* = -1*/)
|
|||
|
||||
// 去子(设置禁点)
|
||||
if (currentRule.hasForbiddenPoint && context.stage == GAME_PLACING) {
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x0f';
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
} else { // 去子
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x00';
|
||||
|
@ -1036,7 +1036,7 @@ bool NineChess::place(int pos)
|
|||
|
||||
board_[pos] = piece;
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
move_ = pos;
|
||||
|
@ -1114,11 +1114,11 @@ bool NineChess::place(int pos)
|
|||
// 移子
|
||||
move_ = (currentPos << 8) + pos;
|
||||
board_[pos] = board_[currentPos];
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
board_[currentPos] = '\x00';
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(currentPos);
|
||||
#endif
|
||||
currentPos = pos;
|
||||
|
@ -1184,15 +1184,15 @@ bool NineChess::capture(int pos)
|
|||
}
|
||||
|
||||
if (currentRule.hasForbiddenPoint && context.stage == GAME_PLACING) {
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x0f';
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
} else { // 去子
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x00';
|
||||
|
@ -1206,7 +1206,7 @@ bool NineChess::capture(int pos)
|
|||
move_ = -pos;
|
||||
currentPos = 0;
|
||||
context.nPiecesNeedRemove--;
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
//step++;
|
||||
|
@ -1751,7 +1751,7 @@ void NineChess::cleanForbiddenPoints()
|
|||
for (int j = 0; j < N_SEATS; j++) {
|
||||
pos = i * N_SEATS + j;
|
||||
if (board_[pos] == '\x0f') {
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x00';
|
||||
|
@ -2300,7 +2300,7 @@ void NineChess::rotate(int degrees, bool cmdChange /*= true*/)
|
|||
}
|
||||
}
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
|
||||
#if 0
|
||||
/*
|
||||
|
@ -2345,30 +2345,19 @@ void NineChess::constructHash()
|
|||
|
||||
uint64_t NineChess::getHash()
|
||||
{
|
||||
updateHashMisc(); // 放在此处合适?
|
||||
// TODO: 每次获取哈希值时更新 hash 值低8位,放在此处调用不优雅
|
||||
updateHashMisc();
|
||||
|
||||
return context.hash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64_t NineChess::updateHash(int pos)
|
||||
{
|
||||
#if 0
|
||||
// 这里不做
|
||||
for (int i = POS_BEGIN; i < POS_END; i++) {
|
||||
hash ^= context.zobrist[i][pointType];
|
||||
}
|
||||
#endif
|
||||
|
||||
// PieceType is board_[pos]
|
||||
|
||||
// 0b00表示空白,0b01=1 表示先手棋子,0b10=2 表示后手棋子,0b11=3 表示禁点
|
||||
// 0b00 表示空白,0b01 = 1 表示先手棋子,0b10 = 2 表示后手棋子,0b11 = 3 表示禁点
|
||||
int pointType = (board_[pos] & 0x30) >> 4;
|
||||
|
||||
//context.hashCheckCode |= (temp) << ((pos - 8) * 2 + 6);
|
||||
// TODO: context.hash =
|
||||
|
||||
// 清除或者放置棋子
|
||||
context.hash ^= context.zobrist[pos][pointType];
|
||||
|
||||
|
@ -2395,9 +2384,8 @@ uint64_t NineChess::updateHashMisc()
|
|||
context.hash |= 1ULL << 1;
|
||||
}
|
||||
|
||||
// TODO: 是否真的需要这几位?
|
||||
context.hash |= (uint64_t)context.nPiecesNeedRemove << 2;
|
||||
context.hash |= (uint64_t)context.nPiecesInHand_1 << 4;
|
||||
context.hash |= (uint64_t)context.nPiecesInHand_1 << 4; // TODO: 或许换 game.stage 也可以?
|
||||
|
||||
return context.hash;
|
||||
}
|
||||
|
|
|
@ -127,16 +127,16 @@ public:
|
|||
};
|
||||
|
||||
uint64_t rand64(void) {
|
||||
return rand() ^
|
||||
return rand() ^
|
||||
((uint64_t)rand() << 15) ^
|
||||
((uint64_t)rand() << 30) ^
|
||||
((uint64_t)rand() << 45) ^
|
||||
((uint64_t)rand() << 30) ^
|
||||
((uint64_t)rand() << 45) ^
|
||||
((uint64_t)rand() << 60);
|
||||
}
|
||||
|
||||
uint64_t rand56(void)
|
||||
{
|
||||
return rand64() << 8;
|
||||
return rand64() << 8;
|
||||
}
|
||||
|
||||
// 玩家标识, 轮流状态, 胜负标识
|
||||
|
@ -184,7 +184,7 @@ public:
|
|||
*/
|
||||
int board[N_POINTS];
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 局面的哈希值
|
||||
uint64_t hash;
|
||||
|
||||
|
@ -225,7 +225,7 @@ public:
|
|||
// 尚待去除的子数
|
||||
int nPiecesNeedRemove;
|
||||
|
||||
#if 0
|
||||
#if 0
|
||||
本打算用如下的结构体来表示“三连”
|
||||
struct Mill {
|
||||
char piece1; // “三连”中最小的棋子
|
||||
|
@ -493,13 +493,13 @@ protected:
|
|||
bool place(int pos);
|
||||
bool capture(int pos);
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// hash相关
|
||||
uint64_t getHash();
|
||||
uint64_t revertHash(int pos);
|
||||
uint64_t updateHash(int pos);
|
||||
uint64_t updateHashMisc();
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
#endif
|
||||
|
||||
private:
|
||||
// 当前使用的规则
|
||||
|
|
|
@ -56,20 +56,28 @@ void NineChessAi_ab::buildRoot()
|
|||
rootNode = addNode(nullptr, 0, 0, 0, NineChess::NOBODY);
|
||||
}
|
||||
|
||||
struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, int move, int bestMove, enum NineChess::Player player)
|
||||
struct NineChessAi_ab::Node *NineChessAi_ab::addNode(
|
||||
Node *parent,
|
||||
int value,
|
||||
int move,
|
||||
int bestMove,
|
||||
enum NineChess::Player player
|
||||
)
|
||||
{
|
||||
Node *newNode = new Node; // (10%)
|
||||
Node *newNode = new Node;
|
||||
|
||||
newNode->parent = parent;
|
||||
newNode->value = value;
|
||||
newNode->move = move;
|
||||
|
||||
|
||||
nodeCount++;
|
||||
newNode->id = nodeCount;
|
||||
|
||||
newNode->pruned = false;
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
player = player; // Remove warning
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
newNode->hash = 0;
|
||||
#endif
|
||||
|
||||
|
@ -96,34 +104,30 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in
|
|||
|
||||
if (move < 0) {
|
||||
chessTemp.pos2cp(-move, c, p);
|
||||
sprintf(cmd, "-(%1u,%1u)", c, p); // (3%)
|
||||
sprintf(cmd, "-(%1u,%1u)", c, p);
|
||||
} else if (move & 0x7f00) {
|
||||
int c1, p1;
|
||||
chessTemp.pos2cp(move >> 8, c1, p1);
|
||||
chessTemp.pos2cp(move & 0x00ff, c, p);
|
||||
sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", c1, p1, c, p); // (7%)
|
||||
sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", c1, p1, c, p);
|
||||
} else {
|
||||
chessTemp.pos2cp(move & 0x007f, c, p);
|
||||
sprintf(cmd, "(%1u,%1u)", c, p); // (12%)
|
||||
sprintf(cmd, "(%1u,%1u)", c, p);
|
||||
}
|
||||
|
||||
newNode->cmd = cmd;
|
||||
#endif // DEBUG_AB_TREE
|
||||
|
||||
if (parent) {
|
||||
if (bestMove != 0 && move == bestMove) {
|
||||
// 把哈希得到的最优着法换到首位
|
||||
parent->children.insert(parent->children.begin(), newNode);
|
||||
// 若没有启用置换表,或启用了但为叶子节点,则 bestMove 为0
|
||||
if (bestMove == 0 || move != bestMove) {
|
||||
parent->children.push_back(newNode);
|
||||
} else {
|
||||
parent->children.push_back(newNode); // (7%)
|
||||
// 如果启用了置换表并且不是叶子结点,把哈希得到的最优着法换到首位
|
||||
parent->children.insert(parent->children.begin(), newNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if (bestMove != 0 && move == bestMove) {
|
||||
// std::swap(parent->children[0], parent->children[parent->children.size() - 1]);
|
||||
// }
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
|
@ -173,11 +177,12 @@ void NineChessAi_ab::generateLegalMoves(Node *node, int bestMove)
|
|||
const int MOVE_PRIORITY_TABLE_SIZE = NineChess::N_RINGS * NineChess::N_SEATS;
|
||||
int pos = 0;
|
||||
|
||||
node->children.reserve(48); // 余量空间 (2%)
|
||||
// 留足余量空间避免多次重新分配,此动作本身也占用 CPU/内存 开销
|
||||
node->children.reserve(48);
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
|
||||
|
||||
#else // RANDOM_MOVE
|
||||
int movePriorityTable[MOVE_PRIORITY_TABLE_SIZE] = {
|
||||
17, 19, 21, 23, // 星位
|
||||
|
@ -220,13 +225,13 @@ void NineChessAi_ab::generateLegalMoves(Node *node, int bestMove)
|
|||
addNode(node, INF_VALUE, pos, bestMove, chessTemp.context.turn);
|
||||
}
|
||||
} else {
|
||||
addNode(node, 0, pos, bestMove, chessTemp.context.turn); // (24%)
|
||||
addNode(node, 0, pos, bestMove, chessTemp.context.turn);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 对于移子阶段
|
||||
if (chessTemp.context.stage & NineChess::GAME_MOVING) {
|
||||
int newPos, oldPos;
|
||||
|
@ -265,9 +270,9 @@ void NineChessAi_ab::generateLegalMoves(Node *node, int bestMove)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// 对于吃子动作
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
if (chessTemp.isAllInMills(opponent)) {
|
||||
// 全成三的情况
|
||||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
|
@ -282,7 +287,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node, int bestMove)
|
|||
pos = movePriorityTable[i];
|
||||
if (chessTemp.board_[pos] & opponent) {
|
||||
if (chessTemp.getRule()->allowRemoveMill || !chessTemp.isInMills(pos)) {
|
||||
addNode(node, 0, -pos, bestMove, chessTemp.context.turn); // (6%)
|
||||
addNode(node, 0, -pos, bestMove, chessTemp.context.turn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -322,71 +327,11 @@ void NineChessAi_ab::sortLegalMoves(Node *node)
|
|||
{
|
||||
// 这个函数对效率的影响很大,排序好的话,剪枝较早,节省时间,但不能在此函数耗费太多时间
|
||||
|
||||
#ifdef AB_RANDOM_SORT_CHILDREN
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
node->children.sort([](Node* n1, Node* n2) {
|
||||
bool ret = false;
|
||||
if (n1->value > n2->value) {
|
||||
ret = true;
|
||||
} else if (n1->value < n2->value) {
|
||||
ret = false;
|
||||
} else if (n1->value == n2->value) {
|
||||
ret = n1->rand < n2->rand;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
} else {
|
||||
node->children.sort([](Node* n1, Node* n2) {
|
||||
bool ret = false;
|
||||
if (n1->value < n2->value) {
|
||||
ret = true;
|
||||
} else if (n1->value > n2->value) {
|
||||
ret = false;
|
||||
} else if (n1->value == n2->value) {
|
||||
ret = n1->rand < n2->rand;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
#else
|
||||
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
//node->children.sort([](Node *n1, Node *n2) {return n1->value > n2->value; }); // (6%)
|
||||
std::stable_sort(node->children.begin(), node->children.end(), nodeGreater);
|
||||
} else {
|
||||
//node->children.sort([](Node *n1, Node *n2) { return n1->value < n2->value; }); // (6%)
|
||||
std::stable_sort(node->children.begin(), node->children.end(), nodeLess);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
node->children.sort([](Node *n1, Node *n2) {
|
||||
bool ret = false;
|
||||
if (n1->value > n2->value) {
|
||||
ret = true;
|
||||
} else if (n1->value < n2->value) {
|
||||
ret = false;
|
||||
} else if (n1->value == n2->value) {
|
||||
ret = n1->pruned < n2->pruned;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
} else {
|
||||
node->children.sort([](Node *n1, Node *n2) {
|
||||
bool ret = false;
|
||||
if (n1->value < n2->value) {
|
||||
ret = true;
|
||||
} else if (n1->value > n2->value) {
|
||||
ret = false;
|
||||
} else if (n1->value == n2->value) {
|
||||
ret = n1->pruned > n2->pruned;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void NineChessAi_ab::deleteTree(Node *node)
|
||||
|
@ -410,6 +355,7 @@ void NineChessAi_ab::setChess(const NineChess &chess)
|
|||
#endif // HASH_MAP_ENABLE
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
// TODO: 规则改变时清空学习表
|
||||
//clearBookHashMap();
|
||||
//openingBook.clear();
|
||||
#endif // BOOK_LEARNING
|
||||
|
@ -476,7 +422,7 @@ int NineChessAi_ab::evaluate(Node *node)
|
|||
|
||||
// 如果形成去子状态,每有一个可去的子,算100分
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
nPiecesNeedRemove = (chessContext->turn == NineChess::PLAYER1) ?
|
||||
nPiecesNeedRemove = (chessContext->turn == NineChess::PLAYER1) ?
|
||||
chessContext->nPiecesNeedRemove : -(chessContext->nPiecesNeedRemove);
|
||||
value += nPiecesNeedRemove * 100;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
|
@ -501,7 +447,7 @@ int NineChessAi_ab::evaluate(Node *node)
|
|||
|
||||
// 如果形成去子状态,每有一个可去的子,算128分
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
nPiecesNeedRemove = (chessContext->turn == NineChess::PLAYER1) ?
|
||||
nPiecesNeedRemove = (chessContext->turn == NineChess::PLAYER1) ?
|
||||
chessContext->nPiecesNeedRemove : -(chessContext->nPiecesNeedRemove);
|
||||
value += nPiecesNeedRemove * 128;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
|
@ -563,7 +509,7 @@ int NineChessAi_ab::evaluate(Node *node)
|
|||
node->result = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -583,15 +529,11 @@ int NineChessAi_ab::changeDepth(int originalDepth)
|
|||
#ifdef GAME_PLACING_DYNAMIC_DEPTH
|
||||
#ifdef DEAL_WITH_HORIZON_EFFECT
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
int depthTable[] = { 8, 12, 12, 13, 13, 12, 11, 10, 10, 9, 9, 8, 1 };
|
||||
//int depthTable[] = { 2, 11, 11, 11, 11, 10, 9, 8, 8, 8, 7, 7, 1 };
|
||||
#else
|
||||
int depthTable[] = { 8, 12, 12, 13, 13, 12, 11, 10, 10, 9, 9, 8, 1 };
|
||||
#else // HASH_MAP_ENABLE
|
||||
int depthTable[] = { 2, 11, 11, 11, 11, 10, 9, 8, 8, 8, 7, 7, 1 };
|
||||
//int depthTable[] = { 8, 12, 12, 13, 13, 12, 11, 10, 10, 9, 9, 9, 1 };
|
||||
#endif // HASH_MAP_ENABLE
|
||||
//int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 9, 8, 8, 7, 1 };
|
||||
#else
|
||||
//int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 8, 8, 8, 7, 1 };
|
||||
#else // DEAL_WITH_HORIZON_EFFECT
|
||||
int depthTable[] = { 2, 13, 13, 13, 12, 11, 10, 9, 9, 8, 8, 7, 1 };
|
||||
#endif // DEAL_WITH_HORIZON_EFFECT
|
||||
newDepth = depthTable[chessTemp.getPiecesInHandCount_1()];
|
||||
|
@ -600,7 +542,7 @@ int NineChessAi_ab::changeDepth(int originalDepth)
|
|||
#endif // GAME_PLACING_DYNAMIC_DEPTH
|
||||
}
|
||||
|
||||
#ifdef GAME_MOVING_FIXED_DEPTH
|
||||
#ifdef GAME_MOVING_FIXED_DEPTH
|
||||
// 走棋阶段将深度调整
|
||||
if ((chessTemp.context.stage) & (NineChess::GAME_MOVING)) {
|
||||
newDepth = GAME_MOVING_FIXED_DEPTH;
|
||||
|
@ -628,7 +570,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth)
|
|||
if (chess_.getStage() == NineChess::GAME_PLACING)
|
||||
{
|
||||
if (chess_.context.nPiecesInHand_1 < 8) {
|
||||
// 不是一开始就记录到开局库
|
||||
// 不是一开始就记录到开局库, 几着之后再记录
|
||||
openingBook.push_back(chess_.getHash());
|
||||
} else {
|
||||
// 暂时在此处清空开局库
|
||||
|
@ -640,14 +582,14 @@ int NineChessAi_ab::alphaBetaPruning(int depth)
|
|||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
shuffleMovePriorityTable();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // RANDOM_MOVE
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
||||
#ifdef IDS_SUPPORT
|
||||
// 深化迭代
|
||||
for (int i = 2; i < d; i += 2) {
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
clearHashMap();
|
||||
clearHashMap(); // 每次走子前清空哈希表
|
||||
#endif
|
||||
alphaBetaPruning(i, -INF_VALUE, INF_VALUE, rootNode);
|
||||
}
|
||||
|
@ -658,6 +600,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth)
|
|||
#ifdef HASH_MAP_ENABLE
|
||||
clearHashMap(); // 每次走子前清空哈希表
|
||||
#endif
|
||||
|
||||
value = alphaBetaPruning(d, -INF_VALUE /* alpha */, INF_VALUE /* beta */, rootNode);
|
||||
|
||||
qDebug() << "Total Time: " << time1.elapsed() / 1000.0 << "s\n";
|
||||
|
@ -686,7 +629,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
bool hitBook = false;
|
||||
#endif
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 哈希值
|
||||
HashValue hashValue;
|
||||
memset(&hashValue, 0, sizeof(hashValue));
|
||||
|
@ -703,7 +646,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 检索开局库
|
||||
if (findBookHash(hash, hashValue)) {
|
||||
if (chessContext->turn == NineChess::PLAYER2) {
|
||||
// 是否需对后手扣分
|
||||
// 是否需对后手扣分 // TODO: 先后手都处理
|
||||
hitBook = true;
|
||||
}
|
||||
}
|
||||
|
@ -713,9 +656,6 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 检索 hashmap
|
||||
//hashMapMutex.lock();
|
||||
|
||||
// 从地址里一定可以读取出东西,found 恒定为 true?
|
||||
//bool found = findHash(hash, hashValue);
|
||||
|
||||
HashType type = hashfEMPTY;
|
||||
|
||||
int probeVal = probeHash(hash, depth, alpha, beta, bestMove, type);
|
||||
|
@ -726,60 +666,20 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
node->value = probeVal;
|
||||
|
||||
if (type != hashfEXACT && type != hashfEMPTY) {
|
||||
node->pruned = true;
|
||||
node->pruned = true; // TODO: 是否有用?
|
||||
}
|
||||
|
||||
// // TODO: 有必要?
|
||||
// if (chessContext->turn == NineChess::PLAYER1)
|
||||
// node->value += hashValue.depth - depth;
|
||||
// else
|
||||
// node->value -= hashValue.depth - depth;
|
||||
#if 0
|
||||
// TODO: 有必要针对深度微调 value?
|
||||
if (chessContext->turn == NineChess::PLAYER1)
|
||||
node->value += hashValue.depth - depth;
|
||||
else
|
||||
node->value -= hashValue.depth - depth;
|
||||
#endif
|
||||
|
||||
return node->value;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (node != rootNode &&
|
||||
hashValue.hash == hash && // 校验放在这里?
|
||||
hashValue.depth >= depth) { // 大于还是大于或等于?
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->isHash = true;
|
||||
#endif
|
||||
// TODO: 处理 Alpha/Beta 确切值
|
||||
if (hashValue.type == hashfEXACT) {
|
||||
hashHitCount++;
|
||||
node->value = hashValue.value;
|
||||
alpha = hashValue.alpha;
|
||||
beta = hashValue.beta;
|
||||
|
||||
// Why? 对 depth 的调整放在这里合适?
|
||||
if (chessContext->turn == NineChess::PLAYER1)
|
||||
node->value += hashValue.depth - depth;
|
||||
else
|
||||
node->value -= hashValue.depth - depth;
|
||||
|
||||
//hashMapMutex::unlock();
|
||||
|
||||
return node->value;
|
||||
}
|
||||
|
||||
if (hashValue.type == hashfALPHA) {
|
||||
alpha = hashValue.alpha;
|
||||
}
|
||||
|
||||
if (hashValue.type == hashfBETA) {
|
||||
beta = hashValue.beta;
|
||||
}
|
||||
|
||||
minMax = chessTemp.whosTurn() == NineChess::PLAYER1 ? -INF_VALUE : INF_VALUE;
|
||||
|
||||
if (alpha >= beta) {
|
||||
node->value = hashValue.value;
|
||||
return node->value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//hashMapMutex.unlock();
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
|
||||
|
@ -797,11 +697,11 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
#endif // HASH_MAP_ENABLE
|
||||
#endif // DEBUG_AB_TREE
|
||||
|
||||
// 搜索到叶子节点(决胜局面) TODO: 是否应该先检索哈希?
|
||||
// 搜索到叶子节点(决胜局面) // TODO: 对哈希进行特殊处理
|
||||
if (chessContext->stage == NineChess::GAME_OVER) {
|
||||
// 局面评估
|
||||
node->value = evaluate(node);
|
||||
|
||||
|
||||
// 为争取速胜,value 值 +- 深度
|
||||
if (node->value > 0)
|
||||
node->value += depth;
|
||||
|
@ -835,7 +735,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
if (requiredQuit) {
|
||||
node->isTimeout = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// 记录确切的哈希值
|
||||
|
@ -848,19 +748,16 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 生成子节点树,即生成每个合理的着法
|
||||
generateLegalMoves(node, bestMove); // (43%)
|
||||
|
||||
// 排序子节点树
|
||||
//sortChildren(node);
|
||||
|
||||
// 根据演算模型执行 MiniMax 检索,对先手,搜索 Max, 对后手,搜索 Min
|
||||
|
||||
minMax = chessTemp.whosTurn() == NineChess::PLAYER1 ? -INF_VALUE : INF_VALUE;
|
||||
|
||||
for (auto child : node->children) {
|
||||
// 上下文入栈保存,以便后续撤销着法
|
||||
contextStack.push(chessTemp.context); // (7%)
|
||||
contextStack.push(chessTemp.context);
|
||||
|
||||
// 执行着法
|
||||
chessTemp.command(child->move); // (13%)
|
||||
chessTemp.command(child->move);
|
||||
|
||||
#ifdef DEAL_WITH_HORIZON_EFFECT
|
||||
// 克服“水平线效应”: 若遇到吃子,则搜索深度增加
|
||||
|
@ -870,13 +767,13 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
else {
|
||||
epsilon = 0;
|
||||
}
|
||||
#endif
|
||||
#endif // DEAL_WITH_HORIZON_EFFECT
|
||||
|
||||
// 递归 Alpha-Beta 剪枝
|
||||
value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child);
|
||||
|
||||
// 上下文弹出栈,撤销着法
|
||||
chessTemp.context = contextStack.top(); // (5%)
|
||||
chessTemp.context = contextStack.top();
|
||||
contextStack.pop();
|
||||
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
|
@ -887,11 +784,10 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
|
||||
// α 为走棋一方搜索到的最好值,任何比它小的值对当前结点的走棋方都没有意义
|
||||
// 如果某个着法的结果小于或等于 α,那么它就是很差的着法,因此可以抛弃
|
||||
//alpha = std::max(value, alpha);
|
||||
|
||||
if (value > alpha) {
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
hashf = hashfEXACT; // ????
|
||||
hashf = hashfEXACT;
|
||||
#endif
|
||||
alpha = value;
|
||||
}
|
||||
|
@ -910,12 +806,16 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 如果搜索过程中返回 β 或比 β 更好的值,那就够好的了,走棋的一方就没有机会使用这种策略了。
|
||||
// 如果某个着法的结果大于或等于 β,那么整个结点就作废了,因为对手不希望走到这个局面,而它有别的着法可以避免到达这个局面。
|
||||
// 因此如果我们找到的评价大于或等于β,就证明了这个结点是不会发生的,因此剩下的合理着法没有必要再搜索。
|
||||
|
||||
// TODO: 本意是要删掉这句,忘了删,结果反而棋力没有明显问题,待查
|
||||
// 如果删掉这句,三有时不会堵并且计算效率较低
|
||||
// 有了这句之后,hashf 不可能等于 hashfBETA
|
||||
beta = std::min(value, beta);
|
||||
|
||||
if (value < beta)
|
||||
{
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
hashf = hashfBETA; // ????
|
||||
hashf = hashfBETA;
|
||||
#endif
|
||||
beta = value;
|
||||
}
|
||||
|
@ -926,19 +826,16 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
if (alpha >= beta) {
|
||||
node->pruned = true;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
//hashf = hashfBETA; // ????
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node->value = minMax;
|
||||
node->value = minMax;
|
||||
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->alpha = alpha;
|
||||
node->beta = beta;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 删除“孙子”节点,防止层数较深的时候节点树太大
|
||||
#ifndef DONOT_DELETE_TREE
|
||||
|
@ -951,35 +848,12 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
|
||||
#ifdef IDS_SUPPORT
|
||||
// 排序子节点树
|
||||
sortLegalMoves(node); // (13%)
|
||||
sortLegalMoves(node);
|
||||
#endif // IDS_SUPPORT
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// 记录不一定确切的哈希值
|
||||
// 记录不一定确切的哈希值
|
||||
recordHash(node->value, depth, hashf, hash, node->children[0]->move);
|
||||
|
||||
#if 0
|
||||
if (hashValue.hash != hash) {
|
||||
// 添加到hashmap
|
||||
HashValue newHashValue;
|
||||
newHashValue.alpha = alpha;
|
||||
newHashValue.beta = beta;
|
||||
newHashValue.depth = depth;
|
||||
newHashValue.type = hashf;
|
||||
newHashValue.hash = hash;
|
||||
newHashValue.value = node->value;
|
||||
recordHash(newHashValue);
|
||||
}
|
||||
// 更新更深层数据
|
||||
else {
|
||||
//hashMapMutex.lock();
|
||||
if (hashValue.depth < depth) {
|
||||
hashValue.value = node->value;
|
||||
hashValue.depth = depth;
|
||||
}
|
||||
//hashMapMutex.unlock();
|
||||
}
|
||||
#endif
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
|
@ -995,7 +869,6 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
const char* NineChessAi_ab::bestMove()
|
||||
{
|
||||
vector<Node*> bestMoves;
|
||||
size_t retIndex = 0;
|
||||
size_t bestMovesSize = 0;
|
||||
|
||||
if ((rootNode->children).size() == 0)
|
||||
|
@ -1046,28 +919,14 @@ const char* NineChessAi_ab::bestMove()
|
|||
nodeCount = 0;
|
||||
evaluatedNodeCount = 0;
|
||||
|
||||
#ifdef RANDOM_BEST_MOVE
|
||||
time_t time0 = time(0);
|
||||
|
||||
if (time0 % 10 == 0) {
|
||||
retIndex = bestMovesSize > 1 ? 1 : 0;
|
||||
}
|
||||
#else
|
||||
retIndex = 0;
|
||||
#endif
|
||||
|
||||
#ifdef RANDOM_BEST_MOVE
|
||||
qDebug() << "Return" << retIndex << "of" << bestMovesSize << "results" << "(" << time0 << ")";
|
||||
#endif
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
qDebug() << "Hash hit count:" << hashHitCount;
|
||||
#endif
|
||||
|
||||
return move2string(bestMoves[retIndex]->move);
|
||||
return move2string(bestMoves[0]->move);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const char *NineChessAi_ab::move2string(int move)
|
||||
{
|
||||
|
@ -1092,7 +951,7 @@ int NineChessAi_ab::probeHash(uint64_t hash, int depth, int alpha, int beta, int
|
|||
{
|
||||
const int valUNKNOWN = INT32_MIN;
|
||||
HashValue hashValue;
|
||||
|
||||
|
||||
if (hashmap.find(hash, hashValue) == false) {
|
||||
return valUNKNOWN;
|
||||
}
|
||||
|
@ -1163,7 +1022,6 @@ bool NineChessAi_ab::findHash(uint64_t hash, HashValue &hashValue)
|
|||
int NineChessAi_ab::recordHash(const HashValue &hashValue)
|
||||
{
|
||||
//hashMapMutex.lock();
|
||||
//HashMap<HashValue>::insert(hashValue.hash, hashValue);
|
||||
hashmap.insert(hashValue.hash, hashValue);
|
||||
//hashMapMutex.unlock();
|
||||
|
||||
|
@ -1177,12 +1035,12 @@ int NineChessAi_ab::recordHash(int value, int depth, HashType type, uint64_t has
|
|||
|
||||
//hashMapMutex.lock();
|
||||
HashValue hashValue;
|
||||
memset(&hashValue, 0, sizeof(HashValue));
|
||||
memset(&hashValue, 0, sizeof(HashValue));
|
||||
|
||||
if (findHash(hash, hashValue) &&
|
||||
if (findHash(hash, hashValue) &&
|
||||
hashValue.type != hashfEMPTY &&
|
||||
hashValue.depth > depth) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_MODE
|
||||
qDebug() << "Skip recordHash coz depth";
|
||||
#endif
|
||||
return -1;
|
||||
|
@ -1195,7 +1053,7 @@ int NineChessAi_ab::recordHash(int value, int depth, HashType type, uint64_t has
|
|||
hashValue.bestMove = bestMove;
|
||||
|
||||
hashmap.insert(hashValue.hash, hashValue);
|
||||
|
||||
|
||||
//hashMapMutex.unlock();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
struct Node* parent; // 父节点
|
||||
size_t id; // 结点编号
|
||||
bool pruned; // 是否在此处剪枝
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
uint64_t hash; // 哈希值
|
||||
#endif
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
|
@ -50,7 +50,7 @@ public:
|
|||
int depth; // 深度
|
||||
bool evaluated; // 是否评估过局面
|
||||
int alpha; // 当前搜索结点走棋方搜索到的最好值,任何比它小的值对当前结点的走棋方都没有意义。当函数递归时 Alpha 和 Beta 不但取负数而且要交换位置
|
||||
int beta; // 表示对手目前的劣势,这是对手所能承受的最坏结果,Beta 值越大,表示对手劣势越明显,如果当前结点返回 Beta 或比 Beta 更好的值,作为父结点的对方就绝对不会选择这种策略
|
||||
int beta; // 表示对手目前的劣势,这是对手所能承受的最坏结果,Beta 值越大,表示对手劣势越明显,如果当前结点返回 Beta 或比 Beta 更好的值,作为父结点的对方就绝对不会选择这种策略
|
||||
bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出
|
||||
bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面
|
||||
bool visited; // 是否在遍历时访问过
|
||||
|
@ -62,26 +62,9 @@ public:
|
|||
int result; // 终局结果,-1为负,0为未到终局,1为胜,走棋阶段被闷棋则为 -2/2,布局阶段闷棋为 -3
|
||||
struct Node* root; // 根节点
|
||||
#endif /* DEBUG_AB_TREE */
|
||||
|
||||
#if 0
|
||||
bool operator < (const Node &another) const
|
||||
{
|
||||
return this->value < another.value;
|
||||
}
|
||||
|
||||
bool operator > (const Node &another) const
|
||||
{
|
||||
return this->value > another.value;
|
||||
}
|
||||
|
||||
bool operator == (const Node &another) const
|
||||
{
|
||||
return this->value == another.value;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 定义哈希值的类型
|
||||
enum HashType
|
||||
{
|
||||
|
@ -120,7 +103,7 @@ public:
|
|||
// 返回最佳走法的命令行
|
||||
const char *bestMove();
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 清空哈希表
|
||||
void clearHashMap();
|
||||
#endif
|
||||
|
@ -190,7 +173,7 @@ private:
|
|||
|
||||
NineChess::ChessContext *chessContext;
|
||||
|
||||
// hash计算时,各种转换用的模型
|
||||
// hash 计算时,各种转换用的模型
|
||||
NineChess chessTempShift;
|
||||
|
||||
// 根节点
|
||||
|
@ -231,10 +214,6 @@ private:
|
|||
private:
|
||||
// 命令行
|
||||
char cmdline[32];
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
//HashMap<struct HashValue> hashmap;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue