Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么我的minimax算法是dosen';不要阻止我的行动?_Javascript_Algorithm_Minimax - Fatal编程技术网

Javascript 为什么我的minimax算法是dosen';不要阻止我的行动?

Javascript 为什么我的minimax算法是dosen';不要阻止我的行动?,javascript,algorithm,minimax,Javascript,Algorithm,Minimax,这是我的Tic-Tac-Toe算法的Javascript代码: function minimax(newGrid, depth, Player){ //debugger const gameState = checkWin(newGrid,true); if (gameState == false){ values = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) {

这是我的Tic-Tac-Toe算法的Javascript代码:

function minimax(newGrid, depth, Player){

//debugger

const gameState = checkWin(newGrid,true);

if (gameState == false){
    values = [];

    for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
            const boardCopy = _.cloneDeep(newGrid);
            if (boardCopy[i][j] !== '') continue;
            boardCopy[i][j] = Player;
            console.log(boardCopy);
            const value = minimax(boardCopy, depth + 1, (Player === PLYR_TOKEN) ? COMP_TOKEN : PLYR_TOKEN);
            values.push({
                cost: value,
                cell: {
                    i: i,
                    j: j
                } 
            });
        }
    }

    //debugger

    if (Player === COMP_TOKEN){
        const max = _.maxBy(values, (v) => {
            return v.cost;
        });
        if( depth === 0 ){
            return max.cell;
        } else {
            return max.cost;
        }
    }else{
            const min = _.minBy(values, (v) => {
            return v.cost;
        });
        if( depth === 0 ){
            return min.cell;
        } else {
            return min.cost;
        }

    }
} else if (gameState === null){
    return 0;
} else if (gameState === PLYR_TOKEN){
    return depth - 10;
} else if (gameState === COMP_TOKEN){
    return 10 - depth;
   }
}
正常情况下,一个完美的极大极小算法应该选择这个选项来阻止我获胜(小写o是新的动作):

问题是,我的代码中包含以下内容(小写字母o表示新的移动):

为什么??我不知道,但我认为它会抓住任何获胜的机会,忽略我的动作,忽略我离胜利还有一步的事实。 老实说,我真的不明白这个算法是如何工作的

其他信息:主板是一个二维数组,minimax函数的结果是一个具有两个属性(i,j)的对象,表示主板上的坐标

const board = [
['','',''],
['','',''],
['','','']
];

因此,当有疑问时,请发表评论!我一步一步地做,当我陷入困境时,我并没有停下来,而是在每次我理解更多的东西时,我都会拖延和来回

//newGrid : the board
//depth : keep track of the "guessing level"
//Player : keep track of who's turn it would be
function minimax(newGrid, depth, Player){

//checking if the game ended
const gameState = checkWin(newGrid,true);

//if not
if (gameState == false){
    values = [];
    //for each cell in the grid
    for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
            //we make a deep copy of the board
            const boardCopy = _.cloneDeep(newGrid);
            //if the cell isn't empty, we jump to the next one
            if (boardCopy[i][j] !== '') continue;
            //here we assign the Player to the cell (simulating a move from this player to this cell)
            boardCopy[i][j] = Player;
            //debugging
            console.log(boardCopy);
            //here go some recursivity, so we're putting our deepcopy with the simulated move, adding a depth level, and switching player
            const value = minimax(boardCopy, depth + 1, (Player === PLYR_TOKEN) ? COMP_TOKEN : PLYR_TOKEN);
            //since it was a recursive thing, please do imagine we get here at max depth BEFORE lesser depths, and then we'll climb back when each depth return its value to the previous one
            //so here the first "value" going in "values" will be the first cell where we did not go through "if (gameState == false){" : first cell where the game ended (with its associated cost, more on that later)
            values.push({
                cost: value,
                cell: {
                    i: i,
                    j: j
                } 
            });
        }
    }

    //when the loop ended
    //if we're simulating a computer turn
    if (Player === COMP_TOKEN){
        //getting the "value" with max cost out of "values"
        const max = _.maxBy(values, (v) => {
            return v.cost;
        });
        //if we endend our recursivity (we climbed all the way back to depth 0) == we are on the actual grid with no simulation
        if( depth === 0 ){
            return max.cell; //return the cell (computer will play this cell)
        } else {
            return max.cost; //else return the cost (to put in the "values" list)
        }
    }else{ //if we're simulating a player turn, same thing but with the min
        const min = _.minBy(values, (v) => {
            return v.cost;
        });
        if( depth === 0 ){ //may not be useful if you always call minimax at depth 0 on computer turn
            return min.cell;
        } else {
            return min.cost;
        }

    }
} else if (gameState === null){ //so, here we're simulating our endgame, a draw have a value of 0
    return 0;
} else if (gameState === PLYR_TOKEN){ //a player win have a value of "depth-10" (the quicker he win, the lesser the result)
    return depth - 10;
} else if (gameState === COMP_TOKEN){ //a computer win have a value of "10-depth" (the quicker he win, the greater the result)
    return 10 - depth;
   }
}
这还远远不够完美(比如说,你可以用两步赢下他),也没有经过测试,但我希望现在对你来说更清楚。
当你完成了你的代码,并且它按照你想要的方式工作时,请毫不犹豫地发布它,以获得优化建议。

