| 2.5 αβ法 | 
αβ法とは、MinMax法を改良したアルゴリズムです。
MinMax法と比較して探索ノード数を大幅に減らし、かつMinMax法と同じ結果を得られるという特徴があります。
下図はMinMax法の説明に使用した図ですが、ノードに名前をつけています。
またいくつかのノードにX印がついています。
このX印は何を意味しているのでしょうか。

αβ法による探索
各ノードで、左の子ノードを先に探索すると仮定します。
するとJの評価を行った段階で、Kの評価を行う必要がなくなります。
この理由は以下の通りです。
Jを評価したときには評価値6という上限によって探索が打ち切られています。
これをβカットと呼びます。
同様の理由によりG以下のノードも評価の必要がなくなります。
Fを評価したときには評価値6という下限によって探索が打ち切られています。
これをαカットと呼びます。
αカットとβカットを行うことで、探索ノードを減らすことができます。
これが、αβ法の探索ノード数がMinMaxと比較して少ない理由です。
またαβ法には、αとβの範囲にある手だけを選択するという特徴もあります。
このように上限と下限を設けて探索を行う手法をWindow探索と呼びます。
上記の例では自分の手番で評価値最大化、相手の手番で評価値最小化を行っていますが、
NegaMax法と同様に、各ノードで評価値最大化をすればよいように改良することもできます。
実際にはこの改良版を使用します。
それではαβ法の実装をしましょう。
static int Com_EndSearch(Com *self, int in_depth, int in_alpha, int in_beta, int in_color, int in_opponent, int in_pass, int *out_move)
{
	int x, y;
	int value, max = in_alpha;
	int can_move = 0;
	int move;
	if (in_depth == 0) {
		self->Node++;
		return Board_CountDisks(self->Board, in_color) - Board_CountDisks(self->Board, in_opponent);
	}
	*out_move = NOMOVE;
	for (x = 0; x < BOARD_SIZE; x++) {
		for (y = 0; y < BOARD_SIZE; y++) {
			if (Board_Flip(self->Board, in_color, Board_Pos(x, y))) {
				if (!can_move) {
					*out_move = Board_Pos(x, y);
					can_move = 1;
				}
				value = -Com_EndSearch(self, in_depth-1, -in_beta, -max, in_opponent, in_color, 0, &move);
				Board_Unflip(self->Board);
				if (value > max) {
					max = value;
					*out_move = Board_Pos(x, y);
					if (max >= in_beta) {
						return in_beta;
					}
				}
			}
		}
	}
	if (!can_move) {
		if (in_pass) {
			*out_move = NOMOVE;
			self->Node++;
			max = Board_CountDisks(self->Board, in_color) - Board_CountDisks(self->Board, in_opponent);
		} else {
			*out_move = PASS;
			max = -Com_EndSearch(self, in_depth, -in_beta, -max, in_opponent, in_color, 1, &move);
		}
	}
	return max;
}
引数は以下の通りです。
NegaMax法と異なるのは、α値とβ値が加わっている点です。
self : Comクラスへのポインタ
in_depth : 探索の手数(Com_EndSearch()の場合は空きマスの数と一致する)
in_alpha : α値(探索の下限)
in_beta : β値(探索の上限)
in_color : 自分の手番
in_opponent : 相手の手番
in_pass : 直前の手がパスなら1、パスでなければ0
*out_move : 選択した手を格納しておく。
処理はNegaMax法の場合とほぼ同じですが、評価値がβ値以上になったときに探索を打ち切る(βカット)点が違います。
それではαβ法で探索を行うプログラムと対局を行ってみましょう。
main()を実行するとコンピュータと対局を行います。
NegaMax法の場合と同じ手を選ぶようになっていますが、思考時間が大幅に減っているはずです。
コンピュータ思考時に探索時間、探索ノード数が表示されるので確認してください。