著者:谷 知紘
今回は、C言語を用いて作成した、コンピュータと対戦できるリバーシを紹介します。あまり強くはありませんが、きちんとコンピュータが相手をしてくれます。C99以降の規格に対応するCコンパイラと標準Cライブラリがあれば、環境を問わずに動作するプログラムになっていますので、皆さんもコンパイルして楽しんでください。
シェルスクリプトマガジン Vol.85は以下のリンク先でご購入できます。
図5 盤面の生成用コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//盤面 空白(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()関数のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//指定したマスに石を置けるかどうかを判定する関数 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()関数のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//指定方向に何個の石を挟めるかを調べる関数 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()関数のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//指定したマスに石を配置して、挟んだ石を自分の石にする関数 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()関数のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//コンピュータの手番で呼び出される関数 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()関数のコード
1 2 3 4 5 6 7 8 |
//盤面データをコピーする関数 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()関数のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//総スコアを計算する関数 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; } |