C入門9 課題解答

1. 次のプログラムを実行するとどうなるでしょうか。

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

void saikoro(void){
    printf("さいころを振るよ〜\n");
    printf("ころころころ...\n");
    printf("出た目は%dです。\n", rand() % 6 + 1);
}

int main(void)
{
    srand( (unsigned)time( NULL ) );
    saikoro();
    return 0;
}

  「さいころを振るよ〜
   ころころ...
   出た目は3です。」

  のように出力される。ただし、整数は1〜6のどれか。

2. 実行すると、今日のパワーとラッキー度が表示される関数omikuji2を書いて、
  それを使うプログラムを書いてください。
  パワーとラッキー度は、1から100までとします。

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

void omikuji2(void){
    printf("今日のパワー  :%d\n", rand() % 100 + 1);
    printf("今日のラッキー度:%d\n", rand() % 100 + 1);
}

int main(void)
{
    srand( (unsigned)time( NULL ) );
    omikuji2();
    return 0;
}

3. 「入門9にある古典的なおみくじ」と「今日のパワーとラッキー度が表示されるおみくじ」を
  選択できるプログラムを書いてください。ただし、入門9の関数omikujiと問2のomikuji2を
  使うようにしてください。

(ヒント)
mainは次のように書けます。

int main(void)
{
    int a;
    srand( (unsigned)time( NULL ) );
    printf("どちらにしますか?\n");
    printf("1 古典的なおみくじ 2 パワーとラッキー度\n");
    scanf("%d", &a);
    if(a == 1){
        omikuji();
    }
    else if(a == 2){
        omikuji2();
    }
    return 0;
}

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

void omikuji(void){
    switch(rand() % 5){
        case 0:
            printf("大吉\n");
            break;
        case 1:
            printf("吉\n");
            break;
        case 2:
            printf("普通\n");
            break;
        case 3:
            printf("凶\n");
            break;
        case 4:
            printf("大凶\n");
            break;
    }
}

void omikuji2(void){
    printf("今日のパワー  :%d\n", rand() % 100 + 1);
    printf("今日のラッキー度:%d\n", rand() % 100 + 1);
}

int main(void)
{
    int a;
    srand( (unsigned)time( NULL ) );
    printf("どちらにしますか?\n");
    printf("1 古典的なおみくじ 2 パワーとラッキー度\n");
    scanf("%d", &a);
    if(a == 1){
        omikuji();
    }
    else if(a == 2){
        omikuji2();
    }
    return 0;
}

4. 問3では、入門9の関数omikujiをそのまま使いました。
  しかし、上の最初の図のように、「古典的なおみくじ」の結果は、なんだかさみしいですね。
  そこで、関数omikujiを少し改良して、出力がもう少しはでに(?)なるようにしてください。

omikujiを以下のように改良する。

void omikuji(){
    printf("おみくじの結果、今日のあなたは...\n");
    switch(rand() % 5){
        case 0:
            printf("  大吉\n");
            break;
        case 1:
            printf("  吉\n");
            break;
        case 2:
            printf("  普通\n");
            break;
        case 3:
            printf("  凶\n");
            break;
        case 4:
            printf("  大凶\n");
            break;
    }
    printf("です。\n");
}

ここで、プログラムの他の部分には手を触れていないことに注意してください。

5. 問4のプログラムをさらに改良し、「コンピュータがユーザとじゃんけんをし、その結果を表示する」
  機能も付け加えてください。
  ただし、この機能は、jankenという名前の関数で、すでに以下のように書かれているとします。
  これを使ってプログラムを書いてください。

