Artificial intelligence 为国际象棋引擎实现alpha-beta修剪时出现问题

Artificial intelligence 为国际象棋引擎实现alpha-beta修剪时出现问题,artificial-intelligence,chess,minimax,alpha-beta-pruning,Artificial Intelligence,Chess,Minimax,Alpha Beta Pruning,我最近一直在开发一个国际象棋引擎,我准备实现某种AI来实际玩这个游戏(搜索位置)。我已经写了一个alpha-beta剪枝算法,但是当我测试它时,它不会返回最好的动作 alpha beta搜索的代码为: float Search::alphabeta(S_BOARD* pos, S_SEARCHINFO *info, int depth, float alpha, float beta){ if (depth == 0) { info->nodes++; return eva

我最近一直在开发一个国际象棋引擎,我准备实现某种AI来实际玩这个游戏(搜索位置)。我已经写了一个alpha-beta剪枝算法,但是当我测试它时,它不会返回最好的动作

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);
        MoveGeneration::makeMove(*pos, list.moves[moveNum].move);

        value = min(value, alphabeta(pos, info, depth - 1, alpha, 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;
}
float Search::alphabeta(S_BOARD*pos,S_SEARCHINFO*info,int depth,float alpha,float beta){
如果(深度==0){
信息->节点++;
返回评估:静态评估(pos);
}
信息->节点++;
S_移动列表;
移动生成::有效移动(pos,列表);
浮点数=0;
S_MOVE bestMove;
bestMove.move=NOMOVE;
bestMove.score=0;
float prevBound=(pos->whitesMove==白色)?alpha:beta;
int-pvMove=TT::probeMove(pos);
如果(pvMove!=NOMOVE){
对于(int i=0;i白色移动==白色){
值=-无穷大;
for(int moveNum=0;moveNumalpha){
如果(值>=beta){
如果(moveNum==0){
信息->fhf++;
}
信息->跳频++;
打破
}
α=值;
bestMove=list.moves[moveNum];
}
}
如果(位置->被将死){
返回-配合+位置->铺层;
}
否则(pos->is\U僵局){
返回0;
}
如果(alpha!=prevBound){
TT::storePvMove(pos、bestMove);
}
返回值;
}
否则{
价值=无限;
for(int moveNum=0;moveNum跳频++;
打破
}
β=值;
bestMove=list.moves[moveNum];
}
}
如果(位置->被将死){
返回配对-位置->铺层;
}
否则(pos->is\U僵局){
返回0;
}
如果(beta!=prevBound){
TT::storePvMove(pos、bestMove);
}
返回值;
}
(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, info, 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;}
float Search::searchPosition(S_BOARD*pos,S_SEARCHINFO*info){
clearForSearch(pos、信息);
浮动分数=-无限;
int bestMove=NOMOVE;
int=0;
//迭代深化。
对于(int currDepth=1;currDepth深度;currDepth++){
自动启动=标准::时钟::高分辨率时钟::现在();
分数=字母β(位置、信息、电流深度,-无限、无限);
自动结束=标准::时钟::高分辨率时钟::现在();
pvMoves=TT::getPvLine(位置、电流深度);
bestMove=pos->pvArray[0];
std::chrono::持续时间=结束-开始;

std::cout它不返回移动,因为您只返回alpha/beta函数底部的值。在原始调用中,将以下内容放入:

move, score = alphabeta(pos, info, currDepth, -INFINITE, INFINITE);
在你的深度=0时,你将返回将死和僵局:

return None, eval
return move, value
在两个玩家函数(最小化和最大化玩家)结束时,返回:

return None, eval
return move, value
最后,当您从两个播放器函数进行递归调用时,您只需要获取值。我不确定您的编程语言,但在例如Python中,您在末尾放了一个[1]来获取值而不是移动,类似这样:

value = max(value, alphabeta(pos, info, depth - 1, alpha, beta))[1]