明解C言語 中級の4章末問題解いてみた

4章はなかなか苦戦しとります。4章はマスターマインドという数当て遊びでしたが、第4章は例題、自由課題ともにやりがいがある感じにまとまってました。

最近プログラムばっかりですが、ひとまずはできたー!と思えるくらいまではやりたいなと。

ではさっそく1問からいきます。最近はコードばっかりで、うちのブログっぽさがなくなってたので(ある意味あるかもしれないけどお)いろいろ感想や解説を入れます。

1問目 プレーヤの入力回数を制限したマスターマインドを作成しよ。

解説 2問目で上書きしてしまったのでありませぬ!

 

2問目 ヒント機能がついたマスターマインドを作成しよ。

ソースを見る

解説 ある回数でヒントがでるという一番簡単なものをやってみました。
ちなみに回数制限しているので、1問目も兼ねています。

 

3問目 桁数が可変のマスターマインドを作成しよ。

ソースを見る

解説 単純にループの回数を決めるようにしました。

 

4問目 数字の重複を許したマスターマインドを作成しよ。

ソースを見る

解説 これは前問の重複にかかわるところをコメントアウトしました。悪く言えば手抜き、良く言えば手抜きってやつですね。これでいいのだ。

 

5問目 数字ではなくて、色を当てるマスターマインドを作成しよ。

ソースを見る

解説 これはかなり考えました。ですが4色にしてねっていうチェックは省略してます・・・。比較は文字でやり、配列への代入を数字でおこなうようにしてます。
hit&Blowの判定とか、いろいろと作り変えました。

 

6問目 COMと交互にヒントを与えて対戦する。

ソースを見る
ソースを見る       2/27 修正版載せてみました。

解説 これははっきり言うとできてません(笑)、単純にCOMプレイヤーを作って、疑似乱数が4桁一致すればCOMの勝ちという、ようするにただの運ゲーになってます。
いまはこれでいいかな・・(こればっかりやー)

 

7問目 1章で作った数当てゲームで数の重複を認めないものを作りよ。

ソースを見る

解説 数字を配列にいれて検問部分を作って、パスしたらゲームが開始するというものです。力技になってます。。。

 

