Java中的miniMax算法

Java中的miniMax算法,java,recursion,artificial-intelligence,tic-tac-toe,minimax,Java,Recursion,Artificial Intelligence,Tic Tac Toe,Minimax,我目前对我正在编程的AI不满意。人工智能应该在一个3x3的棋盘(TicTacToe)中获得每一步的最佳分数 可能的分数是-1(输),0(平)和1(赢) 首先调用方法makeTurn(),然后调用包含miniMax算法的方法 public void makeTurn(Button[][] currentBoard) { // Calculating best move using miniMax alg

我目前对我正在编程的AI不满意。人工智能应该在一个3x3的棋盘(TicTacToe)中获得每一步的最佳分数

可能的分数是-1(输),0(平)和1(赢)

首先调用方法
makeTurn()
,然后调用包含miniMax算法的方法

public void makeTurn(Button[][] currentBoard) {                                                 // Calculating best move using miniMax algorithm
        AIcheck = new Check(currentBoard);
        int bestScore = Integer.MIN_VALUE;
        int[] bestMove = new int[2];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (currentBoard[i][j].getText().equals("")) {
                    currentBoard[i][j].setText("O");
                    int score = calcScore(currentBoard, 0, false);
                    System.out.println(score);
                    currentBoard[i][j].setText("");
                    if (score > bestScore) {
                        bestScore = score;
                        bestMove = new int[]{i, j};

                    }
                }
            }
        }
        Board.getInstance().getField(bestMove[0], bestMove[1]).performClick();
    }

public void makeTurn(按钮[][]currentBoard){//使用miniMax算法计算最佳移动
A检查=新检查(电流板);
int bestScore=整数最小值;
int[]bestMove=新int[2];
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
if(currentBoard[i][j].getText().equals(“”){
电流板[i][j].setText(“O”);
int分数=CalcCore(电流板,0,假);
系统输出打印项次(分数);
电流板[i][j].setText(“”);
如果(分数>最佳分数){
最佳分数=分数;
bestMove=newint[]{i,j};
}
}
}
}
Board.getInstance().getField(bestMove[0],bestMove[1]).performClick();
}
private int-calcScore(按钮[][]currentBoard,int-depth,boolean-isMax){//MiniMax算法,通过递归执行计算每个分支的分数
智力得分;
if(AIcheck.checkWin()){
返回(Util.getInstance().getTurnCounter()%2)==0?1:-1;
}else if(AIcheck.checkTie()){
返回0;
}
int bestScore=isMax?Integer.MIN_值:Integer.MAX_值;
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
if(currentBoard[i][j].getText().equals(“”){
if(isMax){
电流板[i][j].setText(“O”);
}否则{
电流板[i][j].setText(“X”);
}
分数=CalcCore(电流板,深度+1,!isMax);
电流板[i][j].setText(“”);
bestScore=isMax?Math.max(bestScore,score):Math.min(bestScore,score);
}
}
}
返回最佳分数;
}
我使用
isMax
来确定是否轮到了最大化者,还使用
turnCounter%2
来确定轮到了哪个玩家,因为他们轮流

然而人工智能并没有阻止我获胜,它更像是从一个领域转到下一个领域,而不是选择最佳领域。 我怎样才能正确地实现miniMax算法? 非常感谢

例如:

【】【】【】【】【】

【】【】【】【】【】

[十] |[]|[]


[O] |[]|[]

【】【】【】【】【】

[十] |[]|[]


[O] |[]|[]

【】【】【】【】【】

[十] |[]|[X]


[O] |[O]|[]

【】【】【】【】【】

[十] |[]|[X]


[O] |[O]|[X]

【】【】【】【】【】

[十] |[]|[X]


[O] |[O]|[X]

[O] |[]|[]

[十] |[]|[X]


[O] |[O]|[X]

[O] |[X]|[]我赢了,这也表明人工智能似乎刚刚占据了下一个位置(从左到右)


[十] |[]|[X]

我认为问题在于
calcScore()中的这一行。

如果电路板为空,则只计算分数,但在调用函数之前,始终将其设置为“0”,因此该if的代码块将永远不会执行

makeTurn()
与此类似,但我想你是在轮次之间清理黑板吧?如果没有,你也需要更新这个

编辑: 在主要功能中:

                    currentBoard[i][j].setText("O");
                    int score = calcScore(currentBoard, 0, false);
在calcScore:

// this will always evaluate to false
if (currentBoard[i][j].getText().equals("")) {

你的最佳成绩作业有问题。对于每个空框,请执行以下操作:

int bestScore = isMax ? Integer.MIN_VALUE : Integer.MAX_VALUE;

如果您这样计算,您将始终得到相同的分数,这可能是它只选择下一个空框的原因。在minimax算法中,您需要一种为每个移动分配不同分数值的方法,以便通过比较找到最佳移动。在国际象棋或类似的游戏中,这些分数通常是通过一些试探法得出的。因为你的游戏简单得多,所以这应该更容易。一个简单的解决方案可能是为每个板状态分配不同的分数,您可以简单地选择导致该状态的移动。你可以很容易地做到这一点,因为在你的游戏中,这些状态的数量非常有限。

我认为问题在于如何确定谁在
calcScore
中获胜。您使用了
Util.getInstance().getTurnCounter()
,但在递归调用中似乎没有更新计数器。您只需使用
depth%2
isMax
即可:

if (AIcheck.checkWin()) {
    return isMax ? -1 : 1;
}

这很有帮助,谢谢,但遗憾的是,它没有从整体上解决问题(@M0e“不能解决整个问题”是什么意思?您仍然能够通过此更改获胜吗?是的,但我发现了错误。算法本身是正确的(正如我所认为的那样,因此我感到困惑),但是checkWin()是错误的,也是您提到的。由于没有您的更正,我无法完成此操作,因此我会将您的答案标记为正确。谢谢!但我不是在嵌套的for循环中为bestScore分配另一个值吗?据我所知,算法需要一个回合(此处:将其设置为“O”)然后通过递归调用每个回合的miniMax算法来计算这一步有多好。这样,它会得到最佳回合,如果是,它会撤消它所做的每个回合,并获得以前计算的最佳回合。
int bestScore = isMax ? Integer.MIN_VALUE : Integer.MAX_VALUE;
if (AIcheck.checkWin()) {
    return isMax ? -1 : 1;
}