明解C言語中級編 6章の自由課題解いてみた 後編

やっと6章が終わった~。main関数以外を作るのも少しは慣れたかなと思ったけど、最後のジャッジの部分はmain関数の中に書いてしまった。
課題6-7は1章~6章までの内容をフル活用したらかなり色々とできるんだけど、とりあえず最低限度の内容になっております(笑)

そして、7章以降からまた今までと違う感じが続くようだね。踏まえた内容ではあるんだろうけどさ。んでもって、あとの8~10章でも構造体は全然でてこないので、次の本に期待だね。

 

問題6-7 1章のような数当てゲームを例にして、日付当てゲームを作成せよ。

そーす

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

int y_answer, m_answer, d_answer;
int mday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int mdays;

void initialize(void);
void select_answer(void);
void check_day(int y, int m);
int dayofweek(int year, int month, int day);
int is_leap(int year);
int monthdays(int year, int month);

int main(void)
{

  int y, m, d;
  int year, day;
  int retry = 1;

  initialize();

  printf("何年? :");
  scanf("%d", &y);
  printf("年月? :");
  scanf("%d", &m);
  printf("何日? :");
  scanf("%d", &d);
  putchar('\n');

  if (m < 0 || m > 12)
  {
    fprintf(stderr, "月の値が不正だよ。\n");
    return 1;
  }
  if (y < 0)
  {
    fprintf(stderr, "年の値が不正だよ。\n");
    return 1;
  }
  if (d < 0 || d > 31)
  {
    fprintf(stderr, "日の値が不正だよ。\n");
    return 1;
  }

  printf("あなたが選んだのは\n%d年%d月%d日ですね。\n\n", y, m, d);

  check_day(y_answer, m_answer);

  do
  {
    select_answer();
  } while (d_answer < mdays);

  //      printf("randamに選んだのは\n%d年%d月%d日でした。\n\n", y_answer, m_answer, d_answer); //デバッグ確認用

  do
  {
    if (y_answer == y & m_answer == m & d_answer == d)
    {
      puts("正解です。おめでとう。");
      break;
    }
    else if (y_answer > y)
    {
      puts("年はもっと大きいです。");
    }
    else if (y_answer < y)
    {
      puts("年はもっと小さいです。");
    }
    else if (y_answer == y)
    {
      puts("年は一致しました。");
    }

    if (m_answer > m)
    {
      puts("月はもっと大きいです。");
    }
    else if (m_answer < m)
    {
      puts("月はもっと小さいです。");
    }
    else if (m_answer == m)
    {
      puts("月は一致しました。");
    }

    if (d_answer > d)
    {
      puts("日はもっと大きいです。");
    }
    else if (d_answer < d)
    {
      puts("日はもっと小さいです。");
    }

    printf("\n続けるなら1を押してエンター :");
    scanf("%d", &retry);
    if (retry != 1)
      break;

    printf("何年? :");
    scanf("%d", &y);
    printf("年月? :");
    scanf("%d", &m);
    printf("何日? :");
    scanf("%d", &d);
    putchar('\n');

    if (m < 0 || m > 12)
    {
      fprintf(stderr, "月の値が不正だよ。\n");
      return 1;
    }
    if (y < 0)
    {
      fprintf(stderr, "年の値が不正だよ。\n");
      return 1;
    }
    if (d < 0 || d > 31)
    {
      fprintf(stderr, "日の値が不正だよ。\n");
      return 1;
    }

    printf("あなたが選んだのは\n%d年%d月%d日ですね。\n\n", y, m, d);

  } while (retry == 1);

  return 0;
}

//初期化、必要か分からないけど・・。
void initialize(void)
{

  y_answer = 0;
  m_answer = 0;
  d_answer = 0;
  srand(time(NULL));

  printf("年月日を当ててみてください。\n");
}

//答えの日付をランダムでだいたいで取得。
void select_answer(void)
{

  time_t t = time(NULL);
  struct tm *local = localtime(&t);

  srand(time(NULL));

  y_answer = rand() % 6 + 2009;
  m_answer = rand() % 12 + 1;
  d_answer = rand() % 31 + 1;
}

