| 5.3 着手時のパターン更新 |
本節では着手時のパターン更新処理について説明します。
前節に引き続き"board.c"の修正を行ないます。
まず1マスの状態が変わったときにパターンを更新する関数を記述します。
これは全部で6個あり、名前と役割は以下の通りです。
static void Board_FlipSquareBlack(Board *self, int in_pos)
{
self->Disk[in_pos] = BLACK;
self->Pattern[self->PatternID[in_pos][0]] -= self->PatternDiff[in_pos][0];
self->Pattern[self->PatternID[in_pos][1]] -= self->PatternDiff[in_pos][1];
self->Pattern[self->PatternID[in_pos][2]] -= self->PatternDiff[in_pos][2];
self->Pattern[self->PatternID[in_pos][3]] -= self->PatternDiff[in_pos][3];
self->Pattern[self->PatternID[in_pos][4]] -= self->PatternDiff[in_pos][4];
self->Pattern[self->PatternID[in_pos][5]] -= self->PatternDiff[in_pos][5];
}
static void Board_FlipSquareWhite(Board *self, int in_pos)
{
self->Disk[in_pos] = WHITE;
self->Pattern[self->PatternID[in_pos][0]] += self->PatternDiff[in_pos][0];
self->Pattern[self->PatternID[in_pos][1]] += self->PatternDiff[in_pos][1];
self->Pattern[self->PatternID[in_pos][2]] += self->PatternDiff[in_pos][2];
self->Pattern[self->PatternID[in_pos][3]] += self->PatternDiff[in_pos][3];
self->Pattern[self->PatternID[in_pos][4]] += self->PatternDiff[in_pos][4];
self->Pattern[self->PatternID[in_pos][5]] += self->PatternDiff[in_pos][5];
}
static void Board_RemoveSquareBlack(Board *self, int in_pos)
{
self->Disk[in_pos] = EMPTY;
self->Pattern[self->PatternID[in_pos][0]] -= self->PatternDiff[in_pos][0];
self->Pattern[self->PatternID[in_pos][1]] -= self->PatternDiff[in_pos][1];
self->Pattern[self->PatternID[in_pos][2]] -= self->PatternDiff[in_pos][2];
self->Pattern[self->PatternID[in_pos][3]] -= self->PatternDiff[in_pos][3];
self->Pattern[self->PatternID[in_pos][4]] -= self->PatternDiff[in_pos][4];
self->Pattern[self->PatternID[in_pos][5]] -= self->PatternDiff[in_pos][5];
}
static void Board_RemoveSquareWhite(Board *self, int in_pos)
{
self->Disk[in_pos] = EMPTY;
self->Pattern[self->PatternID[in_pos][0]] -= self->PatternDiff[in_pos][0] + self->PatternDiff[in_pos][0];
self->Pattern[self->PatternID[in_pos][1]] -= self->PatternDiff[in_pos][1] + self->PatternDiff[in_pos][1];
self->Pattern[self->PatternID[in_pos][2]] -= self->PatternDiff[in_pos][2] + self->PatternDiff[in_pos][2];
self->Pattern[self->PatternID[in_pos][3]] -= self->PatternDiff[in_pos][3] + self->PatternDiff[in_pos][3];
self->Pattern[self->PatternID[in_pos][4]] -= self->PatternDiff[in_pos][4] + self->PatternDiff[in_pos][4];
self->Pattern[self->PatternID[in_pos][5]] -= self->PatternDiff[in_pos][5] + self->PatternDiff[in_pos][5];
}
次に着手処理を記述します。
パターン更新を行ないながら1方向に石を返す関数Board_FlipLinePattern()は以下の通りです。
Board_FlipLine()と似た処理ですが、石を返すときにBoard_FlipSquareBlack()またはBoard_FlipSquareWhite()を呼び出す点が異なります。
static int Board_FlipLinePattern(Board *self, int in_color, int in_pos, int in_dir)
{
int result = 0;
int op = OPPONENT_COLOR(in_color);
int pos;
void (*func_flip)(Board *, int);
if (in_color == BLACK) {
func_flip = Board_FlipSquareBlack;
} else {
func_flip = Board_FlipSquareWhite;
}
pos = in_pos + in_dir;
if (self->Disk[pos] != op) {
return 0;
}
pos += in_dir;
if (self->Disk[pos] == op) {
pos += in_dir;
if (self->Disk[pos] == op) {
pos += in_dir;
if (self->Disk[pos] == op) {
pos += in_dir;
if (self->Disk[pos] == op) {
pos += in_dir;
if (self->Disk[pos] == op) {
pos += in_dir;
if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
func_flip(self, pos);
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
func_flip(self, pos);
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
func_flip(self, pos);
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
func_flip(self, pos);
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
func_flip(self, pos);
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
func_flip(self, pos);
BOARD_STACK_PUSH(self, pos);
return result;
}
パターン更新を伴う着手関数Board_FlipPattern()は以下の通りです。
これもBoard_Flip()と似ていますが、Board_FlipLinePattern()を呼び出す点と、
着手位置に石を置くときにBoard_PutSquareBlack()または()を呼び出す点が異なります。
int Board_FlipPattern(Board *self, int in_color, int in_pos)
{
int result = 0;
if (self->Disk[in_pos] != EMPTY) {
return 0;
}
switch (in_pos) {
case C1:
case C2:
case D1:
case D2:
case E1:
case E2:
case F1:
case F2:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_RIGHT);
break;
case C8:
case C7:
case D8:
case D7:
case E8:
case E7:
case F8:
case F7:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_RIGHT);
break;
case A3:
case A4:
case A5:
case A6:
case B3:
case B4:
case B5:
case B6:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_RIGHT);
break;
case H3:
case H4:
case H5:
case H6:
case G3:
case G4:
case G5:
case G6:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN);
break;
case A1:
case A2:
case B1:
case B2:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_RIGHT);
break;
case A8:
case A7:
case B8:
case B7:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_RIGHT);
break;
case H1:
case H2:
case G1:
case G2:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN);
break;
case H8:
case H7:
case G8:
case G7:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_LEFT);
break;
default:
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_UP_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_RIGHT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_LEFT);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN);
result += Board_FlipLinePattern(self, in_color, in_pos, DIR_DOWN_RIGHT);
break;
}
if (result > 0) {
if (in_color == BLACK) {
Board_PutSquareBlack(self, in_pos);
} else {
Board_PutSquareWhite(self, in_pos);
}
BOARD_STACK_PUSH(self, in_pos);
BOARD_STACK_PUSH(self, OPPONENT_COLOR(in_color));
BOARD_STACK_PUSH(self, result);
self->DiskNum[in_color] += result + 1;
self->DiskNum[OPPONENT_COLOR(in_color)] -= result;
self->DiskNum[EMPTY]--;
}
return result;
}
着手関数の説明をしたので、その次は逆の処理の説明をします。
パターン更新をしながら1手戻す処理Board_UnflipPatternは以下の通りです。
例によってBoard_Unflip()と似ていますがマスの状態を変えるときに対応する関数を呼び出す点が違います。
int Board_UnflipPattern(Board *self)
{
int result;
int i, color;
if (self->Sp <= self->Stack) {
return 0;
}
result = BOARD_STACK_POP(self);
color = BOARD_STACK_POP(self);
if (color == BLACK) {
Board_RemoveSquareWhite(self, BOARD_STACK_POP(self));
for (i = 0; i < result; i++) {
Board_FlipSquareBlack(self, BOARD_STACK_POP(self));
}
} else {
Board_RemoveSquareBlack(self, BOARD_STACK_POP(self));
for (i = 0; i < result; i++) {
Board_FlipSquareWhite(self, BOARD_STACK_POP(self));
}
}
self->DiskNum[color] += result;
self->DiskNum[OPPONENT_COLOR(color)] -= result + 1;
self->DiskNum[EMPTY]++;
return result;
}
Boardクラスの修正の締めくくりとしてパターン取得関数の説明をします。
といってもPatternメンバの参照を行なうだけです。
int Board_Pattern(const Board *self, int in_id)
{
return self->Pattern[in_id];
}
次節では探索と局面評価の修正を行ないます。