マスターマインドの問題について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
takaha
記事: 3
登録日時: 9ヶ月前

マスターマインドの問題について

#1

投稿記事 by takaha » 9ヶ月前

コンピューターが生成した4桁の数字を当てるマスターマインドというプログラムを作ろうとしています.
例えば答えが2341の時
入力:7890 出力:それらの数字中0個の数字が含まれ、そのうち位置もあっているのは0個です
入力:1234 出力:それらの数字中4個の数字が含まれ、そのうち位置もあっているのは0個です
入力:2341 出力:正解です

というようなプログラムです。

しかし、どのような数字を入力しても「それらの数字中0個が含まれ、・・・」というような結果になってしまいます・・・。どこが間違っているのか、どなたか教えてください(´;ω;`)

コード:

#include<stdio.h>
#include<string.h>
#include<time.h>
#include<string.h>
#include<ctype.h>

void make4digits(char x[])    /*相異なる4つの数字の並びを生成して配列xに格納*/
{
    int i,j,val;
    
    srand(time(NULL));
    for(i=0;i<4;i++){
        do{
            val=rand()%10;
            for(j=0;j<i;j++)
                if(val==x[j]-'0')    break;
        }while(j<i);    /*重複しない値が出るまで繰り返す*/
        x[i]=val+'0';
    }
}
        
    

int check(const char s[])    /*入力された文字列が四文字、数字のみ、重複なしを満たすかチェック*/
{
    int i,j;
    int len=strlen(s);
    if(len!=4)
        return 1;
    for(i=0;i<4;i++){
        if(!isdigit(s[i]))
            return 2;
    }
    for(i=0;i<4;i++){
        for(j=0;j<i;j++)
            if(s[i]==s[j]) return 3;
    }
    
    return 0;
}

void judge(const char s[],char no[],int *hit,int *blow)    /*ヒットとフローの判定*/
{
    int i,j;
    *hit=*blow=0;
    for(i=0;i<4;i++){
        for(j=0;j<4;j++){
            if(s[i]==no[j])    /*数字が一致*/
                if(i==j)    *(hit)++;    /*位置も一致*/
                else        *(blow)++;   /*位置は不一致*/ 
        }
    }
}

void print_result(int snum,int spos)    /*判定結果を出力*/
{
    if(spos==4)
        printf("正解です!\n");
    else{
        printf("それらの文字中%d個の数字が含まれます\n",spos+snum);
        printf("そのうち位置もあっているのは%d個です\n",spos);
    }
}

int main(void)
{
    int try_no=0,i;
    int chk;
    int hit,blow,ch;
    char no[4];
    const char s[10];
    clock_t end,start;
    
    printf("マスターマインドをしましょう\n");
    printf("4つの数字の並びを当ててください\n");
    printf("1234のように連続して数字を入力してください\n");
    printf("重複のないようにしてください\n");
    printf("五回以内の正解を目指しましょう\n");
    printf("スペースキーで開始します\n");
    make4digits(no);
    printf("%s",no);    /*正しくプログラムが動いてるか検証するために答えを表示*/
    
    while((ch=getchar())!=' ')
        ;
    start=time(NULL);
    do{
        do{
            printf("入力してください:");
            scanf("%s",s);
            chk=check(s);
            switch(chk){    /*正しく入力されるまでループ*/
                case 1:
                    printf("きちんと4文字入力してください\n");
                    break;
                case 2:
                    printf("数字以外を入力しないでください\n");
                    break;
                case 3:
                    printf("同じ数字を重複して入力しないでください\n");
                    break;
            }
        }while(chk!=0);
        
        try_no++;  
        printf("%d回目\n",try_no);
        judge(s,no,&hit,&blow);
        print_result(blow,hit);
        
        
    }while(try_no<6 && hit!=4);
    
    end=time(NULL);
    if(hit!=4)
        printf("残念でした.正解は%sです\n",no);
    else
        printf("正解です!かかった時間は%f秒です\n",difftime(end,start));
 
    return 0;   
}

YuO
記事: 936
登録日時: 8年前
住所: 東京都世田谷区

Re: マスターマインドの問題について

#2

投稿記事 by YuO » 9ヶ月前

takaha さんが書きました:
9ヶ月前
しかし、どのような数字を入力しても「それらの数字中0個が含まれ、・・・」というような結果になってしまいます・・・。どこが間違っているのか、どなたか教えてください(´;ω;`)
これに関しては,演算子の優先順位の確認が必要かと。
takaha さんが書きました:
9ヶ月前

