今回の目標
n手先まで読んで打ち返してもらいます。
今までのプログラムのつぎはぎ作っても面白くないので、Cでは似たような関数を二つ作りましたがここでは一つにまとめたいと思います。
プログラムの拡張子が「.c」になってますがProcessingです。
ここから本編
copyb
若干変えました。
n_hand.c
void copyb(int[][] parent, int[][] child){
for (int i = 0; i < SIZE; i++)
for (int j = 0; j < SIZE; j++)
child[i][j] = parent[i][j];
}
draw
draw関数復活です。
理由としては、1handと比べコンピュータの思考時間が長くなるため、Processingの仕様上think関数がmousePressed関数の中にあると盤面表示が遅れるからです。
n_hand.c
void draw(){
if (turn == !player && check_all(!player)){
think(board, 0, !player);
printb();
if (check_all(player)){
turn = !turn;
turn_print("");
}else{
if (check_all(!player)) turn_print("not place. again, ");
else count_last();
}
}
}
mousePressed
いつものやつです。
n_hand.c
void mousePressed(){
int line = (mouseY - COLT / 2) / COLT;
int col = (mouseX - COLT / 2) / COLT;
if (check(board, line, col, player)){
put(board, line, col, player);
printb();
if (check_all(!player)){
turn = !turn;
turn_print("");
}else{
if (check_all(player)) turn_print("not place. again, ");
else count_last();
}
}
}
think
本題の思考部分です。
といっても結局、昔のput関数とboard_add関数を無理やり一つの関数にまとめる形になりました。
やっていることとしてはC言語の時と似ていて以下の通りです。
- まず、コンピュータのターンで、かつコンピュータに置ける場所があるときのみこの関数が呼ばれる(think関数が呼ばれる条件であり、この関数の外でその判定を行う)。
- もし現在の思考回数(read_num)が指定の回数(READ_NUM)に達したらその時のスコアを返す。
- そうでなかった場合、置ける場所を探す。
- 見つけたら、think関数を再起呼び出ししてスコアを受け取る
- この関数が一回目の呼び出しの場合、スコアが最も高くなる場所を探す(最大スコアになる場所が複数ある場合はあとでランダムで選ぶ)。
- 一回目以外の呼び出しの場合、スコアを加算していく。
- この関数が一回目の呼び出しなら、最大スコアが得られる場所に駒を置く(最大スコアになる場所が複数ある場合はランダムで選ぶ)。
- 一回目以外の呼び出しの場合、
- 置ける箇所を複数見つけた際は平均スコアを返す。
- 置ける場所がなかった場合はその時のスコアを返す。
n_hand.c
int think(int[][] now, int read_num, boolean now_turn){
if (read_num == READ_NUM) return count(now);
int i, j, num = 0;
int score, max_score = - SIZE * SIZE, sum_score = 0;
int[] line = new int[SIZE << 1], col = new int[SIZE << 1];
int[][] board_leaf = new int[SIZE][SIZE];
for (i = 0; i < SIZE; i++){
for (j = 0; j < SIZE; j++){
if (check(now, i, j, now_turn)){
copyb(now, board_leaf);
put(board_leaf, i, j, now_turn);
score = think(board_leaf, read_num + 1, !now_turn);
if (read_num == 0){
if (score > max_score){
num = 0;
line[0] = i;
col[0] = j;
max_score = score;
}else if (score == max_score){
num++;
line[num] = i;
col[num] = j;
}
}else{
sum_score += score;
num++;
}
}
}
}
if (read_num == 0){
if (num != 0) {
num = int(random(num + 1));
line[0] = line[num];
col[0] = col[num];
}
put(board, line[0], col[0], !player);
return 0;
}else{
if (num != 0) return sum_score / num;
else return count(board_leaf);
}
}
フルバージョン
実際にやってみた
思っていたほど強くはなかった。
次回は
DeepLearningの勉強を始めたので、(挫折していなければ)AIが打ち返してくるプログラムを作ります。
(追記) まずPythonで普通にオセロを作りました。