#3
by ゆうとぴあ » 3年前
このコードは質問時より少し手を加えたものです(目指す仕様に変更はありません)。
他人に見せる目的で書いたコードではないので(他にも理由はあるけど...)、見ての通り決して読みやすいものではありません。
また、このコードを実行すると
一括オープンの際に
1.開くべきマスが開かないことがある
2.数字マスが開かない
という、現時点のプログラムでは望まない動作をします。
ひとまずここを何とかしたいところです。
あと、一括オープンのあたりのプログラムは理解しながら書いたというより、望まない動作をやめさせるために付けたり消したりしながら書いたので、過不足があると思います(旗が立っている場合などの動作はまだ組み込んでいません。混乱するので。)
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 20
int rec();
int count();
int act,area,b,bombs,countbomb,num,x,y,selectx,selecty,checkx,checky,k,l,open[N][N],bomb[N][N],flag[N][N];
int rand_X,rand_Y;
int main(void){
int i,j;
countbomb=0;
srand(time(NULL));
//b=爆弾の割合、爆弾の数 bombs=爆弾のメニュー bomb=配列
//配列は[0][0]から(システム的なものは基本0から)、ユーザーが入力するものは1から始める
//広さ選択始め
while(1){
printf("広さを決めてください\n1:初級(10×10)\n2:中級(15×15)\n3:上級(20×20)\n4:カスタム\n....");
scanf("%d",&area);
if(area!=1 && area!=2 && area!=3 && area!=4){
printf("error1\n");
}
else break;
}
if(area==1){//初級
x=10;
y=10;
}
else if(area==2){//中級
x=15;
y=15;
}
else if(area==3){//上級
x=20;
y=20;
}
else{//カスタム
while(1){
printf("行数を入れてください....");
scanf("%d",&x);
//5*5最小
if(x<5 || x>N){
printf("error2\n");
}
else break;
}
while(1){
printf("列数を入れてください....");
scanf("%d",&y);
//5*5最小
if(y<5 || x>N){
printf("error3\n");
}
else break;
}
}
//広さ選択終わり
//爆弾数選択始め
while(1){
printf("爆弾数を決めてください ()内は爆弾の入る確率\n1:初級(15%)\n2:中級(20%)\n3:上級(25%)\n4:カスタム\n....");
scanf("%d",&bombs);
if(bombs!=1 && bombs!=2 && bombs!=3 && bombs!=4){
printf("error4\n");
}
else break;
}
if(bombs==4){
while(1){
printf("爆弾数(%%)を入れてください....");
scanf("%d",&b);
if(b<=0 || b>50){//爆弾の割合上限
printf("error5\n");
}
else break;
}
}
//爆弾数選択終わり
//初期化など
for(i=0;i<x;i++){
for(j=0;j<y;j++){
printf("■");
open[i][j]=0;
flag[i][j]=0;
bomb[i][j]=0;
}
printf("\n");
}
//新たな爆弾初期化法
i=0;
if(bombs==1) b=x*y*0.15;
else if(bombs==2) b=x*y*0.2;
else if(bombs==3) b=x*y*0.25;
else b=x*y*(float)b/100;
while(i<b){//iがbになった瞬間、爆弾はb個セットされた状態になるので、i=bになったらwhileをぬける。
rand_X=rand()%x;
rand_Y=rand()%y;
if(bomb[rand_X][rand_Y]==0){
bomb[rand_X][rand_Y]=1;
i++;
}
}
for(i=0;i<x;i++){
for(j=0;j<y;j++){
if(bomb[i][j]==1) countbomb++;//爆弾を数える
}
}
printf("残りの爆弾=%d\n",countbomb);
while(1){//マインスイーパー動作部
//行動選択、行列選択のエラー復帰用
while(1){
//開くマス選択始め
while(1){
printf("開く行を入力....");
scanf("%d",&selectx);
selectx--;//ユーザーは配列の0行目を1行目として入力する
if(selectx<0 || selectx>x-1){
printf("error6\n");
}
else break;
}
while(1){
printf("開く列を入力....");
scanf("%d",&selecty);
selecty--;//ユーザーは配列の0列目を1列目として入力する
if(selecty<0 || selecty>y-1){//x=5としたとき0~4行まで作られる。5行目は存在しない
printf("error7\n");
}
else break;
}
//行動選択 act=1:開く 2:旗
while(1){
printf("行動選択;開く:1,フラグ:2");
scanf("%d",&act);
if(act!=1 && act!=2){
printf("error8\n");
}
else break;
}
if(act==1 && open[selectx][selecty]==1){//開いているマスを開くと選びなおし
printf("error9\n");
}
else if(act==1 && flag[selectx][selecty]==1){//フラグマスは開けない
printf("error10\n");
}
else break;
}
//開くマス選択終わり
//マスの値制御
if(act==1) open[selectx][selecty]=1;//選択されたマスを開く
else{
if(flag[selectx][selecty]==1) flag[selectx][selecty]=0;//フラグが立っていれば除去
else flag[selectx][selecty]=1;
}
count(selectx,selecty);
if(num==0){
for(i=selectx-1;i<=selectx+1;i++){
for(j=selecty-1;j<=selecty+1;j++){
rec(i,j);
}
}
}
//表示部始め
countbomb=0;
for(i=0;i<x;i++){
for(j=0;j<y;j++){
num=0;//numはマスごとに加算するのでここで初期化
//既にゲームオーバーでこのマスに爆弾があるとき...
if(open[selectx][selecty]==1 && bomb[selectx][selecty]==1 && bomb[i][j]==1) printf("×");
//ゲームオーバーじゃないとき、ゲームオーバーだけど爆弾マスではないとき
else{
if(open[i][j]==1){//マスが開いてるとき
//周りの爆弾を調べる
count(i,j);
//数字または空白を表示
if(num==1) printf("1");
else if(num==2) printf("2");
else if(num==3) printf("3");
else if(num==4) printf("4");
else if(num==5) printf("5");
else if(num==6) printf("6");
else if(num==7) printf("7");
else if(num==8) printf("8");
else{//空白マスの時
if(open[selectx][selecty]==1 && bomb[selectx][selecty]==1) printf("□");//ゲームオーバーのときは空白を表示するだけ
else{//ゲームオーバーでないかつ空白の時、周りも開く
if(open[i][j]==1) printf("□");
}
}
}
else if(flag[i][j]==1) printf("△");//マスが閉じていて、フラグがあるとき
else printf("■");//その他
}
if(bomb[i][j]==1) countbomb++;//爆弾を数える
}
printf("\n");
}
printf("残りの爆弾=%d\n",countbomb);
//表示部終わり
//ゲームの終了
if(open[selectx][selecty]==1 && bomb[selectx][selecty]==1){
printf("GAME OVER\n");
return 0;
}
}
//動作部終わり
return 0;
}
int rec(int checkx,int checky){
num=0;
count(checkx,checky);
if(checkx==selectx && checky==selecty) return 0;
if(checkx<0 || checkx>=x || checky<0 || checky>=y) return 0;
if(num!=0) return 0;
if(bomb[checkx][checky]==1 || open[checkx][checky]==1) return 0;
open[checkx][checky]=1;
for(k=checkx-1;k<=checkx+1;k++){
for(l=checky-1;l<=checky+1;l++){
rec(k,l);
}
}
return 0;
}
int count(int countx,int county){
int i,j;
for(i=countx-1;i<=countx+1;i++){
for(j=county-1;j<=county+1;j++){
if(i<0 || i>=x || j<0 || j>=y) continue;
if(i==countx && j==county) continue;
if(bomb[i][j]==1) num++;
}
}
return 0;
}
このコードは質問時より少し手を加えたものです(目指す仕様に変更はありません)。
他人に見せる目的で書いたコードではないので(他にも理由はあるけど...)、見ての通り決して読みやすいものではありません。
また、このコードを実行すると[b]一括オープン[/b]の際に
1.開くべきマスが開かないことがある
2.数字マスが開かない
という、現時点のプログラムでは望まない動作をします。
ひとまずここを何とかしたいところです。
あと、一括オープンのあたりのプログラムは理解しながら書いたというより、望まない動作をやめさせるために付けたり消したりしながら書いたので、過不足があると思います(旗が立っている場合などの動作はまだ組み込んでいません。混乱するので。)
[code]
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 20
int rec();
int count();
int act,area,b,bombs,countbomb,num,x,y,selectx,selecty,checkx,checky,k,l,open[N][N],bomb[N][N],flag[N][N];
int rand_X,rand_Y;
int main(void){
int i,j;
countbomb=0;
srand(time(NULL));
//b=爆弾の割合、爆弾の数 bombs=爆弾のメニュー bomb=配列
//配列は[0][0]から(システム的なものは基本0から)、ユーザーが入力するものは1から始める
//広さ選択始め
while(1){
printf("広さを決めてください\n1:初級(10×10)\n2:中級(15×15)\n3:上級(20×20)\n4:カスタム\n....");
scanf("%d",&area);
if(area!=1 && area!=2 && area!=3 && area!=4){
printf("error1\n");
}
else break;
}
if(area==1){//初級
x=10;
y=10;
}
else if(area==2){//中級
x=15;
y=15;
}
else if(area==3){//上級
x=20;
y=20;
}
else{//カスタム
while(1){
printf("行数を入れてください....");
scanf("%d",&x);
//5*5最小
if(x<5 || x>N){
printf("error2\n");
}
else break;
}
while(1){
printf("列数を入れてください....");
scanf("%d",&y);
//5*5最小
if(y<5 || x>N){
printf("error3\n");
}
else break;
}
}
//広さ選択終わり
//爆弾数選択始め
while(1){
printf("爆弾数を決めてください ()内は爆弾の入る確率\n1:初級(15%)\n2:中級(20%)\n3:上級(25%)\n4:カスタム\n....");
scanf("%d",&bombs);
if(bombs!=1 && bombs!=2 && bombs!=3 && bombs!=4){
printf("error4\n");
}
else break;
}
if(bombs==4){
while(1){
printf("爆弾数(%%)を入れてください....");
scanf("%d",&b);
if(b<=0 || b>50){//爆弾の割合上限
printf("error5\n");
}
else break;
}
}
//爆弾数選択終わり
//初期化など
for(i=0;i<x;i++){
for(j=0;j<y;j++){
printf("■");
open[i][j]=0;
flag[i][j]=0;
bomb[i][j]=0;
}
printf("\n");
}
//新たな爆弾初期化法
i=0;
if(bombs==1) b=x*y*0.15;
else if(bombs==2) b=x*y*0.2;
else if(bombs==3) b=x*y*0.25;
else b=x*y*(float)b/100;
while(i<b){//iがbになった瞬間、爆弾はb個セットされた状態になるので、i=bになったらwhileをぬける。
rand_X=rand()%x;
rand_Y=rand()%y;
if(bomb[rand_X][rand_Y]==0){
bomb[rand_X][rand_Y]=1;
i++;
}
}
for(i=0;i<x;i++){
for(j=0;j<y;j++){
if(bomb[i][j]==1) countbomb++;//爆弾を数える
}
}
printf("残りの爆弾=%d\n",countbomb);
while(1){//マインスイーパー動作部
//行動選択、行列選択のエラー復帰用
while(1){
//開くマス選択始め
while(1){
printf("開く行を入力....");
scanf("%d",&selectx);
selectx--;//ユーザーは配列の0行目を1行目として入力する
if(selectx<0 || selectx>x-1){
printf("error6\n");
}
else break;
}
while(1){
printf("開く列を入力....");
scanf("%d",&selecty);
selecty--;//ユーザーは配列の0列目を1列目として入力する
if(selecty<0 || selecty>y-1){//x=5としたとき0~4行まで作られる。5行目は存在しない
printf("error7\n");
}
else break;
}
//行動選択 act=1:開く 2:旗
while(1){
printf("行動選択;開く:1,フラグ:2");
scanf("%d",&act);
if(act!=1 && act!=2){
printf("error8\n");
}
else break;
}
if(act==1 && open[selectx][selecty]==1){//開いているマスを開くと選びなおし
printf("error9\n");
}
else if(act==1 && flag[selectx][selecty]==1){//フラグマスは開けない
printf("error10\n");
}
else break;
}
//開くマス選択終わり
//マスの値制御
if(act==1) open[selectx][selecty]=1;//選択されたマスを開く
else{
if(flag[selectx][selecty]==1) flag[selectx][selecty]=0;//フラグが立っていれば除去
else flag[selectx][selecty]=1;
}
count(selectx,selecty);
if(num==0){
for(i=selectx-1;i<=selectx+1;i++){
for(j=selecty-1;j<=selecty+1;j++){
rec(i,j);
}
}
}
//表示部始め
countbomb=0;
for(i=0;i<x;i++){
for(j=0;j<y;j++){
num=0;//numはマスごとに加算するのでここで初期化
//既にゲームオーバーでこのマスに爆弾があるとき...
if(open[selectx][selecty]==1 && bomb[selectx][selecty]==1 && bomb[i][j]==1) printf("×");
//ゲームオーバーじゃないとき、ゲームオーバーだけど爆弾マスではないとき
else{
if(open[i][j]==1){//マスが開いてるとき
//周りの爆弾を調べる
count(i,j);
//数字または空白を表示
if(num==1) printf("1");
else if(num==2) printf("2");
else if(num==3) printf("3");
else if(num==4) printf("4");
else if(num==5) printf("5");
else if(num==6) printf("6");
else if(num==7) printf("7");
else if(num==8) printf("8");
else{//空白マスの時
if(open[selectx][selecty]==1 && bomb[selectx][selecty]==1) printf("□");//ゲームオーバーのときは空白を表示するだけ
else{//ゲームオーバーでないかつ空白の時、周りも開く
if(open[i][j]==1) printf("□");
}
}
}
else if(flag[i][j]==1) printf("△");//マスが閉じていて、フラグがあるとき
else printf("■");//その他
}
if(bomb[i][j]==1) countbomb++;//爆弾を数える
}
printf("\n");
}
printf("残りの爆弾=%d\n",countbomb);
//表示部終わり
//ゲームの終了
if(open[selectx][selecty]==1 && bomb[selectx][selecty]==1){
printf("GAME OVER\n");
return 0;
}
}
//動作部終わり
return 0;
}
int rec(int checkx,int checky){
num=0;
count(checkx,checky);
if(checkx==selectx && checky==selecty) return 0;
if(checkx<0 || checkx>=x || checky<0 || checky>=y) return 0;
if(num!=0) return 0;
if(bomb[checkx][checky]==1 || open[checkx][checky]==1) return 0;
open[checkx][checky]=1;
for(k=checkx-1;k<=checkx+1;k++){
for(l=checky-1;l<=checky+1;l++){
rec(k,l);
}
}
return 0;
}
int count(int countx,int county){
int i,j;
for(i=countx-1;i<=countx+1;i++){
for(j=county-1;j<=county+1;j++){
if(i<0 || i>=x || j<0 || j>=y) continue;
if(i==countx && j==county) continue;
if(bomb[i][j]==1) num++;
}
}
return 0;
}
[/code]