| 5.4 評価と探索の修正 |
本節では修正したBoardクラスを使って探索と局面評価を行ないます。
最初に探索処理を修正します。
対象のソースコードは"com.c"です。
長くなるので関数の一部を省略してあります。
探索開始時にBoard_InitializePattern()を呼び出してパターンの初期化を行ないます。
int Com_NextMove(Com *self, const Board *in_board, int in_color, int *out_value)
{
int result;
int left;
int value;
int color;
Board_Copy(in_board, self->Board);
self->Node = 0;
left = Board_CountDisks(self->Board, EMPTY);
Com_MakeList(self);
Board_InitializePattern(self->Board);
(中略)
return result;
}
着手時にはBoard_FlipPattern()を呼び出し、1手戻すときにはBoard_UnflipPattern()を呼び出すようにします。
static int Com_MidSearch(Com *self, int in_depth, int in_alpha, int in_beta, int in_color, int in_opponent, int in_pass, int *out_move)
{
(中略)
if (in_depth > 2) {
info_num = Com_Sort(self, in_color, info);
if (info_num > 0) {
*out_move = info[0].Move->Pos;
can_move = 1;
}
for (i = 0; i < info_num; i++) {
Board_FlipPattern(self->Board, in_color, info[i].Move->Pos);
RemoveList(info[i].Move);
value = -Com_MidSearch(self, in_depth - 1, -in_beta, -max, in_opponent, in_color, 0, &move);
Board_UnflipPattern(self->Board);
RecoverList(info[i].Move);
if (value > max) {
max = value;
*out_move = info[i].Move->Pos;
if (max >= in_beta) {
return in_beta;
}
}
}
} else {
for (p = self->Moves->Next; p; p = p->Next) {
if (Board_FlipPattern(self->Board, in_color, p->Pos)) {
RemoveList(p);
if (!can_move) {
*out_move = p->Pos;
can_move = 1;
}
value = -Com_MidSearch(self, in_depth - 1, -in_beta, -max, in_opponent, in_color, 0, &move);
Board_UnflipPattern(self->Board);
RecoverList(p);
if (value > max) {
max = value;
*out_move = p->Pos;
if (max >= in_beta) {
return in_beta;
}
}
}
}
}
(中略)
return max;
}
空きマスが8個より多い場合には着手時にBoard_FlipPattern()を呼び出し、1手戻すときにBoard_UnflipPattern()を呼び出すようにします。
空きマスが8個より少ない場合には従来と同じ処理を行ないます。
空きマスが8個より少ない場合には局面評価を行なわないので、パターンの更新が必要ないためです。
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)
{
(中略)
if (in_depth > 8) {
info_num = Com_Sort(self, in_color, info);
if (info_num > 0) {
*out_move = info[0].Move->Pos;
can_move = 1;
}
for (i = 0; i < info_num; i++) {
Board_FlipPattern(self->Board, in_color, info[i].Move->Pos);
RemoveList(info[i].Move);
value = -Com_EndSearch(self, in_depth - 1, -in_beta, -max, in_opponent, in_color, 0, &move);
Board_UnflipPattern(self->Board);
RecoverList(info[i].Move);
if (value > max) {
max = value;
*out_move = info[i].Move->Pos;
if (max >= in_beta) {
return in_beta;
}
}
}
} else {
for (p = self->Moves->Next; p; p = p->Next) {
if (Board_Flip(self->Board, in_color, p->Pos)) {
RemoveList(p);
if (!can_move) {
*out_move = p->Pos;
can_move = 1;
}
value = -Com_EndSearch(self, in_depth - 1, -in_beta, -max, in_opponent, in_color, 0, &move);
Board_Unflip(self->Board);
RecoverList(p);
if (value > max) {
max = value;
*out_move = p->Pos;
if (max >= in_beta) {
return in_beta;
}
}
}
}
}
(中略)
return max;
}
候補手の並び替え時にも局面評価を行なうので、Board_FlipPattern()、Board_UnflipPattern()を呼び出すようにします。
static int Com_Sort(Com *self, int in_color, MoveInfo *out_info)
{
int info_num = 0;
MoveList *p;
MoveInfo info_tmp, *best_info;
int i, j;
for (p = self->Moves->Next; p; p = p->Next) {
if (Board_FlipPattern(self->Board, in_color, p->Pos)) {
out_info[info_num].Move = p;
out_info[info_num].Value = Evaluator_Value(self->Evaluator, self->Board);
info_num++;
Board_UnflipPattern(self->Board);
}
}
(中略)
return info_num;
}
これ以降は"evaluator.c"の修正を行ないます。
まずは評価関数Evaluator_Value()を修正します。
パターンの状態をBoard_Pattern()で取得するようにします。
int Evaluator_Value(const Evaluator *self, const Board *in_board)
{
int result = 0;
result += self->Value[PATTERN_ID_LINE4][Board_Pattern(in_board, PATTERN_ID_LINE4_1)];
result += self->Value[PATTERN_ID_LINE4][Board_Pattern(in_board, PATTERN_ID_LINE4_2)];
result += self->Value[PATTERN_ID_LINE4][Board_Pattern(in_board, PATTERN_ID_LINE4_3)];
result += self->Value[PATTERN_ID_LINE4][Board_Pattern(in_board, PATTERN_ID_LINE4_4)];
result += self->Value[PATTERN_ID_LINE3][Board_Pattern(in_board, PATTERN_ID_LINE3_1)];
result += self->Value[PATTERN_ID_LINE3][Board_Pattern(in_board, PATTERN_ID_LINE3_2)];
result += self->Value[PATTERN_ID_LINE3][Board_Pattern(in_board, PATTERN_ID_LINE3_3)];
result += self->Value[PATTERN_ID_LINE3][Board_Pattern(in_board, PATTERN_ID_LINE3_4)];
result += self->Value[PATTERN_ID_LINE2][Board_Pattern(in_board, PATTERN_ID_LINE2_1)];
result += self->Value[PATTERN_ID_LINE2][Board_Pattern(in_board, PATTERN_ID_LINE2_2)];
result += self->Value[PATTERN_ID_LINE2][Board_Pattern(in_board, PATTERN_ID_LINE2_3)];
result += self->Value[PATTERN_ID_LINE2][Board_Pattern(in_board, PATTERN_ID_LINE2_4)];
result += self->Value[PATTERN_ID_DIAG8][Board_Pattern(in_board, PATTERN_ID_DIAG8_1)];
result += self->Value[PATTERN_ID_DIAG8][Board_Pattern(in_board, PATTERN_ID_DIAG8_2)];
result += self->Value[PATTERN_ID_DIAG7][Board_Pattern(in_board, PATTERN_ID_DIAG7_1)];
result += self->Value[PATTERN_ID_DIAG7][Board_Pattern(in_board, PATTERN_ID_DIAG7_2)];
result += self->Value[PATTERN_ID_DIAG7][Board_Pattern(in_board, PATTERN_ID_DIAG7_3)];
result += self->Value[PATTERN_ID_DIAG7][Board_Pattern(in_board, PATTERN_ID_DIAG7_4)];
result += self->Value[PATTERN_ID_DIAG6][Board_Pattern(in_board, PATTERN_ID_DIAG6_1)];
result += self->Value[PATTERN_ID_DIAG6][Board_Pattern(in_board, PATTERN_ID_DIAG6_2)];
result += self->Value[PATTERN_ID_DIAG6][Board_Pattern(in_board, PATTERN_ID_DIAG6_3)];
result += self->Value[PATTERN_ID_DIAG6][Board_Pattern(in_board, PATTERN_ID_DIAG6_4)];
result += self->Value[PATTERN_ID_DIAG5][Board_Pattern(in_board, PATTERN_ID_DIAG5_1)];
result += self->Value[PATTERN_ID_DIAG5][Board_Pattern(in_board, PATTERN_ID_DIAG5_2)];
result += self->Value[PATTERN_ID_DIAG5][Board_Pattern(in_board, PATTERN_ID_DIAG5_3)];
result += self->Value[PATTERN_ID_DIAG5][Board_Pattern(in_board, PATTERN_ID_DIAG5_4)];
result += self->Value[PATTERN_ID_DIAG4][Board_Pattern(in_board, PATTERN_ID_DIAG4_1)];
result += self->Value[PATTERN_ID_DIAG4][Board_Pattern(in_board, PATTERN_ID_DIAG4_2)];
result += self->Value[PATTERN_ID_DIAG4][Board_Pattern(in_board, PATTERN_ID_DIAG4_3)];
result += self->Value[PATTERN_ID_DIAG4][Board_Pattern(in_board, PATTERN_ID_DIAG4_4)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_1)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_2)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_3)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_4)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_5)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_6)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_7)];
result += self->Value[PATTERN_ID_EDGE8][Board_Pattern(in_board, PATTERN_ID_EDGE8_8)];
result += self->Value[PATTERN_ID_CORNER8][Board_Pattern(in_board, PATTERN_ID_CORNER8_1)];
result += self->Value[PATTERN_ID_CORNER8][Board_Pattern(in_board, PATTERN_ID_CORNER8_2)];
result += self->Value[PATTERN_ID_CORNER8][Board_Pattern(in_board, PATTERN_ID_CORNER8_3)];
result += self->Value[PATTERN_ID_CORNER8][Board_Pattern(in_board, PATTERN_ID_CORNER8_4)];
/* parity */
result += self->Value[PATTERN_ID_PARITY][Board_CountDisks(in_board, EMPTY) & 1];
return result;
}
次に評価値更新処理の修正です。
修正対象となるのはEvaluator_Add()で、パターンの状態をBoard_Pattern()で取得するようにします。
void Evaluator_Add(Evaluator *self, const Board *in_board, int in_value)
{
int index;
double diff;
diff = (double)(in_value - Evaluator_Value(self, in_board));
index = Board_Pattern(in_board, PATTERN_ID_LINE4_1);
Evaluator_AddPattern(self, PATTERN_ID_LINE4, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE4_2);
Evaluator_AddPattern(self, PATTERN_ID_LINE4, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE4_3);
Evaluator_AddPattern(self, PATTERN_ID_LINE4, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE4_4);
Evaluator_AddPattern(self, PATTERN_ID_LINE4, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE3_1);
Evaluator_AddPattern(self, PATTERN_ID_LINE3, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE3_2);
Evaluator_AddPattern(self, PATTERN_ID_LINE3, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE3_3);
Evaluator_AddPattern(self, PATTERN_ID_LINE3, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE3_4);
Evaluator_AddPattern(self, PATTERN_ID_LINE3, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE2_1);
Evaluator_AddPattern(self, PATTERN_ID_LINE2, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE2_2);
Evaluator_AddPattern(self, PATTERN_ID_LINE2, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE2_3);
Evaluator_AddPattern(self, PATTERN_ID_LINE2, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_LINE2_4);
Evaluator_AddPattern(self, PATTERN_ID_LINE2, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG8_1);
Evaluator_AddPattern(self, PATTERN_ID_DIAG8, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG8_2);
Evaluator_AddPattern(self, PATTERN_ID_DIAG8, self->MirrorLine[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG7_1);
Evaluator_AddPattern(self, PATTERN_ID_DIAG7, self->MirrorLine[index * POW_3_1], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG7_2);
Evaluator_AddPattern(self, PATTERN_ID_DIAG7, self->MirrorLine[index * POW_3_1], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG7_3);
Evaluator_AddPattern(self, PATTERN_ID_DIAG7, self->MirrorLine[index * POW_3_1], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG7_4);
Evaluator_AddPattern(self, PATTERN_ID_DIAG7, self->MirrorLine[index * POW_3_1], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG6_1);
Evaluator_AddPattern(self, PATTERN_ID_DIAG6, self->MirrorLine[index * POW_3_2], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG6_2);
Evaluator_AddPattern(self, PATTERN_ID_DIAG6, self->MirrorLine[index * POW_3_2], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG6_3);
Evaluator_AddPattern(self, PATTERN_ID_DIAG6, self->MirrorLine[index * POW_3_2], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG6_4);
Evaluator_AddPattern(self, PATTERN_ID_DIAG6, self->MirrorLine[index * POW_3_2], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG5_1);
Evaluator_AddPattern(self, PATTERN_ID_DIAG5, self->MirrorLine[index * POW_3_3], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG5_2);
Evaluator_AddPattern(self, PATTERN_ID_DIAG5, self->MirrorLine[index * POW_3_3], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG5_3);
Evaluator_AddPattern(self, PATTERN_ID_DIAG5, self->MirrorLine[index * POW_3_3], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG5_4);
Evaluator_AddPattern(self, PATTERN_ID_DIAG5, self->MirrorLine[index * POW_3_3], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG4_1);
Evaluator_AddPattern(self, PATTERN_ID_DIAG4, self->MirrorLine[index * POW_3_4], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG4_2);
Evaluator_AddPattern(self, PATTERN_ID_DIAG4, self->MirrorLine[index * POW_3_4], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG4_3);
Evaluator_AddPattern(self, PATTERN_ID_DIAG4, self->MirrorLine[index * POW_3_4], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_DIAG4_4);
Evaluator_AddPattern(self, PATTERN_ID_DIAG4, self->MirrorLine[index * POW_3_4], index, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_1), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_2), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_3), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_4), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_5), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_6), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_7), -1, diff);
Evaluator_AddPattern(self, PATTERN_ID_EDGE8, Board_Pattern(in_board, PATTERN_ID_EDGE8_8), -1, diff);
index = Board_Pattern(in_board, PATTERN_ID_CORNER8_1);
Evaluator_AddPattern(self, PATTERN_ID_CORNER8, self->MirrorCorner[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_CORNER8_2);
Evaluator_AddPattern(self, PATTERN_ID_CORNER8, self->MirrorCorner[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_CORNER8_3);
Evaluator_AddPattern(self, PATTERN_ID_CORNER8, self->MirrorCorner[index], index, diff);
index = Board_Pattern(in_board, PATTERN_ID_CORNER8_4);
Evaluator_AddPattern(self, PATTERN_ID_CORNER8, self->MirrorCorner[index], index, diff);
Evaluator_AddPattern(self, PATTERN_ID_PARITY, Board_CountDisks(in_board, EMPTY) & 1, -1, diff);
}
これで本章の修正は終了です。
実行してみると中盤探索が2倍程高速になっています。
しかし終盤探索はあまり効果がないようです。
これは終盤探索のリーフ近くでは従来と同じ処理を行なっているためです。