添加更多关于问题的详细信息,这是一款什么样的游戏。对不起,我没有意识到,谢谢。这是关于井字游戏的,我刚在帖子里加上。这个问题真的不清楚。“它不会阻止我的移动”是什么意思?为什么算法“抓住任何获胜的机会”会很奇怪?具体来说,有什么事情没有按您期望的方式工作?这是我第一次发布问题,谢谢您的建议,我试图更清楚地说明我的问题/解释。感谢您的回答和注释代码中的所有行,我以前没有意识到,但注释确实有助于理解发生了什么。
X - O
- X o
- - -
const board = [
['','',''],
['','',''],
['','','']
];
//newGrid : the board
//depth : keep track of the "guessing level"
//Player : keep track of who's turn it would be
function minimax(newGrid, depth, Player){

//checking if the game ended
const gameState = checkWin(newGrid,true);

//if not
if (gameState == false){
    values = [];
    //for each cell in the grid
    for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
            //we make a deep copy of the board
            const boardCopy = _.cloneDeep(newGrid);
            //if the cell isn't empty, we jump to the next one
            if (boardCopy[i][j] !== '') continue;
            //here we assign the Player to the cell (simulating a move from this player to this cell)
            boardCopy[i][j] = Player;
            //debugging
            console.log(boardCopy);
            //here go some recursivity, so we're putting our deepcopy with the simulated move, adding a depth level, and switching player
            const value = minimax(boardCopy, depth + 1, (Player === PLYR_TOKEN) ? COMP_TOKEN : PLYR_TOKEN);
            //since it was a recursive thing, please do imagine we get here at max depth BEFORE lesser depths, and then we'll climb back when each depth return its value to the previous one
            //so here the first "value" going in "values" will be the first cell where we did not go through "if (gameState == false){" : first cell where the game ended (with its associated cost, more on that later)
            values.push({
                cost: value,
                cell: {
                    i: i,
                    j: j
                } 
            });
        }
    }

    //when the loop ended
    //if we're simulating a computer turn
    if (Player === COMP_TOKEN){
        //getting the "value" with max cost out of "values"
        const max = _.maxBy(values, (v) => {
            return v.cost;
        });
        //if we endend our recursivity (we climbed all the way back to depth 0) == we are on the actual grid with no simulation
        if( depth === 0 ){
            return max.cell; //return the cell (computer will play this cell)
        } else {
            return max.cost; //else return the cost (to put in the "values" list)
        }
    }else{ //if we're simulating a player turn, same thing but with the min
        const min = _.minBy(values, (v) => {
            return v.cost;
        });
        if( depth === 0 ){ //may not be useful if you always call minimax at depth 0 on computer turn
            return min.cell;
        } else {
            return min.cost;
        }

    }
} else if (gameState === null){ //so, here we're simulating our endgame, a draw have a value of 0
    return 0;
} else if (gameState === PLYR_TOKEN){ //a player win have a value of "depth-10" (the quicker he win, the lesser the result)
    return depth - 10;
} else if (gameState === COMP_TOKEN){ //a computer win have a value of "10-depth" (the quicker he win, the greater the result)
    return 10 - depth;
   }
}
    if (Player === COMP_TOKEN){
        //[...]
        //if we endend our recursivity (we climbed all the way back to depth 0) == we are on the actual grid with no simulation
        if( depth === 0 ){
            const min = _.minBy(values, (v) => {
                return v.cost;
            });
            if(min.cost>=-9)return min.cell; //if player win in the next turn, prevent it instead
            else return max.cell; //else return the best cell for computer
        }
        //[...]