could someone explain minimax tic tac toe algorithm
我正在研究井字游戏(用户与计算机)的AI,并且正在使用minimax算法来实现计算机的最佳移动。我看过youtube上的一些视频,并阅读了一些人的代码。但是,我仍然对正在执行的部分代码感到困惑。让我们以tic tac toe minimax函数的以下代码为例。有一个主要的if,else if,else语句,其他所有内容都从那里派生。我的主要问题是了解嵌入式for循环,以及随后的2个ifs。我认为我在做些评论。我从以下youtube视频中获取了示例代码:https://www.youtube.com/watch?v=x_Je9i3aKNk
井字游戏的minimax函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | //minimax function function minimax(newGrid, depth, player) { const gameState = isGameOver(newGrid); //if the game is not over, evalute best move for computer if(gameState === false) { const values = []; for(var i = 0; i < 3; i++) { for(var j = 0; j < 3; j++) { const gridCopy = _.cloneDeep(newGrid); //if that spot is taken, skip to next loop if(gridCopy[i][j] !== ' ') continue; //if spot is player, evaluate gridCopy[i][j] = player; //need clarification const value = minimax(gridCopy, depth+1, (player == PLAYER_TOKEN) ? COMPUTER_TOKEN : PLAYER_TOKEN); values.push(value); } } //need clarification for computer turn if(player === COMPUTER_TOKEN) { const max = _.maxBy(value, (v) => { return v.cost; }); if(depth === 0) { return max.cell; } else { return max.cost; } //need clarification for user turn else { const min = _.minBy(value, (v) => { return v.cost; }); if(depth === 0) { return v.cell; } else { return v.cost; } } //if game state is null return 0 else if (gameState === null) { return 0; } //if game state is player return negative else if(gameState === PLAYER_TOKEN) { return depth - 10; } //if game state is computer return positive else if(gameState === COMPUTER_TOKEN) { return 10 - depth; } } |
Minimax算法的关键是在两个玩家之间来回移动,"转弯"的玩家希望以最大得分来选择移动。反过来,每个可用动作的得分由对方玩家决定哪个可用动作具有最小得分来对方玩家的得分再次由轮到玩家决定,试图使得分最大化,依此类推,一直到移动树到最终状态为止。
关于算法的描述,假设X是"转弯牌手",则类似于:
- 如果游戏结束,请从X的angular返回分数。
- 否则,获取所有可能动作的新游戏状态列表
- 创建分数列表
- 对于这些状态中的每个状态,将该状态的minimax结果添加到分数列表
- 轮到X了,从得分列表中返回最大得分
- 轮到O了,从得分列表中返回最低得分
您会注意到该算法是递归的,它在玩家之间来回翻转直到找到最终分数。
让我们通过完整的移动树来逐步完成算法的执行,并说明为什么在算法上会选择即时获胜的移动:
- X进入状态1。X生成状态2、3和4,并在这些状态上调用minimax。
- 状态2将得分10推到状态1的得分列表,因为游戏处于结束状态。
- 状态3和4不在结束状态,因此3生成状态5和6并对其调用minimax,而状态4生成状态7和8并对其调用minimax。
- 状态5将-10的分数推到状态3的分数列表上,而状态7则将状态-10的分数推到状态4的分数列表上。
- 状态6和状态8生成了唯一可用的移动,即结束状态,因此它们都将得分10加到状态3和状态4的移动列表中。
-
因为在状态3和状态4都轮到O了,所以O将寻求找到
最低得分,并在-10和10之间选择,两种状态
3和4将产生-10。 - 最后,状态2、3和4的得分列表分别填充有10,-10和-10,而试图最大化得分的状态1将选择得分为10的获胜举动(状态2)。
有关代码中算法的更多详细信息和实现,您可以阅读以下文章:
井字游戏:了解Minimax算法
在线版本井字游戏
github上的源代码
参考:http://neverstopbuilding.com/minimax
这是我们的演示幻灯片