void janken(void){
    int user, comp;
    printf("では、じゃんけんです。何を出しますか?\n");
    printf("1 グー 2 チョキ 3 パー\n");
    scanf("%d", &user);
    comp = rand() % 3 + 1;
    if(comp == 1){
        if(user == 1){
            printf("あなたはグー。私はグー。ひきわけですね。\n");
        }
        else if(user == 2){
            printf("あなたはチョキ。私はグー。私の勝ちですね。\n");
        }
        else if(user == 3){
            printf("あなたはパー。私はグー。あなたの勝ちです。\n");
        }
    }
    else if(comp == 2){
        if(user == 1){
            printf("あなたはグー。私はチョキ。あなたの勝ちです。\n");
        }
        else if(user == 2){
            printf("あなたはチョキ。私はチョキ。ひきわけですね。\n");
        }
        else if(user == 3){
            printf("あなたはパー。私はチョキ。私の勝ちですね。\n");
        }
    }
    else if(comp == 3){
        if(user == 1){
            printf("あなたはグー。私はパー。私の勝ちですね。\n");
        }
        else if(user == 2){
            printf("あなたはチョキ。私はパー。あなたの勝ちです。\n");
        }
        else if(user == 3){
            printf("あなたはパー。私はパー。ひきわけですね。\n");
        }
    }
}

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

void omikuji(void){
    printf("おみくじの結果、今日のあなたは...\n");
    switch(rand() % 5){
        case 0:
            printf("  大吉\n");
            break;
        case 1:
            printf("  吉\n");
            break;
        case 2:
            printf("  普通\n");
            break;
        case 3:
            printf("  凶\n");
            break;
        case 4:
            printf("  大凶\n");
            break;
    }
    printf("です。\n");
}

void omikuji2(void){
    printf("今日のパワー  :%d\n", rand() % 100 + 1);
    printf("今日のラッキー度:%d\n", rand() % 100 + 1);
}

void janken(void){
    /* userはユーザの手、compはコンピュータの手 */
    int user, comp;
    printf("では、じゃんけんです。何を出しますか?\n");
    printf("1 グー 2 チョキ 3 パー\n");
    scanf("%d", &user);      /* ユーザが手を入力 */
    comp = rand() % 3 + 1;  /* コンピュータの手は乱数で決める */
    if(comp == 1){
        if(user == 1){
            printf("あなたはグー。私はグー。ひきわけですね。\n");
        }
        else if(user == 2){
            printf("あなたはチョキ。私はグー。私の勝ちですね。\n");
        }
        else if(user == 3){
            printf("あなたはパー。私はグー。あなたの勝ちです。\n");
        }
    }
    else if(comp == 2){
        if(user == 1){
            printf("あなたはグー。私はチョキ。あなたの勝ちです。\n");
        }
        else if(user == 2){
            printf("あなたはチョキ。私はチョキ。ひきわけですね。\n");
        }
        else if(user == 3){
            printf("あなたはパー。私はチョキ。私の勝ちですね。\n");
        }
    }
    else if(comp == 3){
        if(user == 1){
            printf("あなたはグー。私はパー。私の勝ちですね。\n");
        }
        else if(user == 2){
            printf("あなたはチョキ。私はパー。あなたの勝ちです。\n");
        }
        else if(user == 3){
            printf("あなたはパー。私はパー。ひきわけですね。\n");
        }
    }
}

int main(void)
{
    int a;
    srand( (unsigned)time( NULL ) );
    printf("どれにしますか?\n");
    printf("1 古典的なおみくじ 2 パワーとラッキー度 3 じゃんけんで運試し\n");
    scanf("%d", &a);
    if(a == 1){
        omikuji();
    }
    else if(a == 2){
        omikuji2();
    }
    else if(a == 3){
        janken();
    }
    return 0;
}

  ずいぶん長いプログラムになりました。しかし、各部分の意味がはっきりしていて、
  わかりやすいプログラムではないでしょうか。

