はじめに
前回の記事で標準入出力のオセロプログラムを公開しましたが、フォルダの整理をしていたら出てきただけで全然覚えていなかったので、プログラムを読んでいたらAIの関数がサクッと作れるかも?と思ったので作ってみました。
ちなみに、全く強くないです。
簡単な説明
このAIは、予め盤面の各マス目に評価値を割り振っておき、次の手を置いたときに最も評価値の合計が大きくなるように配置します。
ほとんどの部分で元のプログラムの関数をそのまま流用しているので、詳しくは前回のプログラムを参照してください。
ソースコード
////////////////////////////////////////////////// //静的評価AI(サンプル) ////////////////////////////////////////////////// //盤面評価値 int val[8][8] = { {170, -20, 20, 5, 5, 20, -20, 170}, {-20, -40, -5, -5, -5, -5, -40, -20}, {20, -5, 15, 3, 3, 15, -5, 20}, {5, -5, 3, 3, 3, 3, -5, 5}, {5, -5, 3, 3, 3, 3, -5, 5}, {20, -5, 15, 3, 3, 15, -5, 20}, {-20, -40, -5, -5, -5, -5, -40, -20}, {170, -20, 20, 5, 5, 20, -20, 170} }; //評価用盤面 int val_board[10][10]; //盤面の複製 void copy_board(){ for(int i = 0; i < 10; i++){ for(int j = 0; j < 10; j++){ val_board[i][j] = board[i][j]; } } } //配置した場合どうなるか int if_change(int row,int column,int color){ //全方向にいくつ石を変えられるか調査 for(int i = -1; i < 2; i++){ for(int j = -1; j < 2; j++){ if(pos_dir(row,column,i,j,player)){ //石をひっくり返す int num = pos_dir(row,column,i,j,player) + 1; for(int k = 1; k < num; k++){ val_board[row+(k*i)][column+(k*j)] = player; } } } } //石を追加する val_board[row][column] = player; //合計値 int score = 0; //評価値の合計を全探索 for(int i = 1; i < 9; i++){ for(int j = 1; j < 9; j++){ if(val_board[i][j] == color){ score += val[i-1][j-1]; } } } //返り値は合計値 return score; } //配置 void ai_static(int *row,int *column){ copy_board(); int board_val[3] = {0,0,-10000}; for(int i = 1; i < 9; i++){ for(int j = 1; j < 9; j++){ if(pos_place(i,j,player)){ if(if_change(i,j,player) > board_val[2]){ board_val[0] = i; board_val[1] = j; board_val[2] = if_change(i,j,player); } } } } *row = board_val[0]; *column = board_val[1]; }
プログラムの実行
前回の記事のプログラムの「一手分実行」というコメントアウトがある場所より上にソースコードを貼り付けて「一手分実行」というコメントアウトのすぐ下のdo_round()関数を次のように書き換えてください。
////////////////////////////////////////////////// //一手分実行 ////////////////////////////////////////////////// int do_round(){ int row = 0; int column = 0; //アドレスで座標を取って来る switch(player){ case -1: printf("先手の手番です。\n"); ai_static(&row,&column); break; case 1: printf("後手の手番です。\n"); get_data(&row,&column); break; default : break; } //配置可能であれば配置 if(pos_place(row,column,player)){ printf("%d%dに配置します。\n",row,column); put_board(row,column); return 0; } //配置不可能であればもう一度入力させる printf("%d%dには配置できません。\n",row,column); return do_round(); }
ここでは先手をAIにしましたが、後手をAIに変えても大丈夫です。
最後に
いつか気が向いたらαβ法を使ったプログラムを作ろうかなと思います。
こんな関数作ったったで!という方がいたらコメントにて教えてください。
今回はこの辺で。
コメント