著者:谷 知紘
今回は、C言語を用いて作成した、コンピュータと対戦できるリバーシを紹介します。あまり強くはありませんが、きちんとコンピュータが相手をしてくれます。C99以降の規格に対応するCコンパイラと標準Cライブラリがあれば、環境を問わずに動作するプログラムになっていますので、皆さんもコンパイルして楽しんでください。
シェルスクリプトマガジン Vol.85は以下のリンク先でご購入できます。![]()
![]()
図5 盤面の生成用コード
//盤面 空白(0) 黒(-1) 白(1) 番兵(2)
int board[10][10] = {0};
//スコアを格納する配列
int weightdata[10][10] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 30,-12, 0, -1, -1, 0,-12, 30, 0},
{0,-12,-15, -3, -3, -3, -3,-15,-12, 0},
{0, 0, -3, 0, -1, -1, 0, -3, 0, 0},
{0, -1, -3, -1, -1, -1, -1, -3, -1, 0},
{0, -1, -3, -1, -1, -1, -1, -3, -1, 0},
{0, 0, -3, 0, -1, -1, 0, -3, 0, 0},
{0,-12,-15, -3, -3, -3, -3,-15,-12, 0},
{0, 30,-12, 0, -1, -1, 0,-12, 30, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
//盤面の生成
void make_board(){
//番兵
for(int i = 0; i < 10; i++){
board[0][i] = 2;
board[9][i] = 2;
board[i][0] = 2;
board[i][9] = 2;
}
//初期配置する石
board[4][4] = 1;
board[5][5] = 1;
board[4][5] = -1;
board[5][4] = -1;
}
図6 check_plc()関数のコード
//指定したマスに石を置けるかどうかを判定する関数
bool check_plc(int i, int j, int now_board[10][10]){
//マスが空かどうか
if(board[i][j] == 0){
//全方向を探索
for(int dir_i = -1; dir_i < 2; dir_i++){
for(int dir_j = -1; dir_j < 2; dir_j++){
if(check_dir(i,j,dir_i,dir_j,now_board)){
//配置可能であればtrueを返す
return true;
}
}
}
}
return false;
}
図8 check_dir()関数のコード
//指定方向に何個の石を挟めるかを調べる関数
int check_dir(int i, int j,
int dir_i, int dir_j,
int now_board[10][10]){
//指定方向に相手の石がある場合は次のマスを探索
int times = 1;
while(now_board[i+dir_i*times][j+dir_j*times] == player*-1){
times++;
}
//指定方向の最後に自分の石がある場合
if(now_board[i+dir_i*times][j+dir_j*times] == player){
//指定方向に相手の石が何個あるかを返す
return times-1;
}
//指定方向の最後に自分の石がなければ0を返す
return 0;
}
図9 place_stn()関数のコード
//指定したマスに石を配置して、挟んだ石を自分の石にする関数
void place_stn(int i, int j, int now_board[10][10]){
//全方向を調査
for(int dir_i = -1; dir_i < 2; dir_i++){
for(int dir_j = -1; dir_j < 2; dir_j++){
//挟んだ石の数
int change_num = check_dir(i,j,dir_i,dir_j,now_board);
//挟んだ石の数だけ自分の石に変更
for(int k = 1; k < change_num+1; k++){
now_board[i+dir_i*k][j+dir_j*k] = player;
}
}
}
//指定したマスに自分の石を配置
now_board[i][j] = player;
}
図10 think()関数のコード
//コンピュータの手番で呼び出される関数
void think(){
//ハイスコアの初期化
int hightscore = -1000;
int px, py;
for(int y = 0; y < 10; y++){
for(int x = 0; x < 10; x++){
//石を置けない場合はスキップ
if(!check_plc(y, x, board)){
continue;
}
int tmpdata[10][10] = {0};
//盤面データをコピーした仮の盤面を作成
copydata(tmpdata);
//仮の盤面に石を置く
place_stn(y, x, tmpdata);
//総スコアを計算する
int score = calcweight(tmpdata);
//ハイスコアよりも総スコアが良ければ更新する
if(score > hightscore){
hightscore = score;
px = x; py = y;
}
}
}
//総スコアが最大のマスに石を置く
place_stn(py, px, board);
printf("PCは(x , y) = (%d , %d)に置きました\n",
px, py);
}
図11 copydata()関数のコード
//盤面データをコピーする関数
void copydata(int tmpdata[10][10]){
for(int y = 0; y < 10; y++){
for(int x = 0; x < 10; x++){
tmpdata[y][x] = board[y][x];
}
}
}
図12 calcweight()関数のコード
//総スコアを計算する関数
int calcweight(int tmpdata[10][10]){
int score = 0;
for(int y = 0; y < 10; y++){
for(int x = 0; x < 10; x++){
//番兵はスキップ
if(tmpdata[y][x] == 2){
continue;
}
//自分の石がある場所のスコアを足す
if(tmpdata[y][x] == 1){
score += weightdata[y][x];
}
}
}
return score;
}