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

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

ただいまの
回答率

90.02%

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,177

chiku_soh

score 10

前提・実現したいこと

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開発環境

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • flied_onion

    2016/08/21 16:06

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

    キャンセル

回答 2

checkベストアンサー

+1

こんにちは。

乱数が重複することと、

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

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

また、

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;


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

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

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]); 
}


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

あと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(bool sweeped){ 
    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(sweeped && 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(sweeped); 
            printf("if you stop the game,put control+c.\n"); 
            printf("input the coordinate. [x][y] : "); 
            scanf("%d %d",&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; 
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/22 17:39

    srand,rand周りをしっかりするとどういうコードになるんですか?

    キャンセル

  • 2016/08/22 18:57

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

    キャンセル

  • 2016/08/22 19:12

    > timeをsrandに与えているので1秒以内にrandを実行すると重複するのでは
    これを

    > srand呼び出しをmain関数からinit_board関数内、2つ目のループ直前に持ってくればいい
    なぜこれで防げるのですか?

    キャンセル

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

  • ただいまの回答率 90.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる