| 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から値を読み込むためのマクロです。