创建一个简单的国际象棋AI:5个简单步骤



我们为您翻译了劳里·哈蒂卡(Lauri Hartikka)撰写的有关创建最简单的国际象棋AI的文章。 它写于2017年,但基本原理保持不变。 Lori使用的所有文件也都可用。

可以基于以下四个概念创建可以下棋的简单人工智能:

  1. 1.搬家
  2. 2.董事会评估;
  3. 3.极小极大
  4. 4. Alpha Beta裁剪 。 在使用算法的每个阶段,将使用其中之一,这将逐渐提高AI的游戏能力。

Skillbox建议: Python数据分析师应用在线课程。

我们提醒您: 对于所有“ Habr”读者来说,使用“ Habr”促销代码注册任何Skillbox课程时均可享受10,000卢布的折扣。

现成的源代码可以在GitHub找到


阶段1.棋盘可视化并产生移动


此时,我们将使用Chess.js库生成移动,并使用Chessboard.js渲染棋盘。 该库负责生成动作,您可以应用所有国际象棋规则,以便我们可以计算特定棋子排列的每个动作。


当您单击图片时,它将以全分辨率打开。

使用这些库可以使您专注于主要任务-搜索并创建算法,以找到最佳移动。 我们通过编写一个函数来开始工作,该函数从所有可能的列表中返回随机移动。

var calculateBestMove =function(game) { //generate all the moves for a given position var newGameMoves = game.ugly_moves(); return newGameMoves[Math.floor(Math.random() * newGameMoves.length)]; }; 

尽管该算法不是理想的棋手,但对于该级别的大多数棋手来说已经足够了。


黑色随机移动。 ( 在线来源和游戏

第二阶段。职位评估


现在,让我们找出在该位置或该位置哪一方具有优势。 最简单的方法是计算板上零件的相对强度,这可以使用表格完成。



使用评估功能,我们有机会创建一个算法,该算法选择具有最高评级的举动。

 var calculateBestMove = function (game) { var newGameMoves = game.ugly_moves(); var bestMove = null; //use any negative large number var bestValue = -9999; for (var i = 0; i < newGameMoves.length; i++) { var newGameMove = newGameMoves[i]; game.ugly_move(newGameMove); //take the negative as AI plays as black var boardValue = -evaluateBoard(game.board()) game.undo(); if (boardValue > bestValue) { bestValue = boardValue; bestMove = newGameMove } } return bestMove; }; 

原则上,级别是相同的,但是当存在这样的机会时,算法已经可以获取他人的身影。


黑方有机会拍白方。 (来源和游戏在这里 )。

阶段3。使用minimax搜索树


之后,我们创建一个搜索树。 现在,程序可以从中选择最佳动作。 这是使用minimax算法完成的。

在这里,将显示所有可能动作的递归树分析到给定深度。 该位置由我们树上的叶子估计。

接下来,我们将子级的最小值或最大值返回到父级节点。 这完全取决于当前计算错误的一方。 换句话说,结果在每个级别上都最大化或最小化。


在这里,b2-c3是怀特的最佳举动,因为他确保玩家以-50的分数到达该位置。

 var minimax = function (depth, game, isMaximisingPlayer) { if (depth === 0) { return -evaluateBoard(game.board()); } var newGameMoves = game.ugly_moves(); if (isMaximisingPlayer) { var bestMove = -9999; for (var i = 0; i < newGameMoves.length; i++) { game.ugly_move(newGameMoves[i]); bestMove = Math.max(bestMove, minimax(depth - 1, game, !isMaximisingPlayer)); game.undo(); } return bestMove; } else { var bestMove = 9999; for (var i = 0; i < newGameMoves.length; i++) { game.ugly_move(newGameMoves[i]); bestMove = Math.min(bestMove, minimax(depth - 1, game, !isMaximisingPlayer)); game.undo(); } return bestMove; } }; 

借助minimax算法,我们的AI已经开始了解国际象棋的基本策略。

深度为2的Minimax(来源和此处的游戏)

值得注意的是,maxmax算法的效率随搜索深度的增加而增加。 下一步对此负责。

阶段4. Alpha Beta剪切


这是一种minimax算法优化方法,可以忽略搜索树中的某些分支。 而且,您可以使用相同数量的资源来增加搜索深度。

Alpha Beta裁剪基于这样一种情况,即如果发现新的举动会导致比评估上一个分支时看到的情况更糟糕的情况,我们可以停止评估特定分支。

优化不会影响minimax的结果,但是一切都会开始更快地工作。

如果您先检查导致良好移动的路径,此算法将更加有效。


该图显示了使用alpha beta裁剪时不必要的移动。

如您所见,通过alpha-beta裁剪,对minimax进行了优化,而且效果非常明显。


如上所示,在深度为4且搜索起始位置的情况下要评估的位置数。 (可在此处找到源代码和游戏)

步骤5:改进的评估功能


初始评估功能非常简单,因为它只计算板上的零件数。 要对其进行优化,可以考虑图形的位置。 例如,如果将马放在板子的中央,那么它将变得更昂贵-此棋子的可用移动范围将扩大。

此时,我们将使用最初在Chess Programming Wiki中描述的方表的略微修改版本。



现在,与普通玩家相比,我们的算法已经表现得相当不错。


来源和游戏都可以在这里找到。

结论


所提出的算法的优点是它不会犯非常愚蠢的错误。 当然,这里的策略很难称得上是完美的,但是。

我们算法的实现只有200行代码,因此基本原理非常简单。 该程序的最终版本可以是在GitHub上看到的<a href= target github.com/lhartikk/simple-chess-ai'>

可以将其他模块添加到算法中,包括:



有关国际象棋算法的更多信息,请参见Chess Programming Wiki

Skillbox建议:

Source: https://habr.com/ru/post/zh-CN437524/


All Articles