前回までで、勝敗判定ができるようにしました。今回は、コンピュータ側の思考ルーチン(コンピュータ側の戦略や方策)をもう少し賢くしていきましょう。
今回のゲームでは、コンピュータ側は後攻です。後攻は言わば守りになるため、先攻とはちょっと違った戦略をとらなければいけません。仮に以下の戦略をとることにしましょう。
- turn 1:角が取られたら真ん中をとる。それ以外の場合は角をとる
- turn 3以降:自分がリーチの場合優先してリーチのマスをとる。プレイヤーがリーチの場合、リーチを防ぐ。それ以外はランダム
必ずしも turn の値によって場合分けする必要はないのですが、このようにすることで無駄な計算を省くことができます。例えばturn が1 のときは、プレイヤーもコンピュータもリーチになることはないので、その計算をする必要はありません。では、上記の流れでコードにしてみましょう。
まず、リーかどうかを判定する関数 reach() を作成します。今回の関数は、リーチであれば True、そうでなければ False を返す Boolean型とします。こうすることで、「もしリーチだったら」ということを if (reach) と端的に表すことができます。リーチの場合は True、そうでない場合は False になるので、このように if 文の条件式として使用することができます。またこの関数では、リーチの場合にリーチになっているマスの X, Y の値も書き換えておくこととします。reachタブを作成して以下のコードを記述します。
boolean reach(){
int line = 1;
// vertical reach
for (X = 0; X < 3; X++){
for (Y = 0; Y < 3; Y++){
line *= map[Y][X];
}
if(line == 9){
for (Y = 0; Y < 3; Y ++){
if(map[Y][X] == 1) return true;
}
} else if(line == 4){
for (Y = 0; Y < 3; Y ++){
if(map[Y][X] == 1) return true;
}
}
}
//horizontal reach
line = 1;
for (Y = 0; Y < 3; Y++){
for (X = 0; X < 3; X++){
line *= map[Y][X];
}
if(line == 9){
for (X = 0; X < 3; X ++){
if(map[Y][X] == 1) return true;
}
} else if (line == 4){
for (X = 0; X < 3; X ++){
if(map[Y][X] == 1) return true;
}
}
}
// cross reach (right-down)
line = map[0][0] * map[1][1] * map[2][2];
if(line == 9){
for(int i = 0; i < 3; i++){
if(map[i][i] == 1) {
X = i;
Y = i;
return true;
}
}
} else if (line == 4){
for(int i = 0; i < 3; i++){
if(map[i][i] == 1) {
X = i;
Y = i;
return true;
}
}
}
// cross reach (right-up)
line = map[2][0] * map[1][1] * map[0][2];
if(line == 9){
for(int i = 0; i < 3; i++){
if(map[2-i][i] == 1) {
X = i;
Y = 2 - i;
return true;
}
}
} else if(line == 4){
for(int i = 0; i < 3; i++){
if(map[2-i][i] == 1) {
X = i;
Y = 2 - i;
return true;
}
}
}
return false;
}
最初のブロック(まとまり)で縦の 3 列を、次のブロックで横 3 列、続いて斜めでリーチになっているか判定しています。リーチになっていれば、そのマスの X, Y を保存して True を return 文で返しています。
続きは次回~