- int MinMax(int depth) {
- if (SideToMove() == WHITE) { // 白方是“最大”者
- return Max(depth);
- } else { // 黑方是“最小”者
- return Min(depth);
- }
- }
- int Max(int depth) {
- int best = -INFINITY;
- if (depth <= 0) {
- return Evaluate();
- }
- GenerateLegalMoves();
- while (MovesLeft()) {
- MakeNextMove();
- val = Min(depth - 1);
- UnmakeMove();
- if (val > best) {
- best = val;
- }
- }
- return best;
- }
- int Min(int depth) {
- int best = INFINITY; // 注意这里不同于“最大”算法
- if (depth <= 0) {
- return Evaluate();
- }
- GenerateLegalMoves();
- while (MovesLeft()) {
- MakeNextMove();
- val = Max(depth - 1);
- UnmakeMove();
- if (val < best) { // 注意这里不同于“最大”算法
- best = val;
- }
- }
- return best;
- } 上面的代码可以这样调用:
- val = MinMax(5); 这样可以返回当前局面的评价,它是向前看 5步的结果。 这里的“评价”函数用的是我上面所说第一种定义,它总是返回对于白方来说的局面。 我简要描述一下这个函数是如何运作的。假设根局面 (棋盘上当前局面 )是白方走,那么调用的是“ Max”函数,它产生白方所有合理着法。在每个后续局面中,调用的是“ Min”函数,它对局面作出评价并返回。由于现在是白走,因此白方需要让评价尽可能地大,能得到最大值的那个着法被认为是最好的,因此返回这个着法的评价。 “ Min”函数正好相反,当黑方走时调用“ Min”函数,而黑方需要尽可能地小,因此选择能得到最小值的那个着法。 这两个函数是互相递归的,即它们互相调用,直到达到所需要的深度为止。当函数到达最底层时,它们就返回“ Evaluate”函数的值。 如果在深度为 1时调用“ MinMax”函数,那么“ Evaluate”函数在走完每个合理着法之后就调用,选择一个能达到最佳值的那个着法导致的局面。如果层数大于 1,那么另一方有权选择局面,并找一个最好的。 以上内容应该不难理解,但是代码很长,下面有个更好的办法。 负值最大函数 负值最大只是对最小-最大的优化,“评价”函数返回我所说的第二种定义,对于当前结点上要走的一方,占优的情况返回正值,其他结点也是对于要走的一方而言的。这个值返回后要加上负号,因为返回以后就是对另一方而言了。代码如下:
- int NegaMax(int depth) {
- int best = -INFINITY;
- if (depth <= 0) {
- return Evaluate();
- }
- GenerateLegalMoves();
- while (MovesLeft()) {
- MakeNextMove();
- val = -NegaMax(depth - 1); // 注意这里有个负号。
- UnmakeMove();
- if (val > best) {
- best = val;
- }
- }
- return best;
- } 在这个函数里,当走子一方改变时就要对返回值取负值,以反映当前局面评价的更改。就根结点是白先走的情况,如果没有剩下的层数,那么“评价”返回的值是就白方而言的,如果有剩下的层数,就产生后续局面,函数对这些局面逐一做递归,每个次递归都得到就黑方而言的评价,黑方走得越好值就越大。当评价值返回时,它们被取负数,变成就白方而言的评价。 该函数在遍历时结点的顺序同“最小 -最大”搜索的函数是一样的,产生的返回值也一样。它的代码更短,同时减少了移植代码时出错的可能,代码维护起来也比较方便。 原文: http://www.seanet.com/~brucemo/topics/minmax.htm 译者:象棋百科全书网 ( webmaster@xqbase.com )
最小-最大搜索
最新推荐文章于 2020-04-29 23:47:50 发布