1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

re:C++でオセロのAIを作る1(超初心者です)

1
Last updated at Posted at 2023-07-21

以前の記事で自作オセロ(人vs人)を投稿して、コメントでアドバイスをいただけたので、改良して再投稿。
<改良点>
・変数名を分かりやすくした
・Bの番専用の関数、Wの番専用の関数があった
→if文を使って一つにまとめた

合計の行数が100行くらい減り、関数の数も減ったのでより分かりやすくなりました。

実はぐちゃぐちゃな方のプログラムを元手に、深層学習ナシでオセロのコツを学ばせただけの、打ち返してくるオセロAIを作ってました。なんと行数800。

今度はこっちを元に作って、より高度なものかつ分かりやすいものに挑戦します。

↓ソースコード↓

オセロ(改良版)
#include <stdio.h>

/*実行する関数(どっちの番か、ボード配列)戻り値→置けたら0,置ける場所がなかったら1*/
int run(char user,char board[12][12]);

/*配置を出力する関数*/
void outputBoard(char board[12][12]);

/*裏返す関数(どっちの番か、ベクトル、初期位置(縦、横)、配列)*/
int revers(char user,int i, int j, int vertical, int horizon, char board[12][12]);

/*まだ打てるか確認する関数*/
int check(char user,char board[12][12]);

/*そこに打てるか確認だけする関数*/
int spe_check(char user,int i, int j, int vertical, int horizon, char board[12][12]);


/*ベクトル(dir_ver,dir_hor)
(-1,-1)(-1,0)(-1,1)
(0,-1)(vertical,horizon)(0,1)
(1,-1)(1,0)(1,1)*/

int main(void) {

	int i, j, cntNoRev;
	int cntB = 0;
	int cntW = 0;
	char user = 'B';
	char partner = 'W';
	char board[12][12];

	/*最初の配置を配列に代入(縦がi)*/
	for (i = 0; i < 12; i++) {
		for (j = 0; j < 12; j++) {
			if ((i == 4 && j == 4) || (i == 5 && j == 5)) {
				board[i][j] = 'B';
				continue;
			}

			if ((i == 4 && j == 5) || (i == 5 && j == 4)) {
				board[i][j] = 'W';
				continue;
			}
			board[i][j] = ':';
		}
	}

	/*配置を出力*/
	outputBoard(board);

	printf("Bが先行です。\n");

	/*----実行-----*/

	while(1){

		/*---------Bの番---------*/
		user = 'B';

		cntNoRev = run(user, board);

		if(cntNoRev==0){
			outputBoard(board);
		}

        cntB = 0;
		cntW = 0;

		/*決着の確認*/
		for (i = 1; i <= 8; i++) {
			for (j = 1; j <= 8; j++) {
				if (board[i][j] == 'B')
					cntB++;
				if (board[i][j] == 'W')
					cntW++;
			}
		}

		if ((cntB + cntW == 64) || cntB == 0 || cntW == 0)
			break;

		cntB = 0;
		cntW = 0;

		/*---------Wの番---------*/
		user = 'W';

		cntNoRev = run(user, board);

		if (cntNoRev == 0){
			outputBoard(board);
		}

        cntB = 0;
		cntW = 0;

		/*決着の確認*/
		for (i = 1; i <= 8; i++) {
			for (j = 1; j <= 8; j++) {
				if (board[i][j] == 'B')
					cntB++;
				if (board[i][j] == 'W')
					cntW++;
			}
		}

		if ((cntB + cntW == 64) || cntB == 0 || cntW == 0)
			break;

		cntB = 0;
		cntW = 0;

	}

	/*勝敗の確認*/

	cntB = 0;
	cntW = 0;

for (i = 1; i <= 8; i++) {
		for (j = 1; j <= 8; j++) {
			if (board[i][j] == 'B')
				cntB++;
			if (board[i][j] == 'W')
				cntW++;
		}
	}

	if (cntB > cntW)
		printf("%d対%dでBの勝ちです", cntB, cntW);
	if (cntB == cntW)
		printf("引き分けです");
	if (cntB < cntW)
		printf("%d対%dでWの勝ちです", cntB, cntW);

	return 0;
}

/*配置を出力する関数*/
void outputBoard(char board[12][12])
{
	int i, j;

	for (i = 1; i <= 8; i++) {
		printf("\t%d", i);
	}
	printf("\n");

	for (i = 1; i <= 8; i++) {
		printf("%d\t", i);
		for (j = 1; j <= 8; j++) {
			printf("%c\t", board[i][j]);
		}
		printf("\n\n");
	}
}

/*実行する関数(どっちの番か、ボード配列)戻り値→置けたら0,置ける場所がなかったら1*/
int run(char user, char board[12][12])
{
	int i, j, horizon, vertical, dir_ver, dir_hor, tmp1, tmp2;
	int cntRev = 0;//revers_to_Aを実行した回数をカウント
	int cntNoPut = 0;//revers_to_Aを実行したけど置けなかった回数をカウント
	int cntNoRev = 0;//どこにも置けない→1
	char partner='W';

	if (user == 'B') {
		partner = 'W';
	}
	else if (user == 'W') {
		partner = 'B';
	}

	while (cntRev == 0 || cntRev == cntNoPut) {

		tmp1 = check(user,board);
		if (tmp1 == 64) {
			printf("%cをどこにも置けません\n",user);
			cntNoRev++;
			break;
		}

		printf("%cの番です。どこに打ちますか?(上の数字が先)\n",user);

		scanf_s("%d", &horizon);
		scanf_s("%d", &vertical);

		j = 0;
		if (board[vertical][horizon] != ':') {
			printf("そこには打てません\n");
			continue;
		}

		if (board[vertical][horizon] == ':') {

			/*置いて裏返す*/
			for (i = vertical - 1; i <= vertical + 1; i++) {
				for (j = horizon - 1; j <= horizon + 1; j++) {
					if (board[i][j] == partner) {
						dir_ver = i - vertical;
						dir_hor = j - horizon;
						tmp2 = revers(user,dir_ver, dir_hor, vertical, horizon, board);
						cntRev++;
						if (tmp2 != 0)
							cntNoPut++;
					}
				}
			}
			
			if (cntRev == 0 || cntRev == cntNoPut) {
				printf("そこには打てません\n");
				board[vertical][horizon] = ':';
			}
		}
	}

	return cntNoRev;
}


/*裏返す関数(ベクトル、初期位置(縦、横)、配列),裏返せた→0、裏返せない→1*/
int revers(char user,int dir_ver, int dir_hor, int vertical, int horizon, char board[12][12])
{
	int move = 1;
	int i, tmp_hor, tmp_ver;
	tmp_hor = horizon;
	tmp_ver = vertical;
	int isReversed = 0;
	char partner='W';

	if (user == 'B') {
		partner = 'W';
	}
	else if (user == 'W') {
		partner = 'B';
	}

	board[vertical][horizon] = user;

	while (board[tmp_ver + dir_ver][tmp_hor + dir_hor] == partner) {


		if (board[vertical + dir_ver * 2][horizon + dir_hor* 2] == ':') {
			isReversed++;
			break;
		}

		if (board[vertical + dir_ver * 2][horizon + dir_hor * 2] == partner) {
			horizon += dir_hor;
			vertical += dir_ver;
			move++;
		}

		if (board[vertical + dir_ver * 2][horizon + dir_hor * 2] == user) {

			for (i = 0; i <= move; i++) {

				if (dir_ver != 0 && dir_hor != 0)
					board[vertical + dir_ver - dir_ver * i][horizon + dir_hor - dir_hor * i] = user;

				if (dir_ver == 0)
					board[vertical][horizon + dir_hor- dir_hor * i] = user;

				if (dir_hor == 0)
					board[vertical + dir_ver - dir_ver * i][horizon] = user;

			}

		}

	}

	return isReversed;

}


/*まだ打てるか確認する関数、戻り値→置けない場所の数*/
int check(char user,char board[12][12]) 
{
	int i,j,dir_ver,dir_hor,is,horizon, vertical;
	int cntRev = 0;
	int cntNoPut = 0;
	int cnt = 0;//打てなかった数をカウント
	char partner='W';

	if (user == 'B') {
		partner = 'W';
	}
	else if (user == 'W') {
		partner = 'B';
	}

	for (vertical = 1; vertical <= 8; vertical++) {
		for (horizon = 1; horizon <= 8; horizon++) {

			if (board[vertical][horizon] != ':') {
				cnt++;
				continue;
			}

			for (i = vertical - 1; i <= vertical + 1; i++) {
				for (j = horizon - 1; j <= horizon + 1; j++) {
					if (board[i][j] == 'W') {
						dir_ver = i - vertical;
						dir_hor = j - horizon;
						is = spe_check(user,dir_ver, dir_hor, vertical, horizon, board);
						cntRev++;
						if (is != 0)
							cntNoPut++;
					}
				}
			}
		
			if (cntRev == 0 || cntRev == cntNoPut) {
				cnt++;
			}

			cntRev = 0;
			cntNoPut = 0;

		}
	}

	return cnt;
}

/*そこに打てるか確認だけする関数(打てる→0、打てない→1)*/
int spe_check(char user,int dir_ver, int dir_hor, int vertical, int horizon, char board[12][12]) 
{

	int  tmp_ver, tmp_hor;
	tmp_hor = horizon;
	tmp_ver = vertical;
	int is = 0;
	char partner='W';

	if (user == 'B') {
		partner = 'W';
	}
	else if (user == 'W') {
		partner = 'B';
	}

	while (board[tmp_ver + dir_ver][tmp_hor + dir_hor] == partner) {

		if (board[vertical + dir_ver * 2][horizon + dir_hor * 2] == ':') {
			is++;
			break;
		}

		if (board[vertical + dir_ver * 2][horizon + dir_hor * 2] == partner) {
			horizon += dir_hor;
			vertical += dir_ver;
		}

		if (board[vertical + dir_ver * 2][horizon + dir_hor * 2] == user) {
			break;
		}

	}

	return is;

}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?