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); }
次節では着手時のパターン更新を行ないます。