こんにちは!
前回は人間同士で戦えるところまで作ったので、今回は単純思考のコンピュータ(AI)と対戦できるところまでを作りました!

ランダムで駒を置くだけのAIですが(笑)
AIを作った…と聞くと僕がメチャクチャすごい人に聞こえますが、実際の僕はただの素人で、コードの書き方とかすごく汚いです。タイトルに【サンプルコード】ってつけてるのが恥ずかしいくらいなんですよね。
しかし、「コード汚くてもとりあえず動けばいいよ」って人もいると思うので、その方に向けて残します。※動作が変だったりしたら対処するので知らせて下さい。
追加した関数
前回までのコードに新しく↓のコードを追加しました。
AIの手をランダムで生成してくれます。
void tanjunAI() {//単純AIの手を作成してcheck関数に遷移する
int AIteX[20];//適当に20手分格納できる配列を生成
int AIteY[20];
int cnt = 0;//ランダムで生成する数を入れていく
int r;//ランダム
for (int i = 1; i < L; i++) {//置ける場所を探して配列に格納
for (int j = 1; j < L; j++) {
aiueo = 1;//while関数で必要
if (3 == check(j, i)) {
AIteX[cnt] = j;
AIteY[cnt] = i;
cnt++;
}
}
}
srand(time(NULL));//乱数の初期化
r = rand() % cnt; //手を選んでに格納 0~N個
aiueo = 0;//while関数で必要
Sleep(3*1000);
check(AIteX[r],AIteY[r]);
}
コマンドプロントで実行するとこんな感じ

メニュー画面から「2」を入力してゲームスタート
先手か後手を決めて遊ぶことができます。
全体のコード
先に次回予告!
次回は盤面に評価値を付けて、強い手(良い手)を指せるAIを頑張って作ります。
コピペだとなぜがエラーが発生するそうです。。。
ファイルをアップロードしたので、ダウンロードして使ってください。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <time.h>//単純AIで手を選ぶときに使う
#include <stdlib.h>//単純AIで使う
#include <windows.h>//sleep関数を使うために必要。Macだと使えないので450行目あたりにあるSleepの行とこのwindows.hを消してください。
#define L 9 //盤の広さ
#define EMPTY 0//何も置いてない場所を示す
#define BLACK -2//1だとバグが出る
#define WHITE -1
void tanjunAI();//単純AI
void game();//手を入力して check関数に遷移
void menu();//人間同士で戦うかAIと戦うか選択する関数
int AIturn = 0;
int whichAI;
int AIx, AIy;//AIのx座標とy座標
int turn = BLACK;
int I_stone = BLACK;//ひっくり返す処理で使う。turn_change()でWHITEと入れ替わる
int You_stone = WHITE;//ひっくり返す処理で使う。turn_change()でBLACKと入れ替わる
int board[L][L];//盤を表示するときに使う
int board_next[L][L];//駒をひっくり返すときに使う。boardのコピー
int cnt;//駒をひっくり返す時に使う
int sum;//駒が置けるかチェックするときに使う
int p;//while関数で駒が置けるかチェックするときに使う
int flag1 = 1;//単純AIの関数とall_check関数で使用
int angle_x[] = { 0,1,1,1,0,-1,-1,-1};//八方面を表す
int angle_y[] = { -1,-1,0,1,1,1,0,-1};//八方面を表す
void shokika() {//盤面リセット
for (int i = 0; i < L; i++) {
for (int j = 0; j < L; j++) {
board[i][j] = EMPTY;
}
}
board[4][4] = WHITE;
board[4][5] = BLACK;
board[5][4] = BLACK;
board[5][5] = WHITE;
}
void turn_change() {//手番の変更
if (turn == WHITE) {
turn = BLACK;
I_stone = BLACK;
You_stone = WHITE;
}
else {
turn = WHITE;
I_stone = WHITE;
You_stone = BLACK;
}
}
void display() {//盤面表示・更新
for (int i = 0; i < L; i++) {
for (int j = 0; j < L; j++) { switch (board[i][j]) { case WHITE: printf(" ●"); break; case BLACK: printf(" 〇"); break; default: if (i==0||j==0) { if (j == 0) { board[i][j]=i;//縦の数字を代入 } if (i == 0) { switch (j){ case 1: printf(" 1 2 3 4 5 6 7 8");//横の数字を表示 break; } } else{ printf(" %d", board[i][j]);//縦の数字を表示 } break; } else { printf(" *"); } } if (j == L - 1) {//改行 printf("\n"); } } } game(); }
int rolling(int i,int w_x,int w_y,int *flag){//石をひっくり返す関数
do { if (i == 0) {//上方向の時
if (board_next[w_y - cnt][w_x] == You_stone) {
board_next[w_y - cnt][w_x] = I_stone;
cnt++; flag[0] = 1;
if (board_next[w_y - cnt][w_x] == EMPTY || w_y - cnt == 1 && board_next[w_y - cnt][w_x] == You_stone || w_y - cnt == 0) {
int a = cnt - 1; flag[0] = 0;
do { board_next[w_y - a][w_x] = You_stone; a--; } while (a >= 1);
}
}
else {
break;
}
}
else if (i == 1) {//右上
if (board_next[w_y - cnt][w_x + cnt] == You_stone) {
board_next[w_y - cnt][w_x + cnt] = I_stone;
cnt++;
flag[1] = 1;
if (board_next[w_y - cnt][w_x + cnt] == EMPTY || w_y - cnt == 1 && board_next[w_y - cnt][w_x + cnt] == You_stone || w_x + cnt == 8 && board_next[w_y - cnt][w_x + cnt] == You_stone || w_y - cnt == 0 || w_x + cnt == 9) {
int a = cnt - 1;
flag[1] = 0;
do {
board_next[w_y - a][w_x + a] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
else if (i == 2) {//右
if (board_next[w_y][w_x + cnt] == You_stone) {
board_next[w_y][w_x + cnt] = I_stone;
cnt++;
flag[2] = 1;
if (board_next[w_y][w_x + cnt] == EMPTY || w_x + cnt == 8 && board_next[w_y][w_x + cnt] == You_stone || w_x + cnt == 9) {
int a = cnt - 1;
flag[2] = 0;
do {
board_next[w_y][w_x + a] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
else if (i == 3) {//右下
if (board_next[w_y + cnt][w_x + cnt] == You_stone) {
board_next[w_y + cnt][w_x + cnt] = I_stone;
cnt++;
flag[3] = 1;
if (board_next[w_y + cnt][w_x + cnt] == EMPTY || w_y + cnt == 8 && board_next[w_y + cnt][w_x + cnt] == You_stone || w_x + cnt == 8 && board_next[w_y + cnt][w_x + cnt] == You_stone || w_y + cnt == 9 || w_x + cnt == 9) {
int a = cnt - 1;
flag[3] = 0;
do {
board_next[w_y + a][w_x + a] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
else if (i == 4) {//下
if (board_next[w_y + cnt][w_x] == You_stone) {
board_next[w_y + cnt][w_x] = I_stone;
cnt++;
flag[4] = 1;
if (board_next[w_y + cnt][w_x] == EMPTY || w_y + cnt == 8 && board_next[w_y + cnt][w_x] == You_stone || w_y + cnt == 9) {
int a = cnt - 1;
flag[4] = 0;
do {
board_next[w_y + a][w_x] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
else if (i == 5) {//左下
if (board_next[w_y + cnt][w_x - cnt] == You_stone) {
board_next[w_y + cnt][w_x - cnt] = I_stone;
cnt++;
flag[5] = 1;
if (board_next[w_y + cnt][w_x - cnt] == EMPTY || w_y + cnt == 8 && board_next[w_y + cnt][w_x - cnt] == You_stone || w_x - cnt == 1 && board_next[w_y + cnt][w_x - cnt] == You_stone || w_y + cnt == 9 || w_x - cnt == 0) {
int a = cnt - 1;
flag[5] = 0;
do {
board_next[w_y + a][w_x - a] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
else if (i == 6) {//左
if (board_next[w_y][w_x - cnt] == You_stone) {
board_next[w_y][w_x - cnt] = I_stone;
cnt++;
flag[6] = 1;
if (board_next[w_y][w_x - cnt] == EMPTY || w_x - cnt == 1 && board_next[w_y][w_x - cnt] == You_stone || w_x - cnt == 0) {
int a = cnt - 1;
flag[6] = 0;
do {
board_next[w_y][w_x - a] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
else if (i == 7) {//左上
if (board_next[w_y - cnt][w_x - cnt] == You_stone) {
board_next[w_y - cnt][w_x - cnt] = I_stone;
cnt++;
flag[7] = 1;
if (board_next[w_y - cnt][w_x - cnt] == EMPTY || w_y - cnt == 1 && board_next[w_y - cnt][w_x - cnt] == You_stone || w_x - cnt == 1 && board_next[w_y - cnt][w_x - cnt] == You_stone || w_y - cnt == 0 || w_x - cnt == 0) {
int a = cnt - 1;
flag[7] = 0;
do {
board_next[w_y - a][w_x - a] = You_stone;
a--;
} while (a >= 1);
}
}
else {
break;
}
}
if (flag[i] == 0) {
break;
}
} while (1);
if (cnt == 1) { board_next[w_y][w_x] = EMPTY; return 2; }
p = 1;
}
int check(int w_x, int w_y) {//石を置けるかチェック
if (EMPTY != board[w_y][w_x]) {
return 0;
}
int flag[8] = { 0,0,0,0,0,0,0,0 };
memcpy((void*)board_next, (void*)board, sizeof(board));
board_next[w_y][w_x] = I_stone;
for (int i = 0; i < 8; i++) {
cnt = 1;
switch (board[w_y + angle_y[i]][w_x + angle_x[i]]) {//置きたい場所の周りに敵の石があるか確認
case BLACK:
if (turn == BLACK) { break; }//黒のターンなら処理しない
rolling(i, w_x, w_y, flag);
break;
case WHITE:
if (turn == WHITE) { break; }
rolling(i, w_x, w_y, flag);
break;
default:
break;
}
}
if (p == EMPTY) {
board_next[w_y][w_x] = EMPTY;
return 2;
}
for (int i = 0; i < 8; i++) {
sum += flag[i];
}
if (sum == EMPTY) {
board_next[w_y][w_x] = EMPTY;
return 2;
}
sum = EMPTY;
if (flag1 == 1) { flag1 = 0; return 3; }//all_check中なのでここで終了
memcpy((void*)board, (void*)board_next, sizeof(board_next));
turn_change();
if(whichAI == 2){AIturn *= -1;}//AIのターンを変更
p = 0;
display();//再描画
return 3;
}
void finish() {
int cntb = 0, cntw = 0;
for (int i = 1; i < L; i++) {
for (int j = 1; j < L; ++j) { switch (board[i][j]) { case BLACK: cntb++; break; case WHITE: cntw++; break; default: break; } } } printf("置ける場所が無くなったのでゲーム終了です。\n結果\n黒 %d個\n白 %d個\n", cntb, cntw); if (cntb > cntw) {
printf("黒の勝ち\n\n");
}
else if (cntw > cntb) {
printf("白の勝ち\n\n");
}
else {
printf("引き分け\n\n");
}
menu();
}
void all_check() {
flag1 = 1;
for (int w = 0; w < 2; w++) {//二重パス
for (int i = 1; i < L; i++) {
for (int j = 1; j < L; j++) { if (3 == check(j, i)) { if (w == 0) { return; }else{ printf("どこにも置けないのでパスします。\nもう一度"); return; } } } } turn_change(); } finish(); } void game() {//手を入力させる int x; int y; all_check(); if (AIturn == 1) {//AI対戦用 printf("AIの手番です。\n"); tanjunAI(); } if (turn == BLACK) { printf("黒の手番です。手を入力してください。\nXを入力\n"); } else { printf("白の手番です。手を入力してください。\nXを入力\n"); } while (1) { if (scanf("%d", &x) >= 1) {//数値だけを入力させる
break;
}
scanf("%*s");
printf("もう一度入力してください。\n");
}
printf("Yを入力");
while (1) {
if (scanf("%d", &y) >= 1) {//数値だけを入力させる
break;
}
scanf("%*s");
printf("もう一度入力してください。\n");
}
if (1 != check(x, y)) {//while関数の変数pと繋がってる
printf("そこには置けません。\n");
game();
}
}
void menu() {//メニューを表示し、選択したゲームモードで遊べるようにする関数
int start = 0;
whichAI = 0;
AIturn = 0;
whichAI = 0;
printf("Main menu:\n1)人間vs人間\n2)人間vs単純AI\nQ)Quit program\nPlease enter your selection:");
while(1) {
if (scanf("%d", &start) != 1) {//数値だけを入力させる
scanf("%*s");
printf("もう一度入力してください。\n");
continue;
}
if (start == 1 || start == 2) {
break;
}
printf("もう一度入力してください。\n");
}
whichAI = start;
switch (start) {
case 1:
AIturn = -1;
shokika();
display();
game();
break;
case 2:
printf("先手で指す:1を入力\n後手で指す:2を入力\n");
while (1) {
scanf("%d", &start);
if(start < 1 && start >8) {//数値だけを入力させる
scanf("%*s");
printf("もう一度入力してください。\n");
continue;
}
if (start == 2) {//後手でスタート
AIturn = 1;
}else{ AIturn = -1; }
shokika();
display();
game();
break;
}
default:
printf("もう一度入力してください。\n");
menu();
}
}
void tanjunAI() {//単純AIの手を作成してcheck関数に遷移する
int AIteX[20];//適当に20手分格納できる配列を生成
int AIteY[20];
int cnt = 0;//ランダムで生成する数を入れていく
int r;//ランダム
for (int i = 1; i < L; i++) {//置ける場所を探して配列に格納
for (int j = 1; j < L; j++) {
flag1 = 1;//while関数で必要
if (3 == check(j, i)) {
AIteX[cnt] = j;
AIteY[cnt] = i;
cnt++;
}
}
}
srand(time(NULL));//乱数の初期化
r = rand() % cnt; //手を選んでに格納 0~N個
flag1 = 0;//while関数で必要
Sleep(2*1000);//2秒停止させてから表示
check(AIteX[r],AIteY[r]);//選んだ手を入力
}
int main(int argc, char* argv[])
{
menu();
return 0;
}
ではまた次回お会いしましょう!



コメント