问题描述
最近我一直在开发国际象棋引擎,并且我准备实现某种AI以实际玩游戏(搜索位置)。我已经编写了alpha-beta修剪算法,但是当我测试它时,它并没有返回最佳移动。
float Search::alphabeta(S_BOARD* pos,S_SEARCHINFO *info,int depth,float alpha,float beta){
if (depth == 0) {
info->nodes++;
return eval::staticEval(pos);
}
info->nodes++;
S_MOVELIST list;
MoveGeneration::validMoves(pos,list);
float value = 0;
S_MOVE bestMove;
bestMove.move = NOMOVE;
bestMove.score = 0;
float prevBound = (pos->whitesMove == WHITE) ? alpha : beta;
int pvMove = TT::probeMove(pos);
if (pvMove != NOMOVE) {
for (int i = 0; i < list.count; i++) {
if (list.moves[i].move == pvMove) {
list.moves[i].score = 20000000;
break;
}
}
}
if (pos->whitesMove == WHITE) {
value = -INFINITE;
for (int moveNum = 0; moveNum < list.count; moveNum++) {
pickNextMove(moveNum,&list);
MoveGeneration::makeMove(*pos,list.moves[moveNum].move);
value = max(value,alphabeta(pos,info,depth - 1,alpha,beta));
MoveGeneration::undoMove(*pos);
if (value > alpha) {
if (value >= beta) {
if (moveNum == 0) {
info->fhf++;
}
info->fh++;
break;
}
alpha = value;
bestMove = list.moves[moveNum];
}
}
if (pos->is_checkmate) {
return -MATE + pos->ply;
}
else if (pos->is_stalemate) {
return 0;
}
if (alpha != prevBound) {
TT::storePvMove(pos,bestMove);
}
return value;
}
else {
value = INFINITE;
for (int moveNum = 0; moveNum < list.count; moveNum++) {
pickNextMove(moveNum,list.moves[moveNum].move);
value = min(value,beta));
MoveGeneration::undoMove(*pos);
if (value < beta){
if (beta <= alpha) {
if (moveNum == 0) {
info->fhf++;
}
info->fh++;
break;
}
beta = value;
bestMove = list.moves[moveNum];
}
}
if (pos->is_checkmate) {
return MATE - pos->ply;
}
else if (pos->is_stalemate) {
return 0;
}
if (beta != prevBound) {
TT::storePvMove(pos,bestMove);
}
return value;
}
(MoveGeneration是一个命名空间,因此在对象实例外部调用函数不是问题。)
float Search::searchPosition(S_BOARD* pos,S_SEARCHINFO *info){
clearForSearch(pos,info);
float score = -INFINITE;
int bestMove = NOMOVE;
int pvMoves = 0;
// Iterative deepening.
for (int currDepth = 1; currDepth <= info->depth; currDepth++){
auto start = std::chrono::high_resolution_clock::Now();
score = alphabeta(pos,currDepth,-INFINITE,INFINITE);
auto end = std::chrono::high_resolution_clock::Now();
pvMoves = TT::getPvLine(pos,currDepth);
bestMove = pos->pvArray[0];
std::chrono::duration<double> elapsed = end - start;
std::cout << "[+] Depth: " << currDepth << " score: " << score << " move: " << printMove(bestMove)
<< " nodes: " << info->nodes << " kN/s: " << (info->nodes/elapsed.count())/1000 << std::endl;
std::cout << "pv";
for (int i = 0; i < pvMoves; i++){
std::cout << " " << printMove(pos->pvArray[i]);
}
std::cout << std::endl;
std::cout << "Ordering: " << info->fhf/info->fh << std::endl;
}
return score;}
有人能指出我犯下的潜在错误吗?
解决方法
它不返回移动,因为您只返回alpha / beta函数底部的值。在原始通话中,输入以下内容:
move,score = alphabeta(pos,info,currDepth,-INFINITE,INFINITE);
在您的深度== 0时,您将返回并死锁:
return None,eval
在两个播放器功能(最小化和最大化播放器)结束时,您返回:
return move,value
最后,当您从两个播放器函数进行递归调用时,只需要获取该值即可。我不确定您的编程语言,但是例如在Python的末尾加上[1]只是为了获取值而不是移动,就像这样:
value = max(value,alphabeta(pos,depth - 1,alpha,beta))[1]