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倍程高速になっています。
しかし終盤探索はあまり効果がないようです。
これは終盤探索のリーフ近くでは従来と同じ処理を行なっているためです。