質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

2507閲覧

乱数と盤面表示についてです。

chiku_soh

総合スコア12

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2016/08/21 05:43

###前提・実現したいこと

centのcmd上でc言語のマインスイーパーを作ろうとしています。

###発生している問題・エラーメッセージ
乱数が重複することと、最初から盤面上に爆弾の位置が表示されてしまい、それに加えて座標を入力してもopenできません。

エラーメッセージ
エラーメッセージはありません。

###該当のソースコード

//min.c

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

#define MINE 10
#define BORD_wide 9
#define BORD_high 9

bool g_open[BORD_wide+2][BORD_high+2];
bool g_mine[BORD_wide+2][BORD_high+2];
char g_near[BORD_wide+2][BORD_high+2];

int init_board(){
int x,y,i;
for(x=0;x<11;x++){
for(y=0;y<11;y++){
g_mine[x][y]=false;
g_near[x][y]=0;
g_open[x][y]=false;
}
}

for(i=0;i<10;i++){
int x,y;
do{
x=rand()%10;
y=rand()%10;
}
while(g_mine[x][y]);
g_mine[x][y]=true;
g_near[x-1][y-1]+=1;
g_near[x][y-1]+=1;
g_near[x+1][y-1]+=1;
g_near[x-1][y]+=1;
g_near[x][y]+=1;
g_near[x+1][y]+=1;
g_near[x-1][y+1]+=1;
g_near[x][y+1]+=1;
g_near[x+1][y+1]+=1;
}
}

