Alpha-Beta算法简介

Alpha-Beta算法“见好就收”不再搜。| 博弈树搜索 | 贪心算法 |  666行的象棋程序下得不错啊

可运行的代码如下:

#include <stdio.h>
#include <vector>

struct { int score; char* kids; } nodes[] = {
  { 0, "BCD" }, // A 可以在这里“排序”,如CBD
  { 0, "EFG" }, // B
  { 0, "HIJ" }, // C
  { 0, "KLM" }, // D
  { 9 }, { 8 }, { 7 }, { 6 }, { 5 }, { 4 }, { 3 }, { 2 }, { 1 }
};
std::vector<int> pstack;  // position(局面) stack

const char* gen_moves() { return nodes[pstack.back()].kids; }
void make_move(char m) { pstack.push_back(m - 'A'); }
void undo_move() { pstack.pop_back(); }
int eval() { return nodes[pstack.back()].score; }
#define I do { for (int i = 0; i < 7 - 3 * d; i++) putchar(' '); } while (0) // Indent

int quiesce(int a, int b) {
  // https://www.chessprogramming.org/Quiescence_Search
  int score = eval();
  return score;
  if (score >= b) return b;
  if (score > a) a = score;
  return a;
}

int alpha_beta(int a, int b, int d) { // d:depth left(还剩几层要搜)
  const char* moves = gen_moves();
  if (!moves) return quiesce(a, b);
  I;printf("[ %d, %d ] %s\n", a, b, moves);
  for (const char* p = moves; *p; p++) {
    make_move(*p);
    int score = -alpha_beta(-b, -a, d - 1);
    if (score >= b) { I;printf("%d >= %d, ret b(%d)\n", score, b, b); return b; }
    if (score > a) { I;printf("%d > %d, now a=%d\n", score, a, score); a = score; }
        undo_move();
  }
  I;printf("ret a(%d)\n", a); return a;
}

int main() {
  pstack.push_back(0);
  int score = alpha_beta(-96, 69, 2);
  printf("%d\n", score);
  getchar(); return 0;
}

/*
 * 以象棋为例,MAX是红方,MIN是黑方。如评价函数是红方子数减去黑方子数,红想要15(16个子vs光杆老将),黑想要-15
 * 方块形的根节点是A,该红方走。下一层圆圈是B,C,D,该黑方走。再一层E..M又该红方走。
 * 搜索的目的是为红方找出最佳着法,但红方在思考时必须站在黑方的角度考虑,比如开局红方炮二进七打马,不能指望黑方
   配合,起横车不吃马。红方要找黑方尽了最大努力的情况下依然对红方有利的走法。
 [ -96, 69 ] BCD # [alpha, beta] alpha先设为-infinity,即比所有的走法都差
    [ -69, 96 ] EFG # Negative Max 很容易把人绕晕。max(3,5) == -min(-3,-5) https://www.chessprogramming.org/Negamax
    -9 > -69, a = -9
    -8 > -9, a = -8
    -7 > -8, a = -7
    ret a(-7) # 在红方已经走棋的前提下,黑方要使自己的利益最大化,即选最小的分。
 7 > -96, a = 7 # 红想“如果我炮二平五”,黑方使劲全力,我也能有7分。
    [ -69, -7 ] HIJ # 红想“如果我……”,就算黑方配合,我也最多6分。
    -7 >= -7, ret b(-7)
    [ -69, -7 ] KLM # 红想“如果我……”,就算黑方配合,我也最多5分。
    -7 >= -7, ret b(-7)
 ret a(7) # 所以,炮二平五,最少7分,黑方走错的话,9分。
7
如果斜线部分把I..M彻底涂掉,怎么知道它们的分数分别是5到1?可能是:
If one already has found a quite good move and search for alternatives, one refutation is enough to avoid it. 见好就收不再搜。
A refutation of an argument, accusation, or theory is something that proves it is wrong or untrue. (FORMAL)
也许:
1. 看到6比7小,5,4就不生成了;看到3比7小,2,1就不生成了。
2. 浅层处理,用快速的方法估计是5,就不再使用准确缓慢的方法(包括但不限于往深搜几步——指数级增长)。
*
* https://www.chessprogramming.org/Fail-Soft https://www.chessprogramming.org/Fail-Hard
*/
posted @ 2022-12-11 21:17  Fun_with_Words  阅读(486)  评论(0编辑  收藏  举报









 张牌。