Минимаксная функция Javascript чрезвычайно медленная - PullRequest
0 голосов
/ 01 мая 2018

После инициирования движения искусственного интеллекта в крестики-нолики (в настоящее время оно написано только для оценки того, может ли miniMax успешно работать), для завершения в firefox или chrome требуется около 1–1,5 минут. Другие минимаксные функции игры в крестики-нолики запускаются на моем компьютере за короткое время. Регистрация результатов не привела к приближению к решению. Убедитесь, что все состояния терминала возвращают счет. Здесь есть очевидная ошибка?

Codepen

$(document).ready(function() {
  var state = {
  status: "inProgress",
  turn: "human", //can be human or AI
  game: 1,

turnSwitch: function() {
  if (this.turn == "human") {
    return (this.turn = "AI");
  } else if (this.turn == "AI") {
    return (this.turn = "human");
    }
  }
};

//AI will use minimx algorithm to determine best possible move
function player(name, symbol) {
  this.name = name;
  this.symbol = symbol;
}

var human = new player("human", "X");
var AI = new player("AI", "O");

var board = {
    board: [],

    createBoard: function() {
      for (let i = 0; i < 9; i++) {
        this.board.push(i);
      }
      return this.board;
    },

    resetBoard: function() {
      this.board = [];
      createBoard();
    },

    //checks board for terminal state
    terminalTest: function() {
      for (let i = 0; i < 7; i += 3) {
        if (
          this.board[i] == this.board[i + 1] &&
          this.board[i] == this.board[i + 2]
        ) {
          if (typeof this.board[i] !== "number") {
            return this.board[i];
          }
        }
      }

      for (let j = 0; j < 3; j++) {
        if (
          this.board[j] == this.board[j + 3] &&
          this.board[j] == this.board[j + 6]
        ) {
          if (typeof this.board[j] !== "number") {
            return this.board[j];
          }
        }
      }
      if (
        (this.board[0] == this.board[4] && this.board[0] == this.board[8]) ||
        (this.board[2] == this.board[4] && this.board[2] == this.board[6])
      ) {
        if (typeof this.board[4] !== "number") {
          return this.board[4];
        }
      }
    },

    //checks for possible moves
    findEmptyIndicies: function() {
      return this.board.filter(a => typeof a == "number");
    }
  };



function miniMax(boardCurrent, player) {
    //store all possible moves
    var availableMoves = boardCurrent.findEmptyIndicies();
    console.log("available moves length " + availableMoves.length);

    //if terminal state, return score
    var terminalCheck = boardCurrent.terminalTest();

    if (terminalCheck === "X") {
      //console.log(boardCurrent.board + " X wins score: -10")
      return human.symbol == "X" ? { score: -10 } : { score: 10 };
    } else if (terminalCheck === "O") {
      //console.log(boardCurrent.board + " ) wins score: 10")
      return human.symbol == "X" ? { score: 10 } : { score: -10 };
    } else if (availableMoves.length === 0) {
      console.log("availmoves length 0 " + availableMoves.length);
      //console.log(boardCurrent.board + " score: 0")
      return { score: 0 };
    }
    //array to store objects containing index and score through each iteration of available moves
    var movesArray = [];

    for (var i = 0; i < availableMoves.length; i++) {
      //create object to store return score from each index branch
      var move = {};

      move.index = boardCurrent.board[availableMoves[i]];

      boardCurrent.board[availableMoves[i]] = player.symbol;

      //returned score from leaf node if conditionials at top of function are met

      if (player.name == "AI") {
        var miniMaxReturn = miniMax(boardCurrent, human);
        move.score = miniMaxReturn.score;
        console.log("move score " + move.score);
      } else {
        var miniMaxReturn = miniMax(boardCurrent, AI);
        move.score = miniMaxReturn.score;
        console.log("move score " + move.score);
      }

      boardCurrent.board[availableMoves[i]] = move.index;

      movesArray.push(move);
    }
    var bestMove;
    console.log("moves array length " + movesArray.length);
    if (player.name === "AI") {
      let bestScore = -1000;
      for (let i = 0; i < movesArray.length; i++) {
        if (movesArray[i].score > bestScore) {
          bestScore = movesArray[i].score;

          bestMove = i;
        }
      }
    } else if (player.name === "human") {
      let bestScore = 1000;
      for (let i = 0; i < movesArray.length; i++) {
        if (movesArray[i].score < bestScore) {
          bestScore = movesArray[i].score;
          bestMove = i;
        }
      }
    }

    return movesArray[bestMove];
  }



/**function AIMove() {
    console.log("ai move initiated");
    var AIPosition = miniMax(board, AI);
    //var index = AIposition.index;
    //console.log(AIposition);
    //$("#" + index).html(AI.symbol);
  }**/

  $(".cell").click(displayMove);

  function displayMove() {
    if (state.turn == "human") $(this).html(human.symbol);

    board.board[this.id] = human.symbol;

    state.turn = "AI";
    miniMax(board, AI);
    //AIMove();
    console.log("AI move complete");
  }

  $(".cell").click(displayMove);

  //on window load create board
  board.createBoard();

});
...