うーむ、これでいいのだ的な解答が目立つようになってきました(´・ω・`)

ばんがろー。

 

Similar Posts:


10 thoughts on “明解C言語 中級の4章末問題解いてみた

  1. かぼちゃ

    数日前にコメントしましたが,どこかで消失したのでしょうか.
    そのコメントでは計算間違えていたので恥ずかしいですが(笑)

    COMの正解率をあげるためかもしれませんが問6についてです.
    COMのクリア率が34.39%あります.
    (1桁だけあっていればクリア,かつ1ターンに4回試行するため.
    ちょっと強すぎるかもしれません(笑

    Reply
    1. たけけん Post author

      かぼちゃさん。

      こんばんわ。全体的につっこみどころはかなりあるだろうとは思っていますが、これはちょっと(だいぶ?)ひどすぎでしたね(笑)
      ありがとうございますmm。
      ご指摘いただいたCOMのところは修正してみました。
      これならまだ遊べるかなと。。。。

      数日前にいただいたコメントですが、WordpressのAkismetに引っかかってしまったようで、スパムフォルダに入ってしまっていました ><
      コードを書いていただくケースもあると、サーバ側で何らかの対処も必要ですねえ。

      Reply
  2. ずっきーに

    かなり遅いレスですみません.

    この4問目ですが,コメントアウトしただけだと,「1111」や「2222」などの同じ数字を並べた入力をすると
    blowが大きくなりすぎませんか???

    Reply
    1. たけけん Post author

      ずっきーに さん

      コメントありがとうございます。こちらもレスが遅れてしまいすみません。
      検証してみましたが見事に数値がおかしいですねw orz

      プログラムを思い出すのに少し時間がかかるので、また時間が出来たら
      再チャレンジしようと思います・・ orz

      Reply
  3. 山田将之

    4-4 うまくいかずに時間がかかりました。いい問題です。ポインタと関数の概念を理解していないと解けない問題であり、逆にこの問題がすらすら解ければ、VBAマクロでもかなりのものが作れると思います。
    #include
    #include
    #include
    #include
    #include

    /*— 相異なる四つの数字の並びを生成して配列xに格納 —*/
    void makedigits(int x[], int *keta)
    {
    int i, j, val;
    for (i = 0; i < *keta; i++) {
    val = rand() % 10; /* 0~9の乱数 */
    x[i] = val;
    }
    }

    /*— 入力された文字列sの妥当性をチェック —*/
    int check(const char s[],int *keta)
    {
    int i, j;
    if (strlen(s) != *keta) /* 文字列の長さがketaでない */
    return (1);

    for (i = 0; i < *keta; i++) {
    if (!isdigit(s[i]))
    return (2); /* 数字以外の文字が含まれている */

    }

    return (0); /* 文字列は妥当 */
    }

    /*— ヒット&ブローの判定 —*/
    void judge(const char s[], const int no[], int *hit, int *blow,int *keta)
    {
    int i, j;
    *hit = *blow = 0;
    for (i = 0; i < *keta; i++) {
    for (j = 0; j < *keta; j++) {
    if (s[i] == '0' + no[j]) /* 数字が一致 */
    if (i == j)
    (*hit)++ ; /* ヒット(位置も一致) */
    else
    (*blow)++ ; /* ブロー(位置が不一致) */
    }
    }
    }
    /*— ヒット&ブローの表示—*/
    void print_res(const char s[], const int no[],int *keta)
    {
    int i, j;
    for (i = 0; i < *keta; i++) {
    for (j = 0; j < *keta; j++) {
    if (s[i] == '0' + no[j]) /* 数字が一致 */
    if (i == j)
    printf("ヒットした数字は%d番目の数字です。\n");
    /* ヒット(位置も一致) */
    else
    printf("ブローした数字は%d番目の数字です。\n");
    /* ブロー(位置が不一致) */
    }
    }

    }
    /*— 判定結果を表示 —*/
    void print_result(int snum, int spos,int *keta)
    {
    if (spos == *keta)
    printf("正解です!!");
    else if (snum == 0)
    printf("  それらの数字はまったく含まれません。\n");
    else {
    printf("  それらの数字中%d個の数字が含まれます。\n", snum);

    if (spos == 0)
    printf("  ただし位置もあっている数字はありません。\n");
    else
    printf("  その中の%d個は位置もあっています。\n", spos);

    }
    putchar('\n');
    }

    int main(void)
    {
    int keta;
    int try_no = 0; /* 入力回数 */
    int chk; /* 入力された文字列のチェック結果 */
    int hit; /* 位置も数字も当たっている個数 */
    int blow; /* 数字が当たって位置が当たっていない数字の個数 */
    int no[10]; /* 当てる数字の並び */
    char buff[11]; /* 読み込む数字の並びを格納する文字列 */
    clock_t start, end; /* 開始時刻・終了時刻 */

    srand(time(NULL)); /* 乱数の種を初期化 */

    puts("■ マスターマインドをしましょう。");
    puts("■ 四つの数字の並びを当ててください。");
    puts("■ 同じ数字が複数含まれることはありません。");
    puts("■ 連続して入力してください。");
    puts("■ スペース文字などを入力してはいけません。\n");
    puts("■何桁にしますか?\n");
    scanf("%d",&keta);
    makedigits(no,&keta); /* 相異なるketaの数字の並びを生成 */

    start = clock(); /* 計測開始 */

    do {
    do {

    printf("入力してください:");
    scanf("%s", buff); /* 文字列として読み込む */

    chk = check(buff,&keta); /* 読み込んだ文字列をチェック */

    switch (chk) {
    case 1: puts("\aきちんと%d文字で入力してください。,keta"); break;
    case 2: puts("\a数字以外の文字を入力しないでください。"); break;
    case 3: puts("\a同一の数字を複数入力しないでください。"); break;
    }
    } while (chk != 0);

    try_no++;
    judge(buff, no, &hit, &blow,&keta); /* 判定 */
    print_res(buff, no,&keta);
    print_result(hit + blow, hit,&keta); /* 判定結果を表示 */

    } while (hit < keta);

    end = clock(); /* 計測終了 */

    printf("%d回かかりました。\n所要時間は%.1f秒でした。\n",
    try_no, (double)(end – start) / CLOCKS_PER_SEC);

    return (0);
    }
    [EOF]

    Reply
  4. 山田将之

    悩んだのは4-3でした。4-4はこれをもとにすれば大丈夫です。

    #include
    #include
    #include
    #include
    #include

    /*— 相異なる四つの数字の並びを生成して配列xに格納 —*/
    void makedigits(int x[], int *keta)
    {
    int i, j, val;
    for (i = 0; i < *keta; i++) {
    do {
    val = rand() % 10; /* 0~9の乱数 */
    for (j = 0; j < i; j++) /* その数が既に得られているか */
    if (val == x[j])
    break;
    } while (j < i); /* 重複しない値が得られるまで繰り返す */
    x[i] = val;
    }
    }
    /*— 入力された文字列sの妥当性をチェック —*/
    int check(const char s[],int *keta)
    {
    int i, j;
    if (strlen(s) != *keta) /* 文字列の長さがketaでない */
    return (1);

    for (i = 0; i < *keta; i++) {
    if (!isdigit(s[i]))
    return (2); /* 数字以外の文字が含まれている */
    for (j = 0; j < i; j++)
    if (s[i] == s[j])
    return (3); /* 同一の数字が含まれている */
    }

    return (0); /* 文字列は妥当 */
    }

    /*— ヒット&ブローの判定 —*/
    void judge(const char s[], const int no[], int *hit, int *blow,int *keta)
    {
    int i, j;
    *hit = *blow = 0;
    for (i = 0; i < *keta; i++) {
    for (j = 0; j < *keta; j++) {
    if (s[i] == '0' + no[j]) /* 数字が一致 */
    if (i == j)
    (*hit)++ ; /* ヒット(位置も一致) */
    else
    (*blow)++ ; /* ブロー(位置が不一致) */
    }
    }
    }
    /*— ヒット&ブローの表示—*/
    void print_res(const char s[], const int no[],int *keta)
    {
    int i, j;
    for (i = 0; i < *keta; i++) {
    for (j = 0; j < *keta; j++) {
    if (s[i] == '0' + no[j]) /* 数字が一致 */
    if (i == j)
    printf("ヒットした数字は%d番目の数字です。\n");
    /* ヒット(位置も一致) */
    else
    printf("ブローした数字は%d番目の数字です。\n");
    /* ブロー(位置が不一致) */
    }
    }

    }
    /*— 判定結果を表示 —*/
    void print_result(int snum, int spos,int *keta)
    {
    if (spos == *keta)
    printf("正解です!!");
    else if (snum == 0)
    printf("  それらの数字はまったく含まれません。\n");
    else {
    printf("  それらの数字中%d個の数字が含まれます。\n", snum);

    if (spos == 0)
    printf("  ただし位置もあっている数字はありません。\n");
    else
    printf("  その中の%d個は位置もあっています。\n", spos);

    }
    putchar('\n');
    }

    int main(void)
    {
    int keta;
    int try_no = 0; /* 入力回数 */
    int chk; /* 入力された文字列のチェック結果 */
    int hit; /* 位置も数字も当たっている個数 */
    int blow; /* 数字が当たって位置が当たっていない数字の個数 */
    int no[10]; /* 当てる数字の並び */
    char buff[11]; /* 読み込む数字の並びを格納する文字列 */
    clock_t start, end; /* 開始時刻・終了時刻 */

    srand(time(NULL)); /* 乱数の種を初期化 */

    puts("■ マスターマインドをしましょう。");
    puts("■ 四つの数字の並びを当ててください。");
    puts("■ 同じ数字が複数含まれることはありません。");
    puts("■ 連続して入力してください。");
    puts("■ スペース文字などを入力してはいけません。\n");
    puts("■何桁にしますか?\n");
    scanf("%d",&keta);
    makedigits(no,&keta); /* 相異なるketaの数字の並びを生成 */

    start = clock(); /* 計測開始 */

    do {
    do {

    printf("入力してください:");
    scanf("%s", buff); /* 文字列として読み込む */

    chk = check(buff,&keta); /* 読み込んだ文字列をチェック */

    switch (chk) {
    case 1: puts("\aきちんと%d文字で入力してください。,keta"); break;
    case 2: puts("\a数字以外の文字を入力しないでください。"); break;
    case 3: puts("\a同一の数字を複数入力しないでください。"); break;
    }
    } while (chk != 0);

    try_no++;
    judge(buff, no, &hit, &blow,&keta); /* 判定 */
    print_res(buff, no,&keta);
    print_result(hit + blow, hit,&keta); /* 判定結果を表示 */

    } while (hit < keta);

    end = clock(); /* 計測終了 */

    printf("%d回かかりました。\n所要時間は%.1f秒でした。\n",
    try_no, (double)(end – start) / CLOCKS_PER_SEC);

    return (0);
    }
    [EOF]

    Reply
  5. 山田将之

    今の自分の実力では、色を当てるマスターマインドが作れませんでした。
    文字を配列に格納し、使おうとしてもエラーでした。解答例もしよければ教えてください。よろしくお願いします。
    ちなみに私の作ったプログラムは以下の通りです。
    * マスターマインド */

    #include
    #include
    #include
    #include
    #include

    /*— 相異なる四つの数字の並びを生成して配列xに格納 —*/
    void make4digits(char x[])
    {
    int i, j, val;
      char *hd[ ]={“白” , “黒” , “赤” , “青” , “黄” , “緑 “, “橙” , “茶”};
    for (i = 0; i < 4; i++) {
    do {
    val = rand() % 8; /* 0~7の乱数 */
    for (j = 0; j < i; j++) /* その数が既に得られているか */
    if (hd[val] == x[j])
    break;
    } while (j < i); /* 重複しない値が得られるまで繰り返す */
    x[i] = hd[val];
    }
    }

    /*— 入力された文字列sの妥当性をチェック —*/
    int check(const char s[])
    {
    int i, j;

    if (strlen(s) != 4) /* 文字列の長さが4でない */
    return (1);

    for (i = 0; i < 4; i++) {

    for (j = 0; j < i; j++)
    if (s[i] == s[j])
    return (2); /* 同一の色が含まれている */
    }

    return (0); /* 文字列は妥当 */
    }

    /*— ヒット&ブローの判定 —*/
    void judge(const char s[], const char col[], 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] == col[j]) /* 色が一致 */
    if (i == j)
    (*hit)++; /* ヒット(位置も一致) */
    else
    (*blow)++; /* ブロー(位置が不一致) */
    }
    }
    }

    /*— 判定結果を表示 —*/
    void print_result(int snum, int spos)
    {
    if (spos == 4)
    printf("正解です!!");
    else if (snum == 0)
    printf("  それらの色はまったく含まれません。\n");
    else {
    printf("  それらの色中%d個の数字が含まれます。\n", snum);

    if (spos == 0)
    printf("  ただし位置もあっている色はありません。\n");
    else
    printf("  その中の%d個は位置もあっています。\n", spos);
    }
    putchar('\n');
    }

    int main(void)
    {
    int try_no = 0; /* 入力回数 */
    int chk; /* 入力された文字列のチェック結果 */
    int hit; /* 位置も色も当たっている個数 */
    int blow; /* 色が当たって位置が当たっていない数字の個数 */
    char col[4]; /* 当てる色の並び */
    char buff[10]; /* 読み込む色の並びを格納する文字列 */

    clock_t start, end; /* 開始時刻・終了時刻 */

    srand(time(NULL)); /* 乱数の種を初期化 */

    puts("■ マスターマインドをしましょう。");
    puts("■ 四つの色の並びを当ててください。");
    puts("■ 同じ色が複数含まれることはありません。");
    puts("■ 赤、青、橙、黄のように連続して入力してください。");
    puts("■ スペース文字などを入力してはいけません。\n");

    make4digits(col); /* 相異なる四つの色の並びを生成 */

    start = clock(); /* 計測開始 */

    do {
    do {
    printf("入力してください:");
    scanf("%s", buff); /* 文字列として読み込む */

    chk = check(buff); /* 読み込んだ文字列をチェック */

    switch (chk) {
    case 1: puts("\aきちんと4文字で入力してください。"); break;
    case 2: puts("\a同一の数字を複数入力しないでください。"); break;
    }
    } while (chk != 0);

    try_no++;
    judge(buff, col, &hit, &blow); /* 判定 */
    print_result(hit +blow,hit); /* 判定結果を表示 */

    } while (hit < 4);

    end = clock(); /* 計測終了 */

    printf("%d回かかりました。\n所要時間は%.1f秒でした。\n",
    try_no, (double)(end – start) / CLOCKS_PER_SEC);

    return (0);
    }
    [EOF]

    Reply
  6. 山田将之

    色の問題を配列に格納して表示するところまでできました。
    わからないのは、scanfで色を読み取って配列に格納し、問題と文字で比較する方法です。
    入力した文字が一定の条件を満たしているか調べる方法もわかりません。今、入門編の本で復習して一生懸命考えています。
    ちなみに、色の問題を配列に格納して表示するところまでのプログラムは以下のようにしました。
    /*— 相異なる四つの数字の並びを生成して配列xに格納 —*/
    int main(void)
    {
    int i;
    int j;
    int val;
    char *x[3];
    char *p[] = {“白” , “黒” , “赤” , “青” , “黄” , “緑 “, “橙” , “茶”};
    srand(time(NULL)); /* 乱数の種を初期化 */

    for (i = 0; i < 4; i++) {
    do {
    val = rand() % 8; /* 0~7の乱数 */
    for (j = 0; j < i; j++) /* その数が既に得られているか */
    if (p[val] == x[j])
    break;
    } while (j < i); /* 重複しない値が得られるまで繰り返す */
    x[i] = p[val];
    }
    for (i = 0; i < 4; i++)
    printf("x[%d] = \"%s\"\n", i, x[i]);
    return 0;
    }
    [EOF]

    Reply
  7. 山田将之

    配列としてscanfで読み込み、表示するところまで理解できました。後は、比較だけですが、引数の渡し方と、
    比較するものがポインタの配列と、2次元配列を比較するのがうまくいけば完成ですが、ここがどうもうまくいきません。配列としてscanfで読み込み、表示するところまでのプログラムは以下のようになります。
    #include

    int main(void)
    {
    int i;
    char buff[4][4];
    printf(“入力してください:”);
    for(i=0;i<4;i++) {
    printf(" buff[%d]: ", i);
    scanf("%s", buff[i]); /* 文字列として読み込む */

    }

    for(i=0;i<4;i++)
    printf("buff[%d]=%s\n", i,buff[i]);

    return 0;
    }
    (EOF)

    Reply
  8. 山田将之

    お久しぶりです。
    少しずるい解答かと思いますが、これで動かしました。
    /* マスターマインド */

    #include
    #include
    #include
    #include
    #include

    /*— 相異なる四つの数字の並びを生成して配列xに格納 —*/
    void make4digits(int x[])
    {
    int i, j, val;

    for (i = 0; i < 4; i++) {
    do {
    val = rand() % 8; /* 0~9の乱数 */
    for (j = 0; j < i; j++) /* その数が既に得られているか */
    if (val == x[j])
    break;
    } while (j < i); /* 重複しない値が得られるまで繰り返す */
    x[i] = val;
    }
    }

    /*— 入力された文字列sの妥当性をチェック —*/
    int check(const char s[])
    {
    int i, j;

    if (strlen(s) != 4) /* 文字列の長さが4でない */
    return (1);

    for (i = 0; i < 4; i++) {
    if (!isdigit(s[i]))
    return (2); /* 数字以外の文字が含まれている */
    for (j = 0; j < i; j++)
    if (s[i] == s[j])
    return (3); /* 同一の数字が含まれている */
    }

    return (0); /* 文字列は妥当 */
    }

    /*— ヒット&ブローの判定 —*/
    void judge(const char s[], const int 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] == '0' + no[j]) /* 数字が一致 */
    if (i == j)
    (*hit)++; /* ヒット(位置も一致) */
    else
    (*blow)++; /* ブロー(位置が不一致) */
    }
    }
    }

    /*— 判定結果を表示 —*/
    void print_result(int snum, int spos)
    {
    if (spos == 4)
    printf("正解です!!");
    else if (snum == 0)
    printf("  それらの色はまったく含まれません。\n");
    else {
    printf("  それらの色中%d個の色が含まれます。\n", snum);

    if (spos == 0)
    printf("  ただし位置もあっている色はありません。\n");
    else
    printf("  その中の%d個は位置もあっています。\n", spos);
    }
    putchar('\n');
    }

    int main(void)
    {
    int try_no = 0; /* 入力回数 */
    int chk; /* 入力された文字列のチェック結果 */
    int hit; /* 位置も数字も当たっている個数 */
    int blow; /* 数字が当たって位置が当たっていない数字の個数 */
    int no[4]; /* 当てる数字の並び */
    char buff[10]; /* 読み込む数字の並びを格納する文字列 */
    clock_t start, end; /* 開始時刻・終了時刻 */

    srand(time(NULL)); /* 乱数の種を初期化 */

    puts("■ マスターマインドをしましょう。");
    puts("■ 四つの色の並びを当ててください。");
    puts("■ 0:白,1:黒,2:赤,3:青,4:黄,5:緑,6:橙,7:茶");
    puts("■ 同じ色が複数含まれることはありません。");
    puts("■ 4307のように連続して数字で入力してください。");
    puts("■ スペース文字などを入力してはいけません。\n");

    make4digits(no); /* 相異なる四つの数字の並びを生成 */

    start = clock(); /* 計測開始 */

    do {
    do {
    printf("入力してください:");
    scanf("%s", buff); /* 文字列として読み込む */

    chk = check(buff); /* 読み込んだ文字列をチェック */

    switch (chk) {
    case 1: puts("\aきちんと4文字で入力してください。"); break;
    case 2: puts("\a数字以外の文字を入力しないでください。"); break;
    case 3: puts("\a同一の数字を複数入力しないでください。"); break;
    }
    } while (chk != 0);

    try_no++;
    judge(buff, no, &hit, &blow); /* 判定 */
    print_result(hit + blow, hit); /* 判定結果を表示 */

    } while (hit < 4);

    end = clock(); /* 計測終了 */

    printf("%d回かかりました。\n所要時間は%.1f秒でした。\n",
    try_no, (double)(end – start) / CLOCKS_PER_SEC);

    return (0);
    }
    [EOF]

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *