| 4.2 着手の高速化 |
本節では着手処理を高速化します。
着手処理も頻繁に呼ばれるので、着手処理の高速化によって全体の高速化に貢献できます。
まずは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;
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 ++;
self->Disk[pos] = in_color;
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
self->Disk[pos] = in_color;
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
self->Disk[pos] = in_color;
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
self->Disk[pos] = in_color;
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
self->Disk[pos] = in_color;
BOARD_STACK_PUSH(self, pos);
} else if (self->Disk[pos] != in_color) {
return 0;
}
pos -= in_dir;
result ++;
self->Disk[pos] = in_color;
BOARD_STACK_PUSH(self, pos);
return result;
}
修正前のBoard_FlipLine()ではforループを使用して各マスの状態を調べていました。
このforループはループの最大回数が決まっているので、展開することができます。
展開したものが上のソースコードです。
かなり見にくくなっていますが、修正前と同じ処理を行なっています。
ループの展開を行なうと、ループ変数の増減と比較の処理がなくなります。
for (i = 0; i < 10; i++) { (処理) }
というforループでは、(処理)の部分を10回記述すればi++とiを10と比較する処理がなくなります。
このためわずかですが処理を速くすることができます。
B2に着手することを考えてみましょう。
このとき、石を返すことができるのは右方向、下方向、右下方向の3方向だけです。
Board_Flip()では、全部の方向に対してBoard_FlipLine()を呼び出していますがB2に着手する場合には上記3方向に対して呼び出せば十分です。
呼び出す関数を少なくすることで無駄な処理を減らすことができます。
これをB2だけでなく全てのマスに対して適用してみましょう。
int Board_Flip(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_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);
break;
case C8:
case C7:
case D8:
case D7:
case E8:
case E7:
case F8:
case F7:
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);
break;
case A3:
case A4:
case A5:
case A6:
case B3:
case B4:
case B5:
case B6:
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_RIGHT);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN);
result += Board_FlipLine(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_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_LEFT);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN_LEFT);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN);
break;
case A1:
case A2:
case B1:
case B2:
result += Board_FlipLine(self, in_color, in_pos, DIR_RIGHT);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN_RIGHT);
break;
case A8:
case A7:
case B8:
case B7:
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_RIGHT);
break;
case H1:
case H2:
case G1:
case G2:
result += Board_FlipLine(self, in_color, in_pos, DIR_LEFT);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN_LEFT);
result += Board_FlipLine(self, in_color, in_pos, DIR_DOWN);
break;
case H8:
case H7:
case G8:
case G7:
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_LEFT);
break;
default:
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);
break;
}
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);
self->DiskNum[in_color] += result + 1;
self->DiskNum[OPPONENT_COLOR(in_color)] -= result;
self->DiskNum[EMPTY]--;
}
return result;
}
ここには掲載しませんが、Board_CountFlips()に対しても同様の修正を行ないます。
今度はどの程度速くなったでしょうか。
筆者の環境では10%から20%速くなりました。
Boardの改善は本節までです。
次節は探索の改善を行ないます。