const char digitStr[]={
"1","2","3","4","5","6","7","8","9",
};
int pboard(){
int x,y;
printf("\n 123456789\n");
for(y=1;y<=9;y++){
printf("%d",y);
for(x=1;x<=9;x++){
if(!g_mine[x][y])
printf("?");
else if(g_mine[x][y])
printf("
");
else if(!g_near[x][y])
printf("#");
else
printf("%d",g_near[x][y]);
}
printf("\n");
}
printf("\n");
}

bool checkSweeped(){
int x,y;
for(x=1;x<=9;x++){
for(y=1;y<=9;y++){
if(!g_mine[x][y]&&!g_open[x][y])
return false;
}
}
return true;
}

int main(void){
int xx,yy;
srand((int)time(NULL));
printf("start minsweeper!");

for(;;){
init_board();
bool sweeped=false;
while(!sweeped){
pboard();
printf("if you stop the game,put control+c.\n");
printf("input the coordinate. [x][y] : ");
scanf("%d %d",&xx,&yy);

open(xx,yy); if(g_mine[xx][yy]) break; sweeped=checkSweeped(); } pboard(); if(sweeped) printf("cleared!!\n"); else printf("Oh,no!you've failed.");

}
return 0;
}

###試したこと
どこを直せばよいかわからず、下手に手を加えるのが怖くて何もできていません。

###補足情報(言語/FW/ツール等のバージョンなど)
c言語 emacs gcc開発環境

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

flied_onion

2016/08/21 07:06

コードは ``` で括られた中に書くか、 コードを選択して code ボタンを押してください。
guest

回答2

0

ベストアンサー

こんにちは。

乱数が重複することと、

この件については、C言語で重複しない乱数生成の仕方を教えてください!を参考にされると良いです。
配列へ発生させたい範囲の数値を単純に(昇順等)放り込んで、その配列をシャッフルして先頭から必要な数だけ取り出します。これは重複しない乱数となります。

投稿2016/08/22 01:10

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

まず乱数が重複するのは、srand関数の使い方が違います。
srand関数にはrand関数を使う度に異なる値を与える必要があります。

また、

C

1do{ 2 x=rand()%10; 3 y=rand()%10; 4} 5while(g_mine[x][y]); 6 7g_mine[x][y]=true; 8g_near[x-1][y-1]+=1; 9g_near[x][y-1]+=1; 10g_near[x+1][y-1]+=1; 11g_near[x-1][y]+=1; 12g_near[x][y]+=1; 13g_near[x+1][y]+=1; 14g_near[x-1][y+1]+=1; 15g_near[x][y+1]+=1; 16g_near[x+1][y+1]+=1;

これですとxもyも0になる可能性があり、配列の直前のアドレスのデータが壊されます。
もうちょっとループ文をいじると効率の良いものになりますが、ここでは割愛します。

爆弾が表示されてしまうのは、

C

1for(x=1;x<=9;x++){ 2 if(!g_mine[x][y]) 3 printf("?"); 4 else if(g_mine[x][y]) 5 printf("*"); 6 else if(!g_near[x][y]) 7 printf("#"); 8 else 9 printf("%d",g_near[x][y]); 10}

ここでg_mine[x][y]がtrueのとき、「」を表示するようになっています。
これだと何もしなくても「
」が出るのではないでしょうか。

あとopen関数が見当たらないのですが記載もれでしょうか?

----------以下追記--------------
参考としてコードを示します。ご自身のと比べて見て下さい。

C

1//min.c 2 3#include<stdio.h> 4#include<string.h> 5#include<time.h> 6#include<stdlib.h> 7#include<stdbool.h> 8 9#define MINE 10 10#define BORD_wide 9 11#define BORD_high 9 12 13bool g_open[BORD_wide+2][BORD_high+2]; 14bool g_mine[BORD_wide+2][BORD_high+2]; 15char g_near[BORD_wide+2][BORD_high+2]; 16 17int init_board(){ 18 int x,y,i; 19 20 for(x=0;x<11;x++){ 21 for(y=0;y<11;y++){ 22 g_mine[x][y]=false; 23 g_near[x][y]=0; 24 g_open[x][y]=false; 25 } 26 } 27 28 for(i=0;i<10;i++){ 29 int x,y; 30 do{ 31 x=rand()%10; 32 y=rand()%10; 33 }while(g_mine[x][y]); 34 35 g_mine[x][y]=true; 36 g_near[x-1][y-1]+=1; 37 g_near[x][y-1]+=1; 38 g_near[x+1][y-1]+=1; 39 g_near[x-1][y]+=1; 40 g_near[x][y]+=1; 41 g_near[x+1][y]+=1; 42 g_near[x-1][y+1]+=1; 43 g_near[x][y+1]+=1; 44 g_near[x+1][y+1]+=1; 45 } 46} 47 48const char *digitStr[]={ 49"1","2","3","4","5","6","7","8","9", 50}; 51 52int pboard(bool sweeped){ 53 int x,y; 54 printf("\n 123456789\n"); 55 56 for(y=1;y<=9;y++){ 57 printf("%d",y); 58 59 for(x=1;x<=9;x++){ 60 61 if(!g_mine[x][y]) 62 printf("?"); 63 else if(sweeped && g_mine[x][y]) //爆弾未発見時は非表示 64 printf("*"); 65 else if(!g_near[x][y]) 66 printf("#"); 67 else 68 printf("%d",g_near[x][y]); 69 } 70 printf("\n"); 71 } 72 printf("\n"); 73} 74 75bool checkSweeped(){ 76 int x,y; 77 for(x=1;x<=9;x++){ 78 for(y=1;y<=9;y++){ 79 if(!g_mine[x][y]&&!g_open[x][y]) 80 return false; 81 } 82 } 83 return true; 84} 85 86int main(void){ 87 int xx,yy; 88 89 srand((int)time(NULL)); 90 printf("start minsweeper!"); 91 92 for(;;){ 93 init_board(); 94 bool sweeped=false; 95 96 while(!sweeped){ 97 pboard(sweeped); 98 printf("if you stop the game,put control+c.\n"); 99 printf("input the coordinate. [x][y] : "); 100 scanf("%d %d",&xx,&yy); 101 102 if(g_mine[xx][yy]) 103 break; 104 sweeped=checkSweeped(); 105 } 106 } 107 pboard(); 108 if(sweeped) 109 printf("cleared!!\n"); 110 else 111 printf("Oh,no!you've failed."); 112 } 113 return 0; 114}

投稿2016/08/21 06:51

編集2016/08/22 07:40
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chiku_soh

2016/08/21 14:19

open(xx,yy); これでは、不完全なopen関数なんですか? あと、乱数や盤面についてどのように修正すればいいか教えてください。
退会済みユーザー

退会済みユーザー

2016/08/21 23:59

open(xx,yy)で、xxとyyを使って何らかの処理をする関数がopen関数ですが、その処理をしている側のソースコードが見当たらないのです。 乱数は、randを使ったらsrandを使う、というようにrandを使う度にsrandを使う必要があります。 盤面については凡例を教えて下さい。「*」「#」「?」がそれぞれ何なのか、です。
ozwk

2016/08/22 03:13

> randを使ったらsrandを使う、というようにrandを使う度にsrandを使う必要があります。 そんな必要はないのでは。
chiku_soh

2016/08/22 05:29

*が爆弾で#が空白、?が未開封です。 その処理はどのようにすればいいのですか?
退会済みユーザー

退会済みユーザー

2016/08/22 07:43

ここでコードは書けないので、一例を上記回答に追記します。
退会済みユーザー

退会済みユーザー

2016/08/22 07:51 編集

あと乱数についてですが、srandとrandを対にする必要は確かにありません。誤った表現を使ってしまい申し訳ありません。ただ、timeをsrandに与えているので1秒以内にrandを実行すると重複するのでは、と思ったのです。 このあたりは上記追記でのコードでは触っていませんのでご注意ください。
ozwk

2016/08/22 08:39

srand,rand周りをしっかりするとどういうコードになるんですか?
退会済みユーザー

退会済みユーザー

2016/08/22 09:57

srand呼び出しをmain関数からinit_board関数内、2つ目のループ直前に持ってくればいいのでは?
ozwk

2016/08/22 10:12

> timeをsrandに与えているので1秒以内にrandを実行すると重複するのでは これを > srand呼び出しをmain関数からinit_board関数内、2つ目のループ直前に持ってくればいい なぜこれで防げるのですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問