1.哈希函数的关键字值
为每一个棋子在棋盘每一个位置产生一个随机数,整个局面的键值就是棋盘上剩余棋子在棋盘相应位置的异或运算。
随机数的产生:
srand(time(NULL));
……
rand()<<m^rand()<<n;//充分随机
2 哈希函数
除基取余转换成与运算 7mod16 = 7^15
f(key) = key mod 2^n = key & (2^n -1)
3 初始化
HashTable = (HashNode*)malloc(1024*1024*sizeof(HashNode))
HashTable = new HashNode[1024*1024]
4 结合置换表的alpha —beta搜索
最小-最大搜索的理解
你的死敌面前有很多口袋,他和你打赌赌输了,因此他必须从中给你一样东西,而挑选规则却非常奇怪:
每个口袋里有几件物品,你能取其中的一件,你来挑这件物品所在的口袋,而他来挑这个口袋里的物品。你要赶紧挑出 口袋并离开,因为你不愿意一直做在那里翻口袋而让你的死敌盯着你。
假设你一次只能找一只口袋,在找口袋时一次只能从里面摸出一样东西。
很显然,当你挑出口袋时,你的死敌会把口袋里最糟糕的物品给你,因此你的目标是挑出“诸多最糟的物品当中是最好的”那个口袋。
那么怎样才能做得比最小-最大更高效呢?
我们从第一个口袋开始,看每一件物品,并对口袋作出评价。比方说口袋里有一只花生黄油三明治和一辆新汽车的钥匙。你知道三明治更糟,因此如果你挑了这只口袋就会得到三明治。事实上只要我们假设对手也会跟我们一样正确评价物品,那么口袋里的汽车钥匙就是无关紧要的了。
现在你开始翻第二个口袋,这次你采取的方案就和最小-最大方案不同了。你每次看一件物品,并跟你能得到的最好的那件物品(三明治)去比较。只要物品比三明治更好,那么你就按照最小-最大方案来办——去找最糟的,或许最糟的要比三明治更好,那么你就可以挑这个口袋,它比装有三明治的那个口袋好。//三明治相当于Alpha
比方这个口袋里的第一件物品是一张20美元的钞票,它比三明治好。如果包里其他东西都没比这个更糟了,那么如果你选了这个口袋,它就是对手必须给你的物品,这个口袋就成了你的选择。
这个口袋里的下一件物品是六合装的流行唱片。你认为它比三明治好,但比20美元差,那么这个口袋仍旧可以选择。再下一件物品是一条烂鱼,这回比三明治差了。于是你就说“不谢了”,把口袋放回去,不再考虑它了。
无论口袋里还有什么东西,或许还有另一辆汽车的钥匙,也没有用了,因为你会得到那条烂鱼。或许还有比烂鱼更糟的东西(那么你看着办吧)。无论如何烂鱼已经够糟的了,而你知道挑那个有三明治的口袋肯定会更好。
在第二个口袋里找到烂鱼就相当于超过了Beta,如果口袋里没有烂鱼,那么考虑六盒装流行唱片的口袋会比三明治的口袋好,这就相当于超过了Alpha(在上一层)
int AlphaBeta(int depth, int alpha, int beta) {
if (depth == 0) {
return Evaluate();
}
GenerateLegalMoves();
while (MovesLeft()) {
MakeNextMove();
val = -AlphaBeta(depth - 1, -beta, -alpha);
UnmakeMove();
if (val >= beta) {
return beta;
}
if (val > alpha) {
alpha = val;
}
}
return alpha;
}
参考:http://www.xqbase.com/computer/search_alphabeta.htm
https://blog.csdn.net/tangchenyi/article/details/22925957 图解Alpha-Beta剪枝算法
function alphabeta(node, depth, α, β, Player)
if depth = 0 or node is a terminal node
return the heuristic value of node
if Player = MaxPlayer // 极大节点
for each child of node // 极小节点
α := max(α, alphabeta(child, depth-1, α, β, not(Player) ))
if β ≤ α // 该极大节点的值>=α>=β,该极大节点后面的搜索到的值肯定会大于β,因此不会被其上层的极小节点所选用了。对于根节点,β为正无穷
break (* Beta cut-off *)
return α
else // 极小节点
for each child of node // 极大节点
β := min(β, alphabeta(child, depth-1, α, β, not(Player) )) // 极小节点
if β ≤ α // 该极大节点的值<=β<=α,该极小节点后面的搜索到的值肯定会小于α,因此不会被其上层的极大节点所选用了。对于根节点,α为负无穷
break (* Alpha cut-off *)
return β
(* Initial call *)
alphabeta(origin, depth, -infinity, +infinity, MaxPlayer)