Minimax算法JS实现

时间:2016-09-19 20:03:57

标签: javascript tic-tac-toe minimax

在尝试编写 Tic tac toe 游戏时,我有一些javascript代码。
因此AI(人工智能)扮演“ X ”,而“人类”玩家分别扮演“ O ”; 为了测试我把板子作为
['e','e','o',
 'x','o','e',
 'e','e','e']

AI转向移动。显然,AI(人工智能)的最佳举措是 ['e','e','o',
 'x','o','e',
 'x','e','e']。

 但它让我回复 ['x','e','o',
 'x','o','e',
 'e','e','e']
变种。
如果有好的提示,我将不胜感激,这将以正确的方式重新引导我 是的,我读了一周关于Minimax的一堆文章。就个人而言,我用这个教程作为原型http://blog.circuitsofimagination.com/2014/06/29/MiniMax-and-Tic-Tac-Toe.html 所以请看看我的代码:

var board = ['e', 'e', 'o', 'x', 'o', 'e', 'e', 'e', 'e'];
var signPlayer = 'o';
var signAI = (signPlayer === 'x') ? 'o' : 'x';

//Circuits Of Imagination

game = {
    over: function(board) {
        for (var i = 0; i < board.length; i += 3) {
            if (board[i] === board[i + 1] && board[i + 1] === board[i + 2]) {
                return board[i] !== 'e' ? board[i] : false;
            }
        }
        for (var j = 0; j < board.length; j++) {
            if (board[j] === board[j + 3] && board[j + 3] === board[j + 6]) {
                return board[j] !== 'e' ? board[j] : false;
            }
        }
        if ((board[4] === board[0] && board[4] === board[8]) || 
        (board[4] === board[2] && board[4] === board[6])) {
            return board[4] !== 'e' ? board[4] : false;
        }
        var element;
        if (board.every(function(element) {
            return element !== 'e';
        })) {
            return true;
        }
    },
    winner: function(board) {
        return game.over(board);
    },
    possible_moves: function(board, sign) {
        var testBoard = [], 
        nextBoard;
        for (var i = 0; i < board.length; i++) {
            nextBoard = board.slice();
            if (nextBoard[i] === 'e') {
                nextBoard[i] = sign;
                testBoard.push(nextBoard);
            }
        }
        return testBoard;
    }
}

function score(board) {
    if (game.winner(board) === signPlayer) {
        return -10;
    } else if (game.winner(board) === signAI) {
        return +10;
    } else {
        return 0;
        //Game is a draw
    }
}

function max(board) {

    if (game.over(board)) {
        return score(board);
    }
    var newGame = [];
    var best_score = -10;
    var movesArray = game.possible_moves(board, signAI);

    for (var i = 0; i < movesArray.length; i++) {
        newGame = movesArray[i].slice();
        score = min(newGame);
        if (score > best_score) {
            best_score = score;
        }
        console.log('maxnewGame', newGame);
        return best_score;
    }
}

function min(board) {

    if (game.over(board)) {
        return score(board);
    }
    var newGame = [];
    var worst_score = 10;
    var movesArray = game.possible_moves(board, signPlayer);

    for (var i = 0; i < movesArray.length; i++) {
        newGame = movesArray[i].slice();
        score = max(newGame);
        if (score < worst_score) {
            worst_score = score;
        }
        console.log('minnewGame', newGame);
        return worst_score;
    }
}
max(board);

1 个答案:

答案 0 :(得分:2)

您的代码中存在一些错误:

  1. 你在for循环中有return best/worst_score,它过早地终止了搜索。把它带出循环。
  2. score在循环中被重新定义为一个数字,当它应该是一个函数时。将其重命名为moveScore
  3. max/minnewGame设置不正确。
  4. best/worse_score被启动为+/- 10,这意味着有时没有找到最大值。
  5. 固定代码如下。 然而请注意,X仍然没有选择&#34;显而易见的&#34;移动。这实际上是针对你的minimax算法工作的。这是由于算法假设对手正在最佳地进行比赛。在你给定的棋盘状态下,最佳对手将无法以X赢得胜利。因此,算法&#34;放弃&#34;并选择第一个可能的举动。

    这是minmax算法的最大特性之一:算法只能做出与对手一样好的决策。如果对手被最佳地模拟,算法将不会考虑错误的可能性并放弃。为了让算法选择你认为的算法,显而易见的是,你必须让算法也考虑到转向直到丢失,所以它会在游戏中尽可能地输掉可能(这可以通过给出失败的移动-10+turns来完成,其中转弯是失去的转弯次数)。另一种方法是根据可能的游戏超过状态来制作得分,并支持在X获胜的更多可能状态下进行移动。

    &#13;
    &#13;
    var board = ['e', 'e', 'o', 'x', 'o', 'e', 'e', 'e', 'e'];
    var signPlayer = 'o';
    var signAI = (signPlayer === 'x') ? 'o' : 'x';
    
    //Circuits Of Imagination
    
    game = {
      over: function(board) {
        for (var i = 0; i < board.length; i += 3) {
          if (board[i] === board[i + 1] && board[i + 1] === board[i + 2]) {
            return board[i] !== 'e' ? board[i] : false;
          }
        }
        for (var j = 0; j < board.length; j++) {
          if (board[j] === board[j + 3] && board[j + 3] === board[j + 6]) {
            return board[j] !== 'e' ? board[j] : false;
          }
        }
        if ((board[4] === board[0] && board[4] === board[8]) ||
          (board[4] === board[2] && board[4] === board[6])) {
          return board[4] !== 'e' ? board[4] : false;
        }
        var element;
        if (board.every(function(element) {
          return element !== 'e';
        })) {
          return true;
        }
      },
      winner: function(board) {
        return game.over(board);
      },
      possible_moves: function(board, sign) {
        var testBoard = [],
          nextBoard;
        for (var i = 0; i < board.length; i++) {
          nextBoard = board.slice();
          if (nextBoard[i] === 'e') {
            nextBoard[i] = sign;
            testBoard.push(nextBoard);
          }
        }
        return testBoard;
      }
    }
    
    function score(board) {
      if (game.winner(board) === signPlayer) {
        return -10;
      } else if (game.winner(board) === signAI) {
        return +10;
      } else {
        return 0;
        //Game is a draw
      }
    }
    
    function max(board) {
    
      if (game.over(board)) {
        return score(board);
      }
      var newGame = [];
      var moveScore, maxnewGame;
      var best_score = -Infinity;
      var movesArray = game.possible_moves(board, signAI);
    
      for (var i = 0; i < movesArray.length; i++) {
        newGame = movesArray[i].slice();
        moveScore = min(newGame);
        if (moveScore > best_score) {
          best_score = moveScore;
          maxnewGame = newGame;
        }
      }
      console.log('maxnewGame', maxnewGame);
      return best_score;
    }
    
    function min(board) {
    
      if (game.over(board)) {
        return score(board);
      }
      var newGame = [];
      var moveScore, minnewGame;
      var worst_score = Infinity;
      var movesArray = game.possible_moves(board, signPlayer);
    
      for (var i = 0; i < movesArray.length; i++) {
        newGame = movesArray[i].slice();
        moveScore = max(newGame);
        if (moveScore < worst_score) {
          worst_score = moveScore;
          minnewGame = newGame;
        }
      }
      console.log('minnewGame', minnewGame);
      return worst_score;
    }
    console.log(max(board));
    &#13;
    &#13;
    &#13;