diff --git a/NineChess/ninechess.pro b/NineChess/ninechess.pro
index 9d19cf0f..79161391 100644
--- a/NineChess/ninechess.pro
+++ b/NineChess/ninechess.pro
@@ -37,7 +37,7 @@ HEADERS += \
src/gamescene.h \
src/gameview.h \
src/graphicsconst.h \
- src/hashmap.h \
+ src/hashMap.h \
src/ninechess.h \
src/ninechessai_ab.h \
src/ninechesswindow.h \
diff --git a/NineChess/ninechess.vcxproj b/NineChess/ninechess.vcxproj
index f9a59b74..b57f59bd 100644
--- a/NineChess/ninechess.vcxproj
+++ b/NineChess/ninechess.vcxproj
@@ -378,7 +378,6 @@
-
@@ -427,7 +426,8 @@
-
+
+
.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;debug;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories)
diff --git a/NineChess/ninechess.vcxproj.filters b/NineChess/ninechess.vcxproj.filters
index 5d243ebe..59838707 100644
--- a/NineChess/ninechess.vcxproj.filters
+++ b/NineChess/ninechess.vcxproj.filters
@@ -84,9 +84,6 @@
Model
-
- Model
-
@@ -113,7 +110,10 @@
Control
-
+
+ Model
+
+
Model
diff --git a/NineChess/src/HashNode.h b/NineChess/src/HashNode.h
new file mode 100644
index 00000000..625fa0db
--- /dev/null
+++ b/NineChess/src/HashNode.h
@@ -0,0 +1,155 @@
+#ifndef HASH_NODE_H_
+#define HASH_NODE_H_
+
+#include
+namespace CTSL //Concurrent Thread Safe Library
+{
+ // Class representing a templatized hash node
+ template
+ class HashNode
+ {
+ public:
+ HashNode() : next(nullptr)
+ {}
+ HashNode(K key_, V value_) : next(nullptr), key(key_), value(value_)
+ {}
+ ~HashNode()
+ {
+ next = nullptr;
+ }
+
+ const K& getKey() const {return key;}
+ void setValue(V value_) {value = value_;}
+ const V& getValue() const {return value;}
+
+ HashNode *next; //Pointer to the next node in the same bucket
+ private:
+ K key; //the hash key
+ V value; //the value corresponding to the key
+ };
+
+
+ //Class representing a hash bucket. The bucket is implemented as a singly linked list.
+ //A bucket is always constructed with a dummy head node
+ template
+ class HashBucket
+ {
+ public:
+ HashBucket() : head(nullptr)
+ {}
+
+ ~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.
+ //If key is not found, function returns false
+ bool find(const K &key, V &value) const
+ {
+ // A shared mutex is used to enable mutiple concurrent reads
+ std::shared_lock lock(mutex_);
+ HashNode * node = head;
+
+ while (node != nullptr)
+ {
+ if (node->getKey() == key)
+ {
+ value = node->getValue();
+ return true;
+ }
+ node = node->next;
+ }
+ return false;
+ }
+
+ //Function to insert into the bucket
+ //If key already exists, update the value, else insert a new node in the bucket with the pair
+ void insert(const K &key, const V &value)
+ {
+ //Exclusive lock to enable single write in the bucket
+ std::unique_lock lock(mutex_);
+ HashNode * prev = nullptr;
+ HashNode * node = head;
+
+ while (node != nullptr && node->getKey() != key)
+ {
+ prev = node;
+ node = node->next;
+ }
+
+ if (nullptr == node) //New entry, create a node and add to bucket
+ {
+ if(nullptr == head)
+ {
+ head = new HashNode(key, value);
+ }
+ else
+ {
+ prev->next = new HashNode(key, value);
+ }
+ }
+ else
+ {
+ node->setValue(value); //Key found in bucket, update the value
+ }
+
+ }
+
+ //Function to remove an entry from the bucket, if found
+ void erase(const K &key)
+ {
+ //Exclusive lock to enable single write in the bucket
+ std::unique_lock lock(mutex_);
+ HashNode *prev = nullptr;
+ HashNode * node = head;
+
+ while (node != nullptr && node->getKey() != key)
+ {
+ prev = node;
+ node = node->next;
+ }
+
+ if (nullptr == node) //Key not found, nothing to be done
+ {
+ return;
+ }
+ else //Remove the node from the bucket
+ {
+ if(head == node)
+ {
+ head = node->next;
+ }
+ else
+ {
+ prev->next = node->next;
+ }
+ delete node; //Free up the memory
+ }
+ }
+
+ //Function to clear the bucket
+ void clear()
+ {
+ //Exclusive lock to enable single write in the bucket
+ std::unique_lock lock(mutex_);
+ HashNode * prev = nullptr;
+ HashNode * node = head;
+ while(node != nullptr)
+ {
+ prev = node;
+ node = node->next;
+ delete prev;
+ }
+ head = nullptr;
+ }
+
+ private:
+ HashNode * head; //The head node of the bucket
+ mutable std::shared_timed_mutex mutex_; //The mutex for this bucket
+ };
+}
+
+#endif
+
diff --git a/NineChess/src/aithread.cpp b/NineChess/src/aithread.cpp
index 618ad2e9..9df0ced2 100644
--- a/NineChess/src/aithread.cpp
+++ b/NineChess/src/aithread.cpp
@@ -35,7 +35,7 @@ void AiThread::setAi(const NineChess &chess)
ai_ab.setChess(*(this->chess_));
#ifdef HASH_MAP_ENABLE
- ai_ab.clearHashMap();
+ //ai_ab.clearHashMap();
#endif
mutex.unlock();
diff --git a/NineChess/src/hashmap.cpp b/NineChess/src/hashmap.cpp
index 9e6bcc28..54156500 100644
--- a/NineChess/src/hashmap.cpp
+++ b/NineChess/src/hashmap.cpp
@@ -79,6 +79,7 @@ void HashBucket::erase(const K &key)
}
}
+#if 0
// Function to clear the bucket
template
void HashBucket::clear()
@@ -94,6 +95,7 @@ void HashBucket::clear()
}
head = nullptr;
}
+#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/NineChess/src/hashmap.h b/NineChess/src/hashmap.h
index d264ad73..e59bc4e5 100644
--- a/NineChess/src/hashmap.h
+++ b/NineChess/src/hashmap.h
@@ -1,134 +1,80 @@
-#ifndef HASH_MAP_H_
-#define HASH_MAP_H_
-
-#include
-#include
-#include
-#include
-#include
-
-constexpr size_t HASH_SIZE_DEFAULT = 1031; // A prime number as hash size gives a better distribution of values in buckets
-
-namespace CTSL //Concurrent Thread Safe Library
-{
-// Class representing a templatized hash node
-template
-class HashNode
-{
-public:
- HashNode() : next(nullptr)
- {
- }
- HashNode(K key_, V value_) : next(nullptr), key(key_), value(value_)
- {
- }
- ~HashNode()
- {
- next = nullptr;
- }
-
- const K &getKey() const
- {
- return key;
- }
- void setValue(V value_)
- {
- value = value_;
- }
- const V &getValue() const
- {
- return value;
- }
-
- HashNode *next; // Pointer to the next node in the same bucket
-private:
- K key; // the hash key
- V value; // the value corresponding to the key
-};
-
-
-// Class representing a hash bucket. The bucket is implemented as a singly linked list.
-// A bucket is always constructed with a dummy head node
-template
-class HashBucket
-{
-public:
- HashBucket() : head(nullptr)
- {
- }
-
- ~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.
- // If key is not found, function returns false
- bool find(const K &key, V &value) const;
-
- // Function to insert into the bucket
- // If key already exists, update the value, else insert a new node in the bucket with the pair
- void insert(const K &key, const V &value);
-
- // Function to remove an entry from the bucket, if found
- void erase(const K &key);
-
- // Function to clear the bucket
- void clear();
-
-private:
- HashNode *head; //The head node of the bucket
- mutable std::shared_timed_mutex mutex_; //The mutex for this bucket
-};
-
-// The class represting the hash map.
-// It is expected for user defined types, the hash function will be provided.
-// 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
-// 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
-template >
-class HashMap
-{
-public:
- HashMap(size_t hashSize_ = HASH_SIZE_DEFAULT) : hashSize(hashSize_)
- {
- hashTable = new HashBucket[hashSize]; // create the hash table as an array of hash buckets
- }
-
- ~HashMap()
- {
- delete[] hashTable;
- }
-
- // 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=(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;
-
- // Function to insert into the hash map.
- // If key already exists, update the value, else insert a new node in the bucket with the pair.
- void insert(const K &key, const V &value);
-
- // Function to remove an entry from the bucket, if found
- void erase(const K &key);
-
- // Function to clean up the hasp map, i.e., remove all entries from it
- void clear();
-
-private:
- HashBucket *hashTable;
- F hashFn;
- const size_t hashSize;
-};
-}
-#endif /* HASH_MAP_H_ */
+#ifndef HASH_MAP_H_
+#define HASH_MAP_H_
+
+#include
+#include
+#include
+#include
+#include "HashNode.h"
+
+constexpr size_t HASH_SIZE_DEFAULT = 1031; // A prime number as hash size gives a better distribution of values in buckets
+namespace CTSL //Concurrent Thread Safe Library
+{
+ //The class represting the hash map.
+ //It is expected for user defined types, the hash function will be provided.
+ //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
+ //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
+ template >
+ class HashMap
+ {
+ public:
+ HashMap(size_t hashSize_ = HASH_SIZE_DEFAULT) : hashSize(hashSize_)
+ {
+ hashTable = new HashBucket[hashSize]; //create the hash table as an array of hash buckets
+ }
+
+ ~HashMap()
+ {
+ delete [] hashTable;
+ }
+ //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=(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
+ {
+ size_t hashValue = hashFn(key) % hashSize ;
+ return hashTable[hashValue].find(key, value);
+ }
+
+ //Function to insert into the hash map.
+ //If key already exists, update the value, else insert a new node in the bucket with the pair.
+ void insert(const K &key, const V &value)
+ {
+ size_t hashValue = hashFn(key) % hashSize ;
+ hashTable[hashValue].insert(key, value);
+ }
+
+ //Function to remove an entry from the bucket, if found
+ void erase(const K &key)
+ {
+ size_t hashValue = hashFn(key) % hashSize ;
+ hashTable[hashValue].erase(key);
+ }
+
+ //Function to clean up the hasp map, i.e., remove all entries from it
+ void clear()
+ {
+ for(size_t i = 0; i < hashSize; i++)
+ {
+ (hashTable[i]).clear();
+ }
+ }
+
+ private:
+ HashBucket * hashTable;
+ F hashFn;
+ const size_t hashSize;
+ };
+}
+#endif
+
diff --git a/NineChess/src/ninechess.cpp b/NineChess/src/ninechess.cpp
index 80bc33ea..46ea56dd 100644
--- a/NineChess/src/ninechess.cpp
+++ b/NineChess/src/ninechess.cpp
@@ -183,7 +183,6 @@ NineChess::~NineChess()
void NineChess::constructHash()
{
context.hash = 0ull;
- context.hashCheckCode = 0ull;
context.gameMovingHash = rand64();
context.actionCaptureHash = rand64();
@@ -397,7 +396,6 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
memset(context.board, 0, sizeof(context.board));
#ifdef HASH_MAP_ENABLE
context.hash = 0ull;
- context.hashCheckCode = 0ull;
#endif
} else {
memcpy(context.board, board, sizeof(context.board));
@@ -557,9 +555,8 @@ bool NineChess::reset()
elapsedMS_1 = elapsedMS_2 = 0;
#ifdef HASH_MAP_ENABLE
- // 哈希以及哈希校验码归零
+ // 哈希归零
context.hash = 0;
- context.hashCheckCode = 0;
#endif
// 提示
@@ -1324,14 +1321,10 @@ uint64_t NineChess::getHash()
return context.hash;
}
-uint64_t NineChess::getHashCheckCode()
-{
- return context.hashCheckCode;
-}
-
// hash函数,对应可重复去子的规则
uint64_t NineChess::updateHash(int pos)
{
+#if 0
/*
* hashCheckCode 各数据位详解(并无冲突,是算法用到的棋局数据的完全表示)
* 56-63位:空白不用,全为0
@@ -1342,33 +1335,33 @@ uint64_t NineChess::updateHash(int pos)
* 4-5位(共2位):待去子数,最大为3,用2个二进制位表示即可
* 0-3位:player1的手棋数,不需要player2的(可计算出)
*/
+#endif
uint64_t hash = 0ull;
- // TODO: 本函数效率低下,啥时调用?
for (int i = POS_BEGIN; i < POS_END; i++) {
// hash ^= context.zobrist[i][pointType]; // TODO: 待完善
}
uint64_t temp = board_[pos] & 0x30 >> 4;
- context.hashCheckCode |= (temp) << ((pos - 8) * 2 + 6);
+ //context.hashCheckCode |= (temp) << ((pos - 8) * 2 + 6);
// TODO: context.hash =
if (context.turn == PLAYER2) {
- context.hashCheckCode |= 1ull << 55;
+ //context.hashCheckCode |= 1ull << 55;
context.hash ^= context.player2sTurnHash;
}
if (context.action == ACTION_CAPTURE) {
- context.hashCheckCode |= 1ull << 54;
+ //context.hashCheckCode |= 1ull << 54;
context.hash ^= context.actionCaptureHash;
}
- context.hashCheckCode |= (uint64_t)context.nPiecesNeedRemove << 4;
- context.hashCheckCode |= context.nPiecesInHand_1;
+ //context.hashCheckCode |= (uint64_t)context.nPiecesNeedRemove << 4;
+ //context.hashCheckCode |= context.nPiecesInHand_1;
// TODO: hash 应该 不需要
- return context.hashCheckCode; // TODO: 返回什么
+ return context.hash; // TODO: 返回什么
}
#endif /* HASH_MAP_ENABLE */
diff --git a/NineChess/src/ninechess.h b/NineChess/src/ninechess.h
index bc845e99..dd37577b 100644
--- a/NineChess/src/ninechess.h
+++ b/NineChess/src/ninechess.h
@@ -180,15 +180,9 @@ public:
int board[N_POINTS];
#ifdef HASH_MAP_ENABLE
- // 局面哈希的校验码(过时)
- uint64_t hashCheckCode;
-
// 局面的哈希值
uint64_t hash;
- // 哈希表中的地址, 为 hash 的后 16 位
- uint16_t hashAddr;
-
// 标记处于走子阶段的哈希
uint64_t gameMovingHash;
@@ -497,7 +491,6 @@ protected:
#ifdef HASH_MAP_ENABLE
// hash相关
uint64_t getHash();
- uint64_t getHashCheckCode();
uint64_t updateHash(int pos);
#endif /* HASH_MAP_ENABLE */
diff --git a/NineChess/src/ninechessai_ab.cpp b/NineChess/src/ninechessai_ab.cpp
index 9fb1a12a..50fe6e67 100644
--- a/NineChess/src/ninechessai_ab.cpp
+++ b/NineChess/src/ninechessai_ab.cpp
@@ -13,10 +13,12 @@
#include
#include "ninechessai_ab.h"
-#include "hashmap.h"
+#include "hashMap.h"
+
+using namespace CTSL;
#ifdef HASH_MAP_ENABLE
-static std::unique_ptr> instance;
+HashMap hashmap;
#endif
NineChessAi_ab::NineChessAi_ab() :
@@ -638,9 +640,6 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
#ifdef HASH_MAP_ENABLE
// 检索 hashmap
- uint64_t hashCheckCode = chessTemp.getHashCheckCode();
- node->hashCheckCode = hashCheckCode;
-
uint64_t hash = chessTemp.getHash();
node->hash = hash;
@@ -856,12 +855,12 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
}
#ifdef HASH_MAP_ENABLE
-int NineChessAi_ab::recordHash(HashValue &hashValue)
+int NineChessAi_ab::recordHash(const HashValue &hashValue)
{
#ifdef HASH_MAP_ENABLE
//hashMapMutex.lock();
//HashMap::insert(hashValue.hash, hashValue);
-
+ hashmap.insert(hashValue.hash, hashValue);
//hashMapMutex.unlock();
#endif // HASH_MAP_ENABLE
diff --git a/NineChess/src/ninechessai_ab.h b/NineChess/src/ninechessai_ab.h
index 7f61d22d..46773fff 100644
--- a/NineChess/src/ninechessai_ab.h
+++ b/NineChess/src/ninechessai_ab.h
@@ -15,9 +15,10 @@
#include
#include "ninechess.h"
-#include "hashmap.h"
+#include "hashMap.h"
using namespace std;
+using namespace CTSL;
// 注意:NineChess类不是线程安全的!
// 所以不能在ai类中修改NineChess类的静态成员变量,切记!
@@ -61,7 +62,6 @@ public:
int rand; // 随机数,对于 value 一致的结点随机排序用
#ifdef HASH_MAP_ENABLE
uint64_t hash;
- uint64_t hashCheckCode;
bool isHash; // 是否从 Hash 读取
#endif /* HASH_MAP_ENABLE */
bool pruned; // 是否在此处剪枝
@@ -145,11 +145,6 @@ protected:
// 增加新节点
struct Node *addNode(Node *parent, int value, NineChess::move_t move, enum NineChess::Player player);
-#ifdef HASH_MAP_ENABLE
- // 插入哈希表
- int recordHash(HashValue &hashValue);
-#endif
-
// 评价函数
int evaluate(Node *node);
@@ -172,6 +167,9 @@ protected:
#ifdef HASH_MAP_ENABLE
// 查找哈希表
HashValue findHash(uint64_t hash);
+
+ // 插入哈希表
+ int recordHash(const HashValue &hashValue);
#endif
private:
@@ -219,7 +217,7 @@ private:
char cmdline[32];
#ifdef HASH_MAP_ENABLE
- HashMap hashmap;
+ //HashMap hashmap;
#endif
};