Javascript Tic Tac Toe minimax AI在游戏结束后不工作。递归问题,它们在哪里?

Javascript Tic Tac Toe minimax AI在游戏结束后不工作。递归问题,它们在哪里?,javascript,recursion,artificial-intelligence,tic-tac-toe,minimax,Javascript,Recursion,Artificial Intelligence,Tic Tac Toe,Minimax,我设法为我的tic-tac-toe工作获得了一个非常简单的人工智能,但只有在最后一步,当这是两个明显的选择时——我可以让算法在剩下的一个空格中放置一个标记,看看是否有赢家,如果没有,清除棋盘,将其放在另一个空格中,看看是否有赢家,然后返回正确的选择 但是,当我尝试执行递归时,有些地方不正常。你能看一下并告诉我它在哪里散架吗?我躲开了,这对我来说似乎是对的。它也很慢,所以我一定是在什么地方搞砸了 function bestAIMove() { var smartAIArray = listE

我设法为我的tic-tac-toe工作获得了一个非常简单的人工智能,但只有在最后一步,当这是两个明显的选择时——我可以让算法在剩下的一个空格中放置一个标记,看看是否有赢家,如果没有,清除棋盘,将其放在另一个空格中,看看是否有赢家,然后返回正确的选择

但是,当我尝试执行递归时,有些地方不正常。你能看一下并告诉我它在哪里散架吗?我躲开了,这对我来说似乎是对的。它也很慢,所以我一定是在什么地方搞砸了


function bestAIMove() {
  var smartAIArray = listEmptySpaces();
  let bestScore = -100000
  var move;
  for (var i = 0; i < smartAIArray.length; i++) {
    let smartAIpicked = smartAIArray[i];
    origBoard[smartAIpicked].classList.add(TWO_CLASS);
    origBoard[smartAIpicked].innerHTML = TWO_CLASS;
      let score = minimax(origBoard)
      origBoard[smartAIpicked].classList.remove(TWO_CLASS);
      origBoard[smartAIpicked].innerHTML = "";
  if (score > bestScore) {
    bestScore = score;
    move = smartAIpicked;
    console.log(move)
  } 
}
origBoard[move].classList.add(TWO_CLASS);
origBoard[move].innerHTML = TWO_CLASS;
}





function minimax() {
  if (playerhasWon() &&  playerOneTurn) {
    return -10;
  } else if (playerhasWon() && !playerOneTurn) {
    return 10;
  } else if (emptySpaceRemains() == false) {
    return 0;
  }
  swapTurns()

// the recursive part from here down is the problem

  if (!playerOneTurn) {
    let bestScore = -100000; 
    var smartAIArray = listEmptySpaces();
    for (var i = 0; i < smartAIArray.length; i++) {
      let smartAIpicked = smartAIArray[i];
      origBoard[smartAIpicked].classList.add(TWO_CLASS);
      origBoard[smartAIpicked].innerHTML = TWO_CLASS;
        let score = minimax(origBoard)
        origBoard[smartAIpicked].classList.remove(TWO_CLASS);
        origBoard[smartAIpicked].innerHTML = "";
        if (score > bestScore) {
          bestScore = score}
      }
    return bestScore;
    }
   else {


    let bestScore = 100000; 
    var smartAIArray = listEmptySpaces();
    for (var i = 0; i < smartAIArray.length; i++) {
      let smartAIpicked = smartAIArray[i];
      origBoard[smartAIpicked].classList.add(ONE_CLASS);
      origBoard[smartAIpicked].innerHTML = ONE_CLASS;
        let score = minimax(origBoard)
      origBoard[smartAIpicked].classList.remove(ONE_CLASS);
      origBoard[smartAIpicked].innerHTML = "";
      if (score < bestScore) {
        bestScore = score}
      }
    return bestScore;
  }
}

函数bestAIMove(){
var smartAIArray=listemptyspace();
让bestScore=-100000
var移动;
对于(变量i=0;i最佳分数){
最佳分数=分数;
移动=智能拾取;
控制台日志(移动)
} 
}
origBoard[move].classList.add(两个类);
origBoard[move].innerHTML=TWO_类;
}
函数minimax(){
如果(playerHaswen()&&playerTurn){
返回-10;
}else if(playerhasWon()&&!playerTurn){
返回10;
}else if(EmptySpaceResistings()==false){
返回0;
}
swapTurns()
//下面的递归部分就是问题所在
如果(!转){
让bestScore=-100000;
var smartAIArray=listemptyspace();
对于(变量i=0;i最佳分数){
最佳得分=得分}
}
返回最佳分数;
}
否则{
让bestScore=100000;
var smartAIArray=listemptyspace();
对于(变量i=0;i
如果我只是将代码限制为
bestAIMove
If
语句,该语句用于计算
minimax()
中的分数,那么它会起作用。尽管它基本上是
bestAIMove()

  • bestAIMove()
    
  • 更改
    origBoard
    以在[i]空间中放置标记
  • 通过
    minimax()
    评估分数
  • 如果没有得分,则运行
    swapTurns()
    ,然后转到
    else
    部分
    minimax
  • 再次转到listemptyspace()。运行另一个for循环。在[i]空间中再次放置一个标记
  • 再次通过
    minimax()
    评估分数
  • 如果没有分数,则运行
    swapTurns()
  • 然后,如果(!playerOneTurn)
  • 最小最大值的一部分,则从
    开始
    
  • 重复,直到你得到分数
  • 该分数位于bestAIMove中
  • 移除用于测试斑点的标记
  • 将评估下一个空空间
  • 得分最高的空白区域是标记器的位置
  • 相应的空格将被称为
    move
    ,表示AI移动的位置
我错过了什么?谢谢

概述 我对此很感兴趣。我最初的编程经历之一是在TRS-80上用旧的行号BASIC编写tic-tac-toe。(是的,我已经那么老了!)我想从那以后的四十年里我都没有试过写过。具有递归、一级函数等功能的现代语言使这个项目比13岁的我更容易

下面尝试为一个简单的棋盘编写一个合理的minimax函数,例如
['1','X','3','4','5','O','7','8','9']
和一个播放器
'X'
'O'
。其想法是,该模型可以很容易地用作任何用户界面的基础,您可以选择显示和与游戏交互

设计 我们使用许多小的——甚至很小的——单一用途函数来操作简单的数据类型。所有数据都是不可变的。这些都不是全球性的。我们只需将必要的项传递给每个函数,并返回结果,而不是修改全局对象。此代码根本不处理用户界面。一个完整的系统将在这里的功能之上分层

代码
const randomChoice=(xs)=>
xs[Math.floor(Math.random()*xs.length)]
常量移动=(玩家、方块、棋盘)=>
board.map(x=>x==square?玩家:x)
const availableMoves=(板)=>
board.filter(x=>/\d/.test(x))
const checkWin=((赢)=>(玩家、棋盘)=>
赢。一些(方块=>方块。每个(方块=>棋盘[方块-1]==玩家))
) ([[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 4, 7], [2, 5, 8], [3, 6, 9], [1, 5, 9], [3, 5, 7]])
常数分数=(板)=>
checkWin('X',板)?10:checkWin(“O”,板)-10 : 0
常数层=(玩家)=>
玩家=='X'?'O':'X'
常量比较=(测试)=>(最佳,{move,score})=>
测试(分数,最佳[0]。分数)
? [{移动,得分}]
:得分==最佳[0]。得分
? […最佳,{移动,得分}]
:最好的
常量最佳移动=(pla)