改进Minimax算法

时间:2011-07-31 06:00:10

标签: c++ algorithm

目前我正在用c ++开发奥赛罗/黑白棋游戏。我把它“完成”了,只是当我将它设置在产生半挑战AI的深度时,我用于计算机播放器的Minimax算法非常缓慢。

我的游戏的基本设置是电路板由二维数组表示,电路板上的每个单元都在数组中分配了一个值(xMarkeroMarker或{{ 1}})。

到目前为止,这是minimax算法:

underscore

函数signed int Computer::simulate(Board b, int depth, int tempMarker) { if (depth > MAX_DEPTH || b.gameOver()) { int oppMarker = (marker == xMarker) ? oMarker : xMarker; return b.countForMarker(marker) - b.countForMarker(oppMarker); } //if we're simulating our turn, we want to find the highest value (so we set our start at -64) //if we're simulating the opponent's turn, we want to find the lowest value (so we set our start at 64) signed int start = (tempMarker == marker) ? -64 : 64; for (int x = 0; x < b.size; x++) { for (int y = 0; y < b.size; y++) { if (b.markerArray[x][y] == underscore) { Board *c = b.duplicate(); if(c->checkForFlips(Point(x,y), tempMarker, true) > 0) { int newMarker = (tempMarker == xMarker) ? oMarker : xMarker; int r = simulate(*c, depth+1, newMarker); //'marker' is the marker assigned to our player (the computer), if it's our turn, we want the highest value if (tempMarker == marker) { if(r > start) start = r; } else { //if it's the opponent's turn, we want the lowest value if(r < start) start = r; } } delete c; } } } return start; } 返回在给定单元格中播放所产生的翻转次数。此时MAX_DEPTH设置为6,而且速度很慢(每次播放可能大约10-15秒)

到目前为止,我想出的唯一想法是每次都存储树,然后从我离开的地方拿起,但我不确定如何实现它或是否会太有效了。任何想法或建议将不胜感激!

4 个答案:

答案 0 :(得分:5)

计算极小极大值很慢。 第一个可能的优化是alpha-beta修剪: http://en.wikipedia.org/wiki/Alpha-beta_pruning

答案 1 :(得分:4)

你不应该复制董事会,这是非常低效的。在递归调用自己之前进行移动,但保存足够的信息以在从递归调用返回后撤消相同的移动。这样你只需要一块板子。

但Shiroko是对的,alpha-beta修剪是第一步。

答案 2 :(得分:0)

@ Shiroko的建议很棒,但还有更多的优化机会。

您通过值传递Board的状态,然后将其复制到循环内。我将董事会作为指针或const Board& b传递。如果这仍然是昂贵的,你可以使用一个poinger到一个单板,并在评估后反转每一步。在任何情况下都不要在堆上分配它。

您还可以在多个核心上运行此算法。您需要使用openmp(或等效的)在第一级编写for循环的变体。

答案 3 :(得分:0)

改善它的最明显的方法是通过alpha-beta修剪或negascout。

但是,如果你想坚持使用minimax,你就不能让它变得太快,因为它是一种蛮力算法。改进它的一种方法是将其改为Negamax,这将消除此代码中所需的一些逻辑。另一种方法是使用一维数组作为电路板而不是电路板。为了使计算更容易,使用100的长度,所以位置是行列形式(例如,索引27是第2行,第7列)。

但如果你想要更快,请尝试修剪。