如何正确调用minimax方法(使用alpha beta修剪)

时间:2015-08-22 09:32:51

标签: java algorithm artificial-intelligence tic-tac-toe minimax

这是我的minimax方法,它实现了alpha beta修剪和memoization:

public int[] newminimax499(int a, int b){
    int bestPos=-1;
    int alpha= a;
    int beta= b;
    int currentScore;
    //boardShow();
    String stateString = "";                                                
    for (int i=0; i<state.length; i++) 
        stateString += state[i];                        
    int[] oldAnswer = oldAnswers.get(stateString);                          
    if (oldAnswer != null) 
        return oldAnswer;
    if(isGameOver2()!='N'){
        int[] answer = {score(), bestPos};                                    
        oldAnswers.put (stateString, answer);                                   
        return answer;
    }
    else{
        for(int x:getAvailableMoves()){
            if(turn=='O'){  //O is maximizer
                setO(x);
                //System.out.println(stateID++);
                currentScore = newminimax499(alpha, beta)[0];
                //revert(x);
                if(currentScore>alpha){
                    alpha=currentScore;
                    bestPos=x;
                }
                /*if(alpha>=beta){
                    break;
                }*/
            }
            else {  //X is minimizer
                setX(x);
                //System.out.println(stateID++);
                currentScore = newminimax499(alpha, beta)[0];
                //revert(x);
                if(currentScore<beta){
                    beta=currentScore;
                    bestPos=x;
                }
                /*if(alpha>=beta)
                    break;*/
            }
            revert(x);
            if(alpha>=beta)
                break;
        }
    }
    if(turn=='O'){ 
        int[] answer = {alpha, bestPos};                                    
        oldAnswers.put (stateString, answer);                                   
        return answer;
    }
    else {
        int[] answer = {beta, bestPos};                                    
        oldAnswers.put (stateString, answer);                                   
        return answer;
    }
}

作为测试游戏,在我的主要方法中,我将X放置在某处(X是播放器),然后调用newminimax499以查看我应该放置O(计算机)的位置:

 public static void main(String[] args) {
    State3 s=new State3(3);
    int [] result=new int[2];
    s.setX(4);
    result=s.newminimax499(Integer.MIN_VALUE, Integer.MAX_VALUE);
    System.out.println("Score: "+result[0]+" Position: "+ result[1]);
    System.out.println("Run time: " + (endTime-startTime));
    s.boardShow();
}

}

该方法返回计算机应该播放它的位置(在这种情况下它是6),所以我按照指示放置O,为自己播放X,调用newminimax499并运行代码再看看O想要玩的地方等等。

public static void main(String[] args) {
    State3 s=new State3(3);
    int [] result=new int[2];
    s.setX(4);
    s.setO(6);//Position returned from previous code run
    s.setX(2);
    s.setO(8);//Position returned from previous code run
    s.setX(3);
    result=s.newminimax499(Integer.MIN_VALUE, Integer.MAX_VALUE);
    System.out.println("Score: "+result[0]+" Position: "+ result[1]);
    System.out.println("Run time: " + (endTime-startTime));
    s.boardShow();
}

在此特定运行后,我得到结果

Score: 10 Position: 7

哪个好。但是,在我的GUI中,这并不是如何调用newminimax。在那里,每次放置新的X或O时,电路板都不会复位。如果我将它放在像前面示例中那样的主方法中,它将看起来像这样(请记住它是完全相同的输入序列):

public static void main(String[] args) {
    State3 s=new State3(3);
    int [] result=new int[2];
    s.setX(4); //Player makes his move
    result=s.newminimax499(Integer.MIN_VALUE, Integer.MAX_VALUE);//Where should pc play?
    s.setO(result[1]);//PC makes his move
    s.setX(2);//Player makes his move
    result=s.newminimax499(Integer.MIN_VALUE, Integer.MAX_VALUE);//Where should PC make his move?
    s.setO(result[1]);//PC makes his move
    s.setX(3);//Player makes his move
    result=s.newminimax499(Integer.MIN_VALUE, Integer.MAX_VALUE);
    System.out.println("Score: "+result[0]+" Position: "+ result[1]);
    System.out.println("Run time: " + (endTime-startTime));
    s.boardShow();
}

现在,当以这种方式调用该方法时(它在GUI中调用它的方式),它返回:

Score: 0 Position: 5

这意味着它没有取得胜利的举动,而是阻挡了对手。以这种方式玩了几场游戏后,很明显PC真的输了。那么为什么这两种调用newminimax499的方式会返回不同的结果呢?

这就是它在GUI上的外观:

enter image description here

注意:运行程序所需的所有方法都可以在post中找到。

2 个答案:

答案 0 :(得分:1)

这里遇到的问题与使用换位表和alpha beta的国际象棋相同。我必须与你相矛盾,因为它们是不相容的!

正如我之前多次提出的建议,请在尝试实施之前阅读相应的国际象棋程序维基文章!

为了使memo和AB协同工作,你必须为备忘录表中的每个位置保存一个标志,以区分alpha-cut-nodes,beta-cut-nodes和精确节点。

相信我,我从经验中知道他们一起工作;)

答案 1 :(得分:0)

在玩了很多想法之后我终于找到了答案,所以不妨发布它。这里讨论的方法newminimax499正试图实现memoization和alpha beta修剪。出于某种原因,似乎这两个实用程序是不兼容的(或者至少我对这两个实用程序的实现使它们不兼容)。删除与memoization相关的部分后,该方法成为纯alpha beta修剪minimax算法,工作正常,看起来像这样:

public int[] newminimax499(int alpha, int beta){
    int bestPos=-1;
    int currentScore;
    if(isGameOver2()!='N'){
        int[] answer = {score(), bestPos};                                    
        return answer;
    }
    else{
        for(int x:getAvailableMoves()){
            if(turn=='O'){  //O is maximizer
                setO(x);
                //System.out.println(stateID++);
                currentScore = newminimax499(alpha, beta)[0];
                if(currentScore>alpha){
                    alpha=currentScore;
                    bestPos=x;
                }
            }
            else {  //X is minimizer
                setX(x);
                //System.out.println(stateID++);
                currentScore = newminimax499(alpha, beta)[0];
                if(currentScore<beta){
                    beta=currentScore;
                    bestPos=x;
                }
            }
            revert(x);
            if(alpha>=beta)
                break;
        }
        if(turn=='O'){ 
            int[] answer = {alpha, bestPos};                                    
            return answer;
        }
        else {
            int[] answer = {beta, bestPos};                                    
            return answer;
        }
    }
}

此方法现在不仅可以工作(不过你在main方法中调用),但它也比带有memoization的minimax快得多。此方法仅需7秒即可在4x4游戏中计算第二步。实现memoization的minimax在大约23秒内计算它。