//だいたいで取得した日付が実在するかチェック。
void check_day(int y, int m)
{

  int i;
  int wd = dayofweek(y, m, 1); //1日の曜日
  mdays = monthdays(y, m);     //日数
}

int dayofweek(int year, int month, int day)
{
  if (month == 1 || month == 2)
  {
    year--;
    month += 12;
  }
  return ((year + year / 4 - year / 100 + year / 400 + (13 * month + 8) / 5 + day) % 7);
}

int is_leap(int year)
{
  return (year % 4 == 0 & year % 100 != 0 || year % 400 == 0);
}

int monthdays(int year, int month)
{
  if (month-- != 2)
    return (mday[month]);
  return (mday[month] + is_leap(year));
}

実行結果 ※デバッグ用の解答付き。

$ ./a.out
年月日を当ててみてください。
何年? :2013
年月? :5
何日? :15

あなたが選んだのは
2013年5月15日ですね。

randamに選んだのは
2012年3月28日でした。

年はもっと小さいです。
月はもっと小さいです。
日はもっと大きいです。

続けるなら1を押してエンター :1
何年? :2010
年月? :1
何日? :15

あなたが選んだのは
2010年1月15日ですね。

年はもっと大きいです。
月はもっと大きいです。
日はもっと大きいです。

続けるなら1を押してエンター :1
何年? :2011
年月? :3
何日? :20

あなたが選んだのは
2011年3月20日ですね。

年はもっと大きいです。
月は一致しました。
日はもっと大きいです。

続けるなら1を押してエンター :1
何年? :2012
年月? :3
何日? :25

あなたが選んだのは
2012年3月25日ですね。

年は一致しました。
月は一致しました。
日はもっと大きいです。

続けるなら1を押してエンター :1
何年? :2012
年月? :3
何日? :27

あなたが選んだのは
2012年3月27日ですね。

年は一致しました。
月は一致しました。
日はもっと大きいです。

続けるなら1を押してエンター :1
何年? :2012
年月? :3
何日? :28

あなたが選んだのは
2012年3月28日ですね。

正解です。おめでとう。

とりあえず進むよ~。

 

2015/04/19

1年以上も前のものですが新しくコメントいただいたので少し追記します。

ひさしぶりのC言語でしたが、Rubyでプログラミングじたいはやっているおかげかだいたいは読めました。
解いてみたって・・解けてねーしw
使ってない変数があったり、何だか良く分からないものがあったり、上手く使えてない関数があったりと、かなりはちゃめちゃでした。
aridaiさん、どうもありがとうございます。

バリデーションというのかな。バリデーションは全然できていませんが動くようにはなりました。

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

