| 5.2 パターンの初期化 |
本節ではBoardクラスでのパターン初期化について説明します。
"board.c"の修正を行ないます。
まず最初に1マスに関わるパターンの最大数を定義します。
これは、1マスの状態が変わったときに最大何個のパターンが更新されるのかという値です。
B2、B7、G2、G7の状態が変わったときに6個のパターンが更新され、これが最大値です。
#define NUM_PATTERN_DIFF 6
次にBoard構造体のメンバ変数を追加します。
各変数の意味は以下のようになっています。
Pattern : パターンの状態
PatternID : あるマスの状態が変わったときに更新するパターンのID
PatternDiff : あるマスの状態が変わったときに更新するパターンの状態の差分
struct _Board
{
int Disk[NUM_DISK];
int Stack[NUM_STACK];
int *Sp;
int DiskNum[3];
int Pattern[NUM_PATTERN_ID];
int PatternID[NUM_DISK][NUM_PATTERN_DIFF];
int PatternDiff[NUM_DISK][NUM_PATTERN_DIFF];
};
メンバ変数を追加したので、それぞれを初期化する処理が必要です。
まずはPatternIDメンバとPatternDiffメンバの初期化を行ないます。
最初に、指定されたパターンに対してPatternIDとPatternDiffの設定を行なう関数Board_AddPattern()を記述します。
この関数は、例えば「A4が空きから黒になったらPATTERN_ID_LINE4_1(A4-H4のパターン)を1増やす」という値を設定します。
この例ではPatternIDにPATTERN_ID_LINE4_1を代入し、PatternDiffに1を代入します。
引数は以下の通りです。
self : Boardクラスへのポインタ
in_id : パターンID
in_pos_list : パターンを構成するマスのリスト
in_num : パターンを構成するマスの数
static void Board_AddPattern(Board *self, int in_id, const int *in_pos_list, int in_num)
{
int i, j, n;
n = 1;
for (i = 0; i < in_num; i++) {
for (j = 0; self->PatternDiff[in_pos_list[i]][j] != 0; j++) {
}
self->PatternID[in_pos_list[i]][j] = in_id;
self->PatternDiff[in_pos_list[i]][j] = n;
n *= 3;
}
}
次に、全パターンに対してPatternIDとPatternDiffの設定を行なう関数Board_InitializePatternDiff()を記述します。
最初にPatternIDとPatternDiffを0で初期化し、次に各パターンに対してBoard_AddPattern()を呼び出します。
static void Board_InitializePatternDiff(Board *self)
{
int i, j;
int pattern_list[][9] = {
{ A4, B4, C4, D4, E4, F4, G4, H4, -1 },
{ A5, B5, C5, D5, E5, F5, G5, H5, -1 },
{ D1, D2, D3, D4, D5, D6, D7, D8, -1 },
{ E1, E2, E3, E4, E5, E6, E7, E8, -1 },
{ A3, B3, C3, D3, E3, F3, G3, H3, -1 },
{ A6, B6, C6, D6, E6, F6, G6, H6, -1 },
{ C1, C2, C3, C4, C5, C6, C7, C8, -1 },
{ F1, F2, F3, F4, F5, F6, F7, F8, -1 },
{ A2, B2, C2, D2, E2, F2, G2, H2, -1 },
{ A7, B7, C7, D7, E7, F7, G7, H7, -1 },
{ B1, B2, B3, B4, B5, B6, B7, B8, -1 },
{ G1, G2, G3, G4, G5, G6, G7, G8, -1 },
{ A1, B2, C3, D4, E5, F6, G7, H8, -1 },
{ A8, B7, C6, D5, E4, F3, G2, H1, -1 },
{ A2, B3, C4, D5, E6, F7, G8, -1 },
{ B1, C2, D3, E4, F5, G6, H7, -1 },
{ A7, B6, C5, D4, E3, F2, G1, -1 },
{ B8, C7, D6, E5, F4, G3, H2, -1 },
{ A3, B4, C5, D6, E7, F8, -1 },
{ C1, D2, E3, F4, G5, H6, -1 },
{ A6, B5, C4, D3, E2, F1, -1 },
{ C8, D7, E6, F5, G4, H3, -1 },
{ A4, B5, C6, D7, E8, -1 },
{ D1, E2, F3, G4, H5, -1 },
{ A5, B4, C3, D2, E1, -1 },
{ D8, E7, F6, G5, H4, -1 },
{ A5, B6, C7, D8, -1 },
{ E1, F2, G3, H4, -1 },
{ A4, B3, C2, D1, -1 },
{ E8, F7, G6, H5, -1 },
{ B2, G1, F1, E1, D1, C1, B1, A1, -1 },
{ G2, B1, C1, D1, E1, F1, G1, H1, -1 },
{ B7, G8, F8, E8, D8, C8, B8, A8, -1 },
{ G7, B8, C8, D8, E8, F8, G8, H8, -1 },
{ B2, A7, A6, A5, A4, A3, A2, A1, -1 },
{ B7, A2, A3, A4, A5, A6, A7, A8, -1 },
{ G2, H7, H6, H5, H4, H3, H2, H1, -1 },
{ G7, H2, H3, H4, H5, H6, H7, H8, -1 },
{ B3, A3, C2, B2, A2, C1, B1, A1, -1 },
{ G3, H3, F2, G2, H2, F1, G1, H1, -1 },
{ B6, A6, C7, B7, A7, C8, B8, A8, -1 },
{ G6, H6, F7, G7, H7, F8, G8, H8, -1 },
{ -1 }
};
for (i = 0; i < NUM_DISK; i++) {
for (j = 0; j < NUM_PATTERN_DIFF; j++) {
self->PatternID[i][j] = 0;
self->PatternDiff[i][j] = 0;
}
}
for (i = 0; pattern_list[i][0] >= 0; i++) {
for (j = 0; pattern_list[i][j] >= 0; j++) {}
Board_AddPattern(self, i, pattern_list[i], j);
}
}
Board_InitializePatternDiff()はBoardの生成時に呼び出します。
Board *Board_New(void)
{
Board *self;
self = malloc(sizeof(Board));
if (self) {
Board_InitializePatternDiff(self);
Board_Clear(self);
}
return self;
}
メンバ変数Patternを初期化するBoard_InitializePattern()は以下のようになっています。
void Board_InitializePattern(Board *self)
{
int i;
for (i = 0; i < NUM_PATTERN_ID; i++) {
self->Pattern[i] = 0;
}
for (i = 0; i < NUM_DISK; i++) {
if (self->Disk[i] == BLACK) {
Board_PutSquareBlack(self, i);
} else if (self->Disk[i] == WHITE) {
Board_PutSquareWhite(self, i);
}
}
}
まず最初にPatternの内容を0で初期化します。
次に各マスの状態に応じてBoard_PutSquareBlack()またはBoard_PutSquareWhite()を呼び出します。
これらの関数は以下のようになっています。
static void Board_PutSquareBlack(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_PutSquareWhite(Board *self, int in_pos)
{
self->Disk[in_pos] = WHITE;
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];
}
指定されたマスに関連するパターンの状態をPatternDiff分(白石を置く場合にはその2倍)増やしています。
同じような処理を6回行なっていますが、これは関連するパターンが最大6個あるためです。
もし関連するパターンの数が6個より少ない場合、例えば4個しかない場合には
self->PatternDiff[in_pos][4]とself->PatternDiff[in_pos][5]がどちらも0になるため、4個のパターンだけが更新されます。
以下の関数でパターンの初期化を行ないます。
void Board_Clear(Board *self)
{
int i, j;
for (i = 0; i < NUM_DISK; i++) {
self->Disk[i] = WALL;
}
for (i = 0; i < BOARD_SIZE; i++) {
for (j = 0; j < BOARD_SIZE; j++) {
self->Disk[Board_Pos(i, j)] = EMPTY;
}
}
self->Disk[E4] = BLACK;
self->Disk[D5] = BLACK;
self->Disk[D4] = WHITE;
self->Disk[E5] = WHITE;
self->Sp = self->Stack;
self->DiskNum[BLACK] = 2;
self->DiskNum[WHITE] = 2;
self->DiskNum[EMPTY] = BOARD_SIZE * BOARD_SIZE - 4;
Board_InitializePattern(self);
}
void Board_Reverse(Board *self)
{
int pos;
int *p;
int n;
for (pos = 0; pos < NUM_DISK; pos++) {
if (self->Disk[pos] == BLACK) {
self->Disk[pos] = WHITE;
self->DiskNum[BLACK]--;
self->DiskNum[WHITE]++;
} else if (self->Disk[pos] == WHITE) {
self->Disk[pos] = BLACK;
self->DiskNum[WHITE]--;
self->DiskNum[BLACK]++;
}
}
p = self->Sp;
for (p = self->Sp; p > self->Stack;) {
p--;
n = *p;
p--;
*p = OPPONENT_COLOR(*p);
p -= n + 1;
}
Board_InitializePattern(self);
}
次節では着手時のパターン更新を行ないます。