递归在我的极小化极大算法实现中似乎不起作用。

huangapple go评论74阅读模式
英文:

Recursion does not seem to work in my minimax implementation

问题

The miniMax函数返回一个包含索引和分数的对象,但它没有访问预期的状态。

以下是代码的翻译部分:

    const human = 'X'
    const ai = 'O'
    const winOptions = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
    const emptyCells = (layout) => {
      return layout.map((item, index) => {
        return (item === '' ? index : null)
      }).filter((item) => item !== null)
    }
    const checkWin = (layout) => {
      for (let i = 0; i < winOptions.length; i += 1) {
        const [a, b, c] = winOptions[i]
        if (layout[a] === 'X' && layout[a] === layout[b] && layout[b] === layout[c]) {
          return -1
        }
        if (layout[a] === 'O' && layout[a] === layout[b] && layout[b] === layout[c]) {
          return 1
        }
      }
      return false
    }

    function miniMax (gameLayout, player) {
      const empty = emptyCells(gameLayout)
      if (checkWin(gameLayout) === 1) {
        return { score: 10 }
      } else if (checkWin(gameLayout) === -1) {
        return { score: -10 }
      } else if (empty.length === 0) {
        return { score: 0 }
      }
      const moves = []
      for (let i = 0; i < empty.length; i++) {
        const move = {}
        move.index = empty[i]
        player === 'O' ? gameLayout[empty[i]] = 'O' : gameLayout[empty[i]] = 'X'
        player === 'O' ? move.score = miniMax(gameLayout, human).score : move.score = miniMax(gameLayout, ai).score
        moves.push(move)
      }
      let bestMove
      if (player === 'O') {
        bestMove = moves.reduce((acc, curr, i) => moves[acc].score > curr.score ? acc : i, 0)
      } else {
        bestMove = moves.reduce((acc, curr, i) => moves[acc].score < curr.score ? acc : i, 0)
      }
      console.log(JSON.stringify(moves))
      return moves[bestMove]
    }

    // 示例运行:
    const layout = ["X", "", "",
                    "", "", "",
                    "", "", "O"]
    miniMax(layout, "X")

希望这有助于理解你的代码并找到问题。

英文:

The miniMax function returns an object consisting of an index and score as intended, but it does not visit as many states as expected.

Here is the code:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const human = &#39;X&#39;
const ai = &#39;O&#39;
const winOptions = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
const emptyCells = (layout) =&gt; {
return layout.map((item, index) =&gt; {
return (item === &#39;&#39; ? index : null)
}).filter((item) =&gt; item !== null)
}
const checkWin = (layout) =&gt; {
for (let i = 0; i &lt; winOptions.length; i += 1) {
const [a, b, c] = winOptions[i]
if (layout[a] === &#39;X&#39; &amp;&amp; layout[a] === layout[b] &amp;&amp; layout[b] === layout[c]) {
return -1
}
if (layout[a] === &#39;O&#39; &amp;&amp; layout[a] === layout[b] &amp;&amp; layout[b] === layout[c]) {
return 1
}
}
return false
}
function miniMax (gameLayout, player) {
const empty = emptyCells(gameLayout)
if (checkWin(gameLayout) === 1) {
return { score: 10 }
} else if (checkWin(gameLayout) === -1) {
return { score: -10 }
} else if (empty.length === 0) {
return { score: 0 }
}
const moves = []
for (let i = 0; i &lt; empty.length; i++) {
const move = {}
move.index = empty[i]
player === &#39;O&#39; ? gameLayout[empty[i]] = &#39;O&#39; : gameLayout[empty[i]] = &#39;X&#39;
player === &#39;O&#39; ? move.score = miniMax(gameLayout, human).score : move.score = miniMax(gameLayout, ai).score
moves.push(move)
}
let bestMove
if (player === &#39;O&#39;) {
bestMove = moves.reduce((acc, curr, i) =&gt; moves[acc].score &gt; curr.score ? acc : i, 0)
} else {
bestMove = moves.reduce((acc, curr, i) =&gt; moves[acc].score &lt; curr.score ? acc : i, 0)
}
console.log(JSON.stringify(moves))
return moves[bestMove]
}
// Example run:
const layout = [&quot;X&quot;, &quot;&quot;, &quot;&quot; , 
&quot;&quot; , &quot;&quot;, &quot;&quot; ,
&quot;&quot; , &quot;&quot;, &quot;O&quot;]
miniMax(layout, &quot;X&quot;)

<!-- end snippet -->

Here is how it looks, with the console output as produced in the above snippet:

递归在我的极小化极大算法实现中似乎不起作用。

Clearly my minimax implementation for Tic Tac Toe doesn't work as expected. The console should be flooded with output, since there are many options for enumeration. But it displays only 6 lines of output, as if the recursion does not work and does not go into every possible option.

I've been trying to find a bug for days... What is wrong with this implementation?

答案1

得分: 2

问题在于播放的移动没有被撤销。函数按照预期递归调用,但之后棋盘已满,之后不再更改。因此,对于所有执行上下文,empty.length 都将为 0,并且递归将在不进行其他移动的情况下解开。

为了解决这个问题,在push之后添加以下行:

gameLayout[empty[i]] = ''; // 撤销
英文:

The problem is that the played moves are not taken back. The function is called recursively as intended, but then the board is full and it never changes after that. By consequence empty.length will be 0 for all execution contexts, and the recursion will unwind without making other moves.

To fix this, add this line after the push:

gameLayout[empty[i]] = &#39;&#39;; // take back

huangapple
  • 本文由 发表于 2023年5月26日 08:02:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76336889.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定