コード:

void judge(const char s[],char no[],int *hit,int *blow)    /*ヒットとフローの判定*/
{
    int i,j;
    *hit=*blow=0;
    for(i=0;i<4;i++){
        for(j=0;j<4;j++){
            if(s[i]==no[j])    /*数字が一致*/
                if(i==j)    *(hit)++;    /*位置も一致*/
                else        *(blow)++;   /*位置は不一致*/ 
        }
    }
}
まず,(hit)はhitと同じです。
そして,*hit++は,単項*よりも後置++の方が優先順位が高いため,*(hit++)と解釈されます。
よって,*(hit)++はhitが保持するポインタを進めるだけであって,ポインタが指している値をインクリメントしてくれていません。
ポインタが指している値をインクリメントとしたいのであれば,

コード:

(*hit)++
とする必要があります。
hitだけでなくblowに関しても同じことが言えます。

ref) C の演算子の優先順位 - cppreference.com ※表の下の「式を解析するとき」以下に私の指摘内容が例示されています。


その他に,
takaha さんが書きました:
9ヶ月前

コード:

int main(void)
{
    int try_no=0,i;
    int chk;
    int hit,blow,ch;
    char no[4];
    const char s[10];
    clock_t end,start;
  • noが4文字分しか用意されていません。
    答えとして使う分には4文字で足りるのですが,実際には表示に使っています。
    このためNULの分の1文字が必要で,配列長は5にする必要があります。
    また,no[4]を0に設定しておく必要があります。
  • sがconst charの配列になっています。
    入力した値を受け取るものですから,sは変更されます。
    よって,charの配列にする必要があります。
  • endとstartはclock関数の戻り値を受けるのではなくtime関数の戻り値を受けるのですから,time_t型にする必要があります。
    ただ,clock関数とclock_tを使った方が得られる時間の精度は高くなると思います。

結城紬
記事: 42
登録日時: 2年前

Re: マスターマインドの問題について

#3

投稿記事 by 結城紬 » 9ヶ月前

オフトピック
https://teratail.com/questions/148582
マルチポストする場合は、ルールを守ってくださいね

かずま

Re: マスターマインドの問題について

#4

投稿記事 by かずま » 9ヶ月前

takaha さんが書きました:
9ヶ月前

コード:

void make4digits(char x[])    /*相異なる4つの数字の並びを生成して配列xに格納*/
{
    int i,j,val;
    
    srand(time(NULL));
    for(i=0;i<4;i++){
        do{
            val=rand()%10;
            for(j=0;j<i;j++)
                if(val==x[j]-'0')    break;
        }while(j<i);    /*重複しない値が出るまで繰り返す*/
        x[i]=val+'0';
    }
}
for, do, for の三重ループになっているのが気になります。
次のように書けば、乱数発生は 4回だけで済みます。

コード:

void make4digits(char x[])
{
    // srand(time(NULL));  これは main の最初で実行
	char a[] = "0123456789";
	int n = 10;         // 未使用の文字の個数
	for (int i = 0; i < 4; i++) {
		int r = rand() % n;
		x[i++] = a[r];
		a[r] = a[--n]); // 最後の要素の上書きで a[r] を削除。
	}
	x[4] = '\0';        // main で char no[5]; とすること
}
#include <string.h> が 2つありますね。あっても問題ないですが。

かずま

Re: マスターマインドの問題について

#5

投稿記事 by かずま » 9ヶ月前

かずま さんが書きました:
9ヶ月前

コード:

		x[i++] = a[r];
すみません。次のように訂正します。

コード:

		x[i] = a[r];
 

返信

“C言語何でも質問掲示板” へ戻る