読者です 読者をやめる 読者になる 読者になる

試される大地から

furaiboが送る技術ブログ。プログラミングのTipsなど書いていきます。

○✕ゲーム

とりあえず、ブログのネタもそれほどあるわけではないので、記事数稼ぎに2年前に作ったシェルやコマンドプロンプト上で遊ぶ○✕ゲームのソースコードを以下に上げておく。実装に使ったのはC言語


gccやVisualStudioコマンドラインでのコンパイルが可能であることは確認済み。


/*
 * ○×ゲーム
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


/*グローバル変数の定義*/
int a[3][3]={{0, 0, 0},
			 {0, 0, 0},
			 {0, 0, 0}};	//盤面上の状態を表す配列の定義。グローバル変数。
int level;					//COMのレベルを決定するグローバル変数。



/*関数の定義*/
//じゃんけんで先攻後攻を決定し、先攻後攻を表す変数の値を返す関数
int janken(){
	
	int you, com;
	int result;
	
	printf("\nまず、じゃんけんで先攻後攻を決めます。勝った方が先行です。\n");
	
	do{
		
		printf("1:グー, 2:チョキ, 3:パー\n");
		
		do{
			printf("あなたの手:");  
			scanf("%d", &you);
		}while(you<1 || you>3);
		
		
		com = rand()%3+1;
		if(com == 1){
			printf("コンピュータの手:グー\n");
		}else if(com == 2){
			printf("コンピュータの手:チョキ\n");
		}else if(com == 3){
			printf("コンピュータの手:パー\n");
		}
		
		result = (you-com)%3;
		
		if(result == 0){
			printf("あいこです。\n");
		}
		
	}while(result == 0);
	
	
	if(result == -1 || result == 2){
		printf("じゃんけんに勝ちました。あなたが先行です!\n\n");
		return 0;
	}else if(result == 1 || result == -2){
		printf("じゃんけんに負けました。あなたが後攻です。\n\n");
		return 1;
	}
}



//コンピュータの強さを設定する関数
int difficulty(){
	printf("コンピュータの強さを決定してください。\n");
	printf("1:弱い, 2:普通, 3:強い\n");
	printf("強さ:"); scanf("%d", &level);
}



//○×ゲームの盤面を表示する関数
void gameboard(){
	
	int i, j;
	
	for(i=0; i<3; i++){
		printf("+--+--+--+\n");
		printf("|");
		
		for(j=0; j<3; j++){
			
			if(a[i][j]==0){
				printf(" |");
			}else if(a[i][j]==1){
				printf("○|");
			}else if(a[i][j]==2){
				printf("×|");
			}
		}
		
		printf("\n");
	}
	printf("+--+--+--+\n");

}


//基本となる敵の挙動を決定する関数
int act2(){
	int n, count=0;
	int i, j; 
	
	n = rand()%4;
	
	for(count=0; count<4; count++, n++){
		n = n%4;
		
		switch(n){
			case 0:
				if(a[0][0]==0){
					a[0][0]=2;
					printf("敵は1行1列目に×を置きました。\n");
					return 0;
				}
				break;
			case 1:
				if(a[0][2]==0){
					a[0][2]=2;
					printf("敵は1行3列目に×を置きました。\n");
					return 0;
				}
				break;
			case 2:
				if(a[2][0]==0){
					a[2][0]=2;
					printf("敵は3行1列目に×を置きました。\n");
					return 0;
				}
				break;
			case 3:
				if(a[2][2]==0){
					a[2][2]=2;
					printf("敵は3行3列目に×を置きました。\n");
					return 0;
				}
				break;
		}
	}
	
	//敵が真ん中及び四隅に×を置けなかった時の挙動
	while(1){					//無限ループ。×を置く場所が決まるまでループが続く。
		i=rand()%3+1;
		j=rand()%3+1;
		
		if(a[i-1][j-1]==0){
			a[i-1][j-1]=2;
			printf("敵は%d%d列目に×を置きました。\n", i, j);
			return 0;
		}
		
	}
		
}


//盤面上の状態を評価し、敵の挙動を決定する関数(COMの強さによってこの関数が有効となる確率が変動する)
int act1(){
	
	int k;
	int i, j;
	int count;
	
	//×をおいた場合に勝てるか、あるいは負けを回避できるかどうかを判定し、実行に移す。
	//リーチをかけていて×をおいた時に確実に勝てる時には、その位置に×を置く。
	//プレイヤーにリーチをかけられた状態で、×を置かなければ確実に負ける場合、負けを回避する。
	
	
	//横の評価
	for(k=2; k>=1; k--){
	
		for(i=0; i<3; i++){
			count=0;
			
			for(j=0; j<3; j++){
				if(a[i][j]==k){
					count++;
				}
			}
			
			if(count==2){
				for(j=0; j<3; j++){
					if(a[i][j]==0){
						a[i][j]=2;
						printf("敵は%d%d列目に×を置きました。\n", i+1, j+1);
						return 0;
					}
				}
			}
			
		}
		
	}
	
	
	//縦の評価
	for(k=2; k>=1; k--){
	
		for(j=0; j<3; j++){
			count=0;
			
			for(i=0; i<3; i++){
				if(a[i][j]==k){
					count++;
				}
			}
			
			if(count==2){
				for(i=0; i<3; i++){
					if(a[i][j]==0){
						a[i][j]=2;
						printf("敵は%d%d列目に×を置きました。\n", i+1, j+1);
						return 0;
					}
				}
			}
			
		}
	}
	
	
	//斜めの評価1
	for(k=2; k>=1; k--){
		count=0;
		
		for(i=0, j=0; i<3; i++, j++){
			
			if(a[i][j]==k){
				count++;
			}
		}
		
		if(count==2){
			for(i=0, j=0; i<3; i++, j++){
				if(a[i][j]==0){
					a[i][j]=2;
					printf("敵は%d%d列目に×を置きました。\n", i+1, j+1);
					return 0;
				}
			}
		}
		
	}
	
	
	//斜めの評価2
	for(k=2; k>=1; k--){
		count=0;
		
		for(i=0, j=2; i<3; i++, j--){
			
			if(a[i][j]==k){
				count++;
			}
		}
		
		if(count==2){
			for(i=0, j=2; i<3; i++, j--){
				if(a[i][j]==0){
					a[i][j]=2;
					printf("敵は%d%d列目に×を置きました。\n", i+1, j+1);
					return 0;
				}
			}
		}
		
	}
	
	//どの条件にも合致しなかった場合(勝ちも負けも決まらない局面)には関数act2を実行する
	act2();
}



//敵の挙動を決定する関数
int enemy(){
	
	int n, count=0;
	int i, j;
	int p;
	
	if(a[1][1]==0){
		a[1][1]=2;
		printf("敵は2行2列目に×を置きました。\n");
	}else{
		
		p=rand()%10+1;
		
		if(level == 1){			//COMの強さが弱いとき
			if(p>7){			//30%の確率でact1関数が呼び出される
				act1();
			}else{
				act2();
			}
		}else if(level == 2){	//COMの強さが普通のとき
			if(p>4){			//60%の確率でact1関数が呼び出される
				act1();
			}else{
				act2();
			}
		}else if(level == 3){	//COMの強さが強いとき
			if(p>1){			//90%の確率でact1関数が呼び出される
				act1();
			}else{
				act2();
			}
		}
		
	}
}


//プレイヤーの挙動を決定する関数
void player(){
	
	int i, j;
	
	printf("どこに○を置きますか?\n");
	
	while(1){
		do{ printf("行:"); scanf("%d", &i);}while(i<1 || i>3);
		do{ printf("列:"); scanf("%d", &j);}while(j<1 || j>3);
		
		if(a[i-1][j-1]==0){
			a[i-1][j-1]=1;
			break;
		}else{
			printf("そこには置けません!もう一度選び直してください。\n");
		}
	}
	
	printf("あなたは%d%d列目に○を置きました。\n", i, j);
}



//ゲームが終了したかどうかを判定する関数
int finish(){
	
	int k;
	int i, j;
	int count;
	
	//横の評価
	for(k=1; k<=2; k++){
	
		for(i=0; i<3; i++){
			count=0;
			
			for(j=0; j<3; j++){
				if(a[i][j]==k){
					count++;
				}
			}
			
			if(count==3){
				return k;
			}
			
		}
	}
	
	
	//縦の評価
	for(k=1; k<=2; k++){
	
		for(j=0; j<3; j++){
			count=0;
			
			for(i=0; i<3; i++){
				if(a[i][j]==k){
					count++;
				}
			}
			
			if(count==3){
				return k;
			}
			
		}
	}
	
	
	//斜めの評価
	for(k=2; k>=1; k--){
		
		if(a[0][0]==k && a[1][1]==k && a[2][2]==k){
			return k;
		}
		if(a[2][0]==k && a[1][1]==k && a[0][2]==k){
			return k;
		}
		
	}
	
	
	//どれにも当てはまらなかった場合の返り値
	return 0;
}




//main関数
int main(){
	
	int turn;			//先攻か後攻かを決める変数。2で割り切れる時はプレーヤー、割り切れないときは敵のターンを表す。
	int win=0;			//勝者が誰かを表す変数。値が0の時は勝負がついていない状態。
	int turncount=0;	//総ターン数を表す変数。値が9となった時、ゲームが終了。
	srand((unsigned)time(NULL));	//srand(乱数)を使うための記述。<time.h>ライブラリのインクルードも忘れないこと。
	
	
	printf("○×ゲームをします。\n");
	printf("○×ゲームでコンピュータに勝利してください!\n\n");
	
	
	//敵の強さの設定
	difficulty();
	
	//先攻後攻の決定
	turn = janken();
	
	//○×ゲーム
	while((win=finish())==0 && turncount<9){
		if(turn%2==0){
			turncount++;
			printf("\nあなたのターンです。\n");
			gameboard();
			player();
			gameboard();
			turn++;
		}else{
			turncount++;
			printf("\n敵のターンです。\n");
			gameboard();
			enemy();
			gameboard();
			turn++;
		}
	}
	
	//結果の表示
	if(win==1){
		printf("あなたの勝ちです!\n");
	}else if(win==2){
		printf("あなたの負けです!\n");
	}else{
		printf("引き分けです!\n");
	}
	
	return 0;
}