1

我正在尝试使用 minimax 算法在我的连接四游戏中创建 AI,但我无法让它工作。我相信我非常接近,但仍然无法正确。任何人都可以帮助我解决任何错误吗?我意识到我的代码不是很好,因为我对 Javascript 的效率还不是很高,这就是我想尝试这个的原因。如果我完全偏离轨道,有人可以告诉我更好的方法吗?提前致谢。

编辑:我已经用我更新的代码替换了下面的代码。它现在在给我人工智能动作方面“有效”,但问题是它们不是“智能”动作。我查看了许多极小极大定义,我觉得我已经正确地实现了它。即使我去到大约 7 的深度,一个 5 岁的孩子也能打败它。任何帮助,将不胜感激。

    function getBestMove(currBoard,depth,who) {
        var opp;
        //Get opponent for next piece
        if(who == 'a') {
            opp = 'p';
        } else {
            opp = 'a';
        }

        var tBoard = new Array(rows);
        for(var i=0; i<tBoard.length; i++) {
            tBoard[i] = new Array(cols);
        }

        var moves = new Array(aiOpenCols.length);
        //Drop each piece and use minimax function until depth == 0
        for(var i=0; i<aiOpenCols.length; i++) {
            for(var j=0; j<rows; j++) {
                for(var k=0; k<cols; k++) {
                    tBoard[j][k] = currBoard[j][k];
                }
            }
            tBoard = dropPiece(aiOpenCols[i],who,tBoard);
            moves[i] = minimax(tBoard,(+depth - 1),opp,aiOpenCols[i]);
        }

        var bestAlpha = -100000;    //Large negative
        //Use random column if no moves are "good"
        var bestMove = Math.floor(Math.random() * aiOpenCols.length);
        bestMove = +aiOpenCols[bestMove];
        //Get largest value from moves for best move
        for(var i=0; i<aiOpenCols.length; i++) {
            if(+moves[i] > bestAlpha) {
                bestAlpha = moves[i];
                bestMove = aiOpenCols[i];
            }
        }

        bestMove++; //Offset by 1 due to actual drop function
        return bestMove;
    }
    function minimax(currBoard,depth,who,col) {
        //Drop current piece, called from getBestMove function
        currBoard = dropPiece(col,who,currBoard);

        //When depth == 0 return heuristic/eval of board
        if(+depth == 0) {
            var ev = evalMove(currBoard);
            return ev;
        }
        var alpha = -100000;    //Large negative
        var opp;
        //Get opponent for next piece
        if(who == 'a') {
            opp = 'p';
        } else {
            opp = 'a';
        }

        //Loop through all available moves
        for(var i=0; i<aiOpenCols.length; i++) {
            var tBoard = new Array(rows);
            for(var i=0; i<tBoard.length; i++) {
                tBoard[i] = new Array(cols);
            }
            for(var j=0; j<rows; j++) {
                for(var k=0; k<cols; k++) {
                    tBoard[j][k] = currBoard[j][k];
                }
            }
            //Continue recursive minimax until depth == 0
            var next = minimax(tBoard,(+depth - 1),opp,aiOpenCols[i]);
            //Alpha = max(alpha, -minimax()) for negamax
            alpha = Math.max(alpha, (0 - +next));
        }
        return alpha;
    }
    function evalMove(currBoard) {
        //heuristic function
        //AI = # of 4 streaks + # of 3 streaks + # of 2 streaks - # of 3 streaks opp - # of 2 streaks opp           
        var fours = checkFours(currBoard,'b') * 1000;
        var threes = checkThrees(currBoard,'b') * 100;
        var twos = checkTwos(currBoard,'b') * 10;
        var oppThrees = checkThrees(currBoard,'r') * 100;
        var oppTwos = checkTwos(currBoard,'r') * 10;

        var scores = fours + threes + twos - oppThrees - oppTwos;

        //If opponent wins, return large negative
        var oppFours = checkFours(currBoard,'r');
        if(+oppFours > 0) {
            return -100000;
        } else {
            return scores;
        }
    }
    function dropPiece(col,who,currBoard) {
        for(var i=0; i<currBoard.length; i++) {
            if(currBoard[i][col] != 'w') {
                //Make sure column isn't full
                if(i != 0) {
                    if(who == 'p') {
                        currBoard[i-1][col] = 'r';
                    } else {
                        currBoard[i-1][col] = 'b';
                    }
                    break;
                }
            }
            //If column is empty, place in first row
            if(i == (currBoard.length - 1)) {
                if(who == 'p') {
                    currBoard[i][col] = 'r';
                } else {
                    currBoard[i][col] = 'b';
                }
            }
        }
        return currBoard;
    }
4

1 回答 1

2

您的评估功能正在为没有价值的位置特征分配价值。连续有两个连续的单元格没有价值。如果第四个单元格可以被对手占据而不允许在其他地方获胜,那么连续三个单元格也没有任何价值。

简化。对于四连线,您只需要关心位置是赢还是输,或者在下一步行动中是否可以赢或输。如果是胜利,则返回一个很大的正值。如果是损失,则返回较大的负值。如果该位置可以在下一步中获胜或丢失,则将该分支的搜索深度扩大一层,并再次调用 minimax(),返回结果。后者将避免所有固定深度极小极大搜索都容易受到的地平线效应。否则返回零。

于 2013-07-26T22:39:27.347 回答