1.3 石を返す処理 |
本節では石を返す処理と、返した石を戻す処理について説明します。
後述しますが、石を返す関数Board_Flip()は1方向の石を返す関数を全方向に対して呼び出します。
まずはこの1方向の石を返す関数Board_FlipLine()を見てみましょう。
static int Board_FlipLine(Board *self, int in_color, int in_pos, int in_dir) { int result = 0; int op = OPPONENT_COLOR(in_color); int pos; for (pos = in_pos + in_dir; self->Disk[pos] == op; pos += in_dir) {} if (self->Disk[pos] == in_color) { for (pos -= in_dir; self->Disk[pos] == op; pos -= in_dir) { result++; self->Disk[pos] = in_color; BOARD_STACK_PUSH(self, pos); } } return result; }
1行目のOPPONENT_COLOR()は、指定した色と逆の色(黒なら白、白なら黒)を返すマクロです。
以下はin_colorがBLACKであったと仮定して話を進めます。
in_colorがWHITEであったとしても同様の処理になります。
最初のforループでは、着手位置in_posからin_dir方向に移動を行います。
移動先のマスの状態が白石でなくなるまで移動します。
次のif文では、移動先のマスの状態が黒石かどうか調べます。
黒石でなければ挟んだことにならないので、0を返して関数を終了します。
移動先が黒石の場合には、次のforループで逆方向の移動を行い各マスに黒石を置いていきます。
同時に返した石の数を数え(result++)、Stackに返した石の位置を書き込んでいきます。
BOARD_STACK_PUSH()はStackに書き込むためのマクロです。
それでは石を返す関数Board_Flip()を見てみましょう。
int Board_Flip(Board *self, int in_color, int in_pos) { int result = 0; if (self->Disk[in_pos] != EMPTY) { return 0; } result += Board_FlipLine(self, in_color, in_pos, DIR_UP_LEFT); result += Board_FlipLine(self, in_color, in_pos, DIR_UP); result += Board_FlipLine(self, in_color, in_pos, DIR_UP_RIGHT); result += Board_FlipLine(self, in_color, in_pos, DIR_LEFT); result += Board_FlipLine(self, in_color, in_pos, DIR_RIGHT); result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN_LEFT); result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN); result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN_RIGHT); if (result > 0) { self->Disk[in_pos] = in_color; BOARD_STACK_PUSH(self, in_pos); BOARD_STACK_PUSH(self, OPPONENT_COLOR(in_color)); BOARD_STACK_PUSH(self, result); } return result; }
まずはじめに、in_posで指定されたマスの状態が空きでなければ、0を返します。
空きであれば、全8方向に対して石を返していきます。
1つ以上の方向に石を返すことができたら(result > 0の場合)、着手位置に自分の石を置き、
着手位置、相手の色、返した石の数をStackに書き込みます。
返した石を戻す処理はBoard_Unflip()に記述してあります。
int Board_Unflip(Board *self) { int result; int i, color; if (self->Sp <= self->Stack) { return 0; } result = BOARD_STACK_POP(self); color = BOARD_STACK_POP(self); self->Disk[BOARD_STACK_POP(self)] = EMPTY; for (i = 0; i < result; i++) { self->Disk[BOARD_STACK_POP(self)] = color; } return result; }
まず、SpがStackの最初の位置にあったら0を返します。
SpがStackの最初の位置ということは、1度も着手していないことを意味するからです。
次に、Stackから、返した石の数、相手の色、着手位置を読み込みます。
そして返した石の数だけ石の位置を読み込み、その石を反転させます。
BOARD_STACK_POP()はStackから値を読み込むためのマクロです。