6. 問5のプログラムを見て、「関数を書くことのメリット」を論じてください。

  関数を書くことで、プログラムをブロック化することができます。
  kadai9_5.cの例では、omikuji(「古典的おみくじ」の部分)、
  omikuji2(「パワー・ラッキー度おみくじ」の部分)、janken(「じゃんけん」の部分)、
  そして、mainの部分がブロックです。
  長いプログラムですが、構造がはっきりしているので、わかりやすいプログラムに
  なっているのではないでしょうか。
  おかげで、変更も楽にできるはずです。
  つまり、たとえば、「パワー・ラッキー度おみくじ」をよりよくしたい場合、
  関数omikuji2の中身を変更するだけでよいのです。

7. 問5の関数jankenを、機能を変えずに、もう少し短く書き直してください。
  ポイントは、「同じものの繰り返し」をなるべく減らすということです。

  いろいろ考えられますが、ここでは、「手の表示」「勝敗の表示」部分で繰り返しを
  なくしてみます。たとえば、jankenを次のように書き換えることができるでしょう。
  ただし、変数kekkaは、じゃんけんの結果を保持する変数で、0なら「引き分け」、
  1なら「ユーザの勝ち」、2なら「コンピュータの勝ち」とします。

void janken(void){
    /* userはユーザの手、compはコンピュータの手、kekkaは結果 */
    /* kekkaは、ひきわけなら0、ユーザの勝ちなら1、コンピュータが勝ちなら2とする */
    int user, comp, kekka;
    char* te[3] = {"グー", "チョキ", "パー"};
    char* kekka_hyouji[3]
                = {"ひきわけですね。", "あなたの勝ちです。", "私の勝ちです。"};

    printf("では、じゃんけんです。何を出しますか?\n");
    printf("1 グー 2 チョキ 3 パー\n");
    scanf("%d", &user);      /* ユーザが手を入力 */
    comp = rand() % 3 + 1;  /* コンピュータの手は乱数で決める */
    if(comp == 1){
        if(user == 1) kekka = 0;
        else if(user == 2) kekka = 2;
        else if(user == 3) kekka = 1;
    }
    else if(comp == 2){
        if(user == 1) kekka = 1;
        else if(user == 2) kekka = 0;
        else if(user == 3) kekka = 2;
    }
    else if(comp == 3){
        if(user == 1) kekka = 2;
        else if(user == 2) kekka = 1;
        else if(user == 3) kekka = 0;
    }
    printf("あなたは%s。わたしは%s。\n%s\n",
            te[user - 1], te[comp - 1], kekka_hyouji[kekka]);
}

  勝敗の判定で、省略できる中カッコをはずしてみましたが、これは、本質的な
  書き直しではありません。(単に、見やすくしたかっただけです。)

  勝敗を判定したら、その結果を変数kekkaに代入するようにしました。
  手や勝敗表示に使う文字列(ただしくは、「文字列へのポインタ」)は、あらかじめ、
  te、kekka_hyoujiという配列に格納しておき、それをuser、comp、kekkaに
  もとづいて表示しているのです。これで、「グー」とか「あなたの勝ちです。」のような
  決まりきった文字列を、プログラマが何度も書かなくてすむわけです。
  ただし、teの配列要素は、te[0]、te[1]、te[2]であり、userやcompは、1、2、3の
  整数であるため、1減らして、te[user - 1]、te[comp - 1]を表示するようにしている
  点に注意してください。

  なお、関数が呼び出されるたびに、teとkekka_hyoujiがあらためて初期化されるのは、
  あまり効率的ではないかもしれません。(今の場合、実際的な影響はありませんが。)
  実は、これらを

    static char* te[3] =  ...;
    static char* kekka_hyouji[3] = ...;

  とすれば、teとkekka_hyoujiは、プログラム実行時に一度だけ初期化されることに
  なります。これは、入門11で説明する予定です。

  勝敗判定も、工夫すれば、もう少し簡単にできるかもしれません。
  しかし、それは、この入門では扱わないことにします。

  いずれにしても、jankenという関数を作ったおかげで、あとで、jankenだけ改良する
  ことができるのです。すばらしいですよね。


課題9

C入門9
C入門目次
ホーム