こんにちは!
前回は人間同士で戦えるところまで作ったので、今回は単純思考のコンピュータ(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; }
ではまた次回お会いしましょう!
コメント