我已经尝试对Russel Norvig的人工智能书中给出的井字游戏的极小极大算法进行编码。它拥有一切,除了向用户返回bestMove的方式。我正在努力退还bestMove,但无法决定何时选择bestMove。帮忙,有人吗?

moveT MiniMax(stateT state)
{
    moveT bestMove;

    max_move(state,bestMove);

    return bestMove;

}

int max_move(stateT state,int & bestMove)
{
    int v = -10000;
    if(GameIsOver(state))
    {
        return EvaluateStaticPosition(state);

    }

    vector<moveT> moveList;
    GenerateMoveList(state, moveList);
    int nMoves = moveList.size();

    for(int i = 0 ; i < nMoves ; i++)
    {
        moveT move = moveList[i];
        MakeMove(state, move);

        int curValue = min_move(state,bestMove);

            if(curValue > v)
            {
              v = curValue;
              bestMove = move;
            }
        RetractMove(state, move);

    }

    return v;

}

int min_move(stateT state, int &bestMove)
{
    int v = 10000;
    if(GameIsOver(state))
    {
      return EvaluateStaticPosition(state);

    }
    vector<moveT> moveList;
    GenerateMoveList(state, moveList);

    int nMoves = moveList.size();

    for(int i = 0 ; i < nMoves; i++)
    {
        moveT move = moveList[i];
        MakeMove(state, move);

        int curValue = max_move(state,depth+1,bestMove);

            if(curValue < v)
            {
              curValue = v;
            }
        RetractMove(state, move);

    }
    return v;
}

附注:还有其他伪代码可用于查找最小值最大值。但是,他们只专注于井字游戏,我正在尝试将其扩展到其他游戏。谢谢。

更新:完整代码可以在这里找到:http://ideone.com/XPswCl

最佳答案

在最简单的minimax版本中,第一个玩家希望最大化其得分,第二个玩家希望最小化第一个玩家的得分。
由于第一和第二玩家都只关心第一玩家的得分,因此EvaluateStaticPosition应该返回一个值,该值指示第一玩家的棋盘状态如何。轮到谁是无关紧要的。

int EvaluateStaticPosition(stateT state)
{
        if(CheckForWin(state, FIRST_PLAYER))
        {
                return WINNING_POSITION;
        }
        if(CheckForWin(state, Opponent(FIRST_PLAYER)))
        {
                return LOSING_POSITION;
        }
        return NEUTRAL_POSITION;
}

现在,当您想要最适合第一个玩家的举动时,请致电MaxMove。当您想要最适合第二位玩家的移动时,请致电MinMove。
moveT MiniMax(stateT state)
{
    moveT bestMove;
    int i = 0;
    if (state.whoseTurn == FIRST_PLAYER){
        i = MaxMove(state, bestMove);
    }
    else{
        i = MinMove(state,bestMove);
    }
    cout<<"i is "<<i<<endl;
    return bestMove;
}

最后,您在MinMoveMaxMove内部存在一些问题。当您同时分配curRating时,不应将bestMove传递为MaxMoveMinMove的第二个参数。然后,它将对手的最佳举动放入bestMove,这没有任何意义。而是声明一个opponentsBestMove对象,并将其作为第二个参数传递。 (您实际上将不会使用该对象,甚至以后也不会查看它的值,但这没关系)。进行此更改后,您再也不会在bestMove内为MinMove分配任何内容,因此您应该在if(curRating < v)块内进行分配。
int MaxMove(stateT state, moveT &bestMove)
{
        if(GameIsOver(state))
        {
            return EvaluateStaticPosition(state);
        }
        vector<moveT> moveList;
        GenerateMoveList(state, moveList);
        int nMoves = moveList.size();
        int v = -1000;
        for(int i = 0 ;i<nMoves; i++)
        {
                moveT move = moveList[i];
                MakeMove(state, move);
                moveT opponentsBestMove;
                int curRating = MinMove(state, opponentsBestMove);
                if (curRating > v)
                {
                        v = curRating;
                        bestMove = move;
                }
                RetractMove(state, move);
        }
        return v;

}
int MinMove(stateT state,  moveT &bestMove)
{
        if(GameIsOver(state))
        {
                return EvaluateStaticPosition(state);
        }
        vector<moveT>moveList;
        GenerateMoveList(state, moveList);
        int nMoves = moveList.size();
        int v = 1000;
        for(int i = 0 ; i<nMoves; i++)
        {
                moveT move = moveList[i];
                MakeMove(state , move);
                moveT opponentsBestMove;
                int curRating = MaxMove(state,opponentsBestMove);
                if(curRating < v)
                {
                        v = curRating;
                        bestMove = move;
                }
                RetractMove(state, move);
        }
        return v;
}

此时,您应该拥有无与伦比的AI!
The final position looks like this:

 O | O | X
---+---+---
 X | X | O
---+---+---
 O | X | X

Cat's game.

替代方法利用井字游戏是零和游戏这一事实。换句话说,在游戏结束时,玩家得分的总和将为零。对于两人游戏,这意味着一个人的得分始终是另一人的负值。这对我们来说很方便,因为最小化其他玩家的分数就等于最大化自己的分数。因此,我们可以让两个玩家尝试最大化自己的得分,而不是一个玩家最大化自己的得分,而一个玩家最小化另一位玩家的得分。

EvaluateStaticPosition更改回其原始形式,以便它根据当前玩家的棋盘状态如何给出得分。
int EvaluateStaticPosition(stateT state)
{
        if(CheckForWin(state, state.whoseTurn))
        {
                return WINNING_POSITION;
        }
        if(CheckForWin(state, Opponent(state.whoseTurn)))
        {
                return LOSING_POSITION;
        }
        return NEUTRAL_POSITION;
}

删除MinMove,因为我们只关心最大化。
重写MaxMove,以便它选择使对手得分最差的举动。最佳举动的分数是另一位玩家的最差分数的负数。
int MaxMove(stateT state, moveT &bestMove)
{
        if(GameIsOver(state))
        {
                return EvaluateStaticPosition(state);
        }
        vector<moveT> moveList;
        GenerateMoveList(state, moveList);
        int nMoves = moveList.size();
        int v = -1000;
        for(int i = 0 ;i<nMoves; i++)
        {
                moveT move = moveList[i];
                MakeMove(state, move);
                moveT opponentsBestMove;
                int curRating = -MaxMove(state, opponentsBestMove);
                if (curRating > v)
                {
                        v = curRating;
                        bestMove = move;
                }
                RetractMove(state, move);
        }
        return v;

}

由于MaxMove用于两个播放器,因此我们不再需要在MiniMax函数中区分播放器。
moveT MiniMax(stateT state)
{
    moveT bestMove;
    int i = 0;
    i = MaxMove(state, bestMove);
    cout<<"i is "<<i<<endl;
    return bestMove;
}

关于c++ - 返回最佳运动中的最小动静算法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13523050/

10-12 22:12