int y_answer, m_answer, d_answer;
int mday[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int mdays;

void initialize(void);
void select_answer(void);
void check_day(int y, int m);
//int dayofweek(int year, int month, int day);
int is_leap(int year);
int monthdays(int year, int month);

int main(void){

        int y, m, d;
        int year, day;
        int retry=1;

        initialize();

        printf("何年? :"); scanf("%d", &y);
        printf("年月? :"); scanf("%d", &m);
        printf("何日? :"); scanf("%d", &d);
        putchar('\n');

        if(m < 0 || m > 12){
                fprintf(stderr, "月の値が不正だよ。\n");
                return 1;
        }
        if(y < 0){
                fprintf(stderr, "年の値が不正だよ。\n");
                return 1;
        }
        if(d < 0 || d > 31){
                fprintf(stderr, "日の値が不正だよ。\n");
                return 1;
        }

        printf("あなたが選んだのは\n%d年%d月%d日ですね。\n\n", y, m, d);

        printf("日付を抽選中\n");
        select_answer();
        check_day(y_answer, m_answer);

        //デバッグように答え表示
        //printf("randamに選んだのは\n%d年%d月%d日でした。\n\n", y_answer, m_answer, d_answer);

        do{
          if(y_answer == y && m_answer == m && d_answer == d){
            puts("正解です。おめでとう。");
            break;
          }else if(y_answer > y){
            puts("年はもっと大きいです。");
          }else if(y_answer < y){
            puts("年はもっと小さいです。");
          }else if(y_answer == y){
            puts("年は一致しました。");
          }

          if(m_answer > m){
            puts("月はもっと大きいです。");
          }else if(m_answer < m){
            puts("月はもっと小さいです。");
          }else if(m_answer == m){
            puts("月は一致しました。");
          }

          if(d_answer > d){
            puts("日はもっと大きいです。");
          }else if(d_answer < d){
            puts("日はもっと小さいです。");
          }else if(d_answer == d){
            puts("日は一致しました。");
          }

          printf("\n続けるときは1を押してエンターを押してね :");
          scanf("%d", &retry);
          if(retry != 1) break;

          printf("何年? :"); scanf("%d", &y);
          printf("年月? :"); scanf("%d", &m);
          printf("何日? :"); scanf("%d", &d);
          putchar('\n');

            if(m < 0 || m > 12){
                fprintf(stderr, "月の値が不正だよ。\n");
                return 1;
            }
            if(y < 0){
                fprintf(stderr, "年の値が不正だよ。\n");
                return 1;
            }
            if(d < 0 || d > 31){
                fprintf(stderr, "日の値が不正だよ。\n");
                return 1;
            }

            printf("あなたが選んだのは\n%d年%d月%d日ですね。\n\n", y, m, d);

        }while(retry == 1);

        return 0;
}

//初期化、必要か分からないけど・・。
void initialize(void){
  srand(time(NULL));
  printf("年月日を当ててみてください。\n");
}

//答えの日付をランダムでだいたいで取得。
void select_answer(void)
{
  time_t t=time(NULL);
  struct tm *local=localtime(&t);

  srand(time(NULL));
  y_answer = rand() % 6 + 2009;
  m_answer = rand() % 12 + 1;
  d_answer = rand() % 31 + 1;
}

//だいたいで取得した日付が実在する日付かチェック。
void check_day(int y, int m)
{
  int i;
  mdays = monthdays(y, m); //日数
}

int is_leap(int year)
{
  return("year%4 == 0" && "year%100 != 0" || "year%400 == 0");
}

int monthdays(int year, int month)
{
  if(month-- != 2)
    return (mday[month]);
  return (mday[month] + is_leap(year));
}

ちょっと遊んでみました。

 
$ ./a.out
年月日を当ててみてください。
何年? :2011
年月? :12
何日? :12

あなたが選んだのは
2011年12月12日ですね。

日付を抽選中
年はもっと小さいです。
月はもっと小さいです。
日はもっと大きいです。

続けるときは1を押してエンターを押してね :1
何年? :2009
年月? :7
何日? :24

あなたが選んだのは
2009年7月24日ですね。

年はもっと大きいです。
月はもっと大きいです。
日はもっと大きいです。

続けるときは1を押してエンターを押してね :1
何年? :2013
年月? :9
何日? :27

あなたが選んだのは
2013年9月27日ですね。

年はもっと小さいです。
月はもっと大きいです。
日はもっと小さいです。

続けるときは1を押してエンターを押してね :1
何年? :2012
年月? :11
何日? :2

あなたが選んだのは
2012年11月2日ですね。

年はもっと小さいです。
月はもっと小さいです。
日はもっと大きいです。

続けるときは1を押してエンターを押してね :1
何年? :2011
年月? :10
何日? :25

あなたが選んだのは
2011年10月25日ですね。

年はもっと小さいです。
月は一致しました。
日は一致しました。

続けるときは1を押してエンターを押してね :1
何年? :2010
年月? :10
何日? :25

あなたが選んだのは
2010年10月25日ですね。

正解です。おめでとう。

Related Posts


投稿者: Takeken

インターネット利用者のITリテラシーを向上したいという設定の2次元キャラです。 サーバー弄りからプログラミングまで手を付けた自称エッセイストなたけけんの物語。

「明解C言語中級編 6章の自由課題解いてみた 後編」への2件のフィードバック

  1. 私の記憶が正しければ、
    initialize関数でグローバル変数を0で初期化させていますが、
    グローバル変数は宣言するときに自動で0で初期化されたと思います。

    1. aridai さん

      コメントどうもありがとうございました。
      仰るとおりInitializeの初期化も不要でしたっ!
      なによりひさしぶりにCをさわって楽しかったです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です