明解C言語中級編 9章の自由課題1~3を簡易版で解いた

うーむむ、難しい。
バイナリファイルの操作はまったく分からんかったので、入門編を復習してから再チャレンジしてなんとかできた程度。入門編のときもこの辺は端折っていたような気がする(おい)。

そして問題はこんな感じ。

課題9-1 P298のラックナンバーサーチを拡張して、最高点だけでなくてこれまでのベスト10と最近の10回の点数、それらの実行日時を記録できるようにしたプログラムを作成せよ。
課題9-2 9-1のプログラムにダブルナンバーサーチを追加したプログラムを作成せよ。
課題9-3 作成したプログラムの情報の記録をテキストファイルではなく、バイナリファイルに対しておこなうように変更せよ。

ってな感じですが、この3つを合わせて簡単にしてみたのです。

P298のラックナンバーサーチを拡張して、過去の実行記録と点数を記録して、最高得点を表示するように作成する。データの書き込みはバイナリファイルでおこなうように。
ダブルナンバーサーチを追加するのはスルー!

ってな感じにしてみました。かなり簡単にシンプルになってしまっているけど、とりあえず今はまぁいい!とします。
このままでは終わらないぞ~。という気持ちだけもっておこう。
分からないまま終わる。そんなのはいやだ!ってな感じで。
だったら今やれよという突っ込みは受け流します

バイナリの部分を入門編の教法で復習したときに、わりと苦労した入門編の問題をえらく簡単に感じたので、だったらこの本が終わったら次はポインタの教本をやる予定なので、その教本を進めていたら今解けない問題も簡単になっているはず!という超楽観的な感じで思っています。

向こうが曲がれるコーナーなら、同じスピードでこっちも曲がれるはずじゃないかな・・・っていうイニD理論に近いです。

そーす  かぼちゃさんからご指摘いただいて修正しますた。

// ラックナンバーサーチ 前回の日時、最高得点を求める。

#include <stdio.h>
#include <time.h>
#include <float.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/types.h> 
#include <unistd.h>

#define MAX_STAGE       10
#define swap(type, x, y)        do{ type t = x; x = y; y = t; } while (0)
#define MAX_NUM         10

char dtfile[] = "LACKNUM.DAT";  // ファイル名
char dtfile2[] = "LACKNUM2.DAT"; // 最高記録用のファイル
double score2;

// 過去のとれーにんぐ情報を取得・表示して得点を返す。

double get_data(void)
{
        FILE *fp, *fp2;
        double best, best2;             //最高得点

        if((fp = fopen(dtfile, "rb")) == NULL){
                printf("ファイルを作成します。\n\n");
                best = DBL_MAX;
        }else{
                int i;
                struct tm local;
                double line[256];

                printf("\n過去の履歴\n-------------------------- \n");

                while((i = fread(&local, sizeof(struct tm), 1, fp)) > 0 ){
                        printf("%d年 %d月 %d日 %d時 %d分 %d秒\n",
                                local.tm_year + 1900, local.tm_mon + 1,
                                local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
                fread(&best, sizeof(double), 1, fp);
                        printf("得点(所要時間)は%.1f秒\n\n", best);
                }
                fclose(fp);
        }

        if((fp2 =fopen(dtfile2, "rb")) == NULL){
                printf("ファイルを作成します。 \n\n");
                best = DBL_MAX;
        }else{
                struct tm local2;

                 fread(&local2, sizeof(struct tm), 1, fp2);
                        printf("最高記録は%d年 %d月 %d日 %d時 %d分 %d秒\n",
                                local2.tm_year + 1900, local2.tm_mon + 1,
                                local2.tm_mday, local2.tm_hour, local2.tm_min, local2.tm_sec);
                fread(&best2, sizeof(double), 1, fp2);
                        printf("得点(所要時間)は %.1f秒です。\n", best2);
        fclose(fp2);
    }

        return (best);
}

// 今回のトレーニング情報を書き込む
void put_data(double best, double best2)
{
        FILE *fp, *fp2;
        time_t t = time(NULL);
        struct tm *local = localtime(&t);

        if((fp = fopen(dtfile, "ab")) == NULL){
                printf("ファイルがあーりません");
                fflush(stdout);
        }else{
                fwrite(local, sizeof(struct tm), 1, fp);
                fwrite(&best, sizeof(double), 1, fp);
                fclose(fp);
        }

        if(best <= best2){
                if((fp2 = fopen(dtfile2, "wb")) ==NULL){
                        printf("ファイルがあーりません");
                        fflush(stdout);
                }else{
                        fwrite(local, sizeof(struct tm), 1, fp2);
                        fwrite(&best2, sizeof(double), 1, fp2);
                        fclose(fp2);
                }
        }

}

// トレーニングを実行して得点を返す。
double go(void)
{
        int i, j, stage;
        int dgt[9] = {1,2,3,4,5,6,7,8,9};
        int a[8];
        double jikan;                   // 時間;
        clock_t start, end;             // 開始、終了時刻

        printf("欠けている数字を入力してください。\n");
        printf("スペース>エンターで練習開始\n");
        while(getchar() != ' ')
                ;

        start = time(NULL);

        for(stage = 0; stage < MAX_STAGE; stage++){
                int x = rand() % 9; // 0~8の乱数を発生
                int no;                 // 読み込んだ値

                i = j = 0;
                while(i < 9){
                        if(i != x)              //dgt[x]を飛ばしてコピー
                                a[j++] = dgt[i];
                        i++;
                }

                for(i = 7; i > 0; i--){         // 配列aをコピー
                        int j = rand() % (i + 1);
                        if(i != j)
                                swap(int , a[i], a[j]);
                }

                printf("%d回目:", stage+1);
                for(i = 0; i < 8; i++)                  //全要素を表示
                        printf("%d", a[i]);
                printf(" : ");

                do{
                        scanf("%d", &no);
                }while (no != dgt[x]);
        }

        end = time(NULL);

        jikan = (double)difftime(end, start);

        printf("%.1f秒かかりました。\n", jikan);

        if(jikan > 30.0)
                printf("おそい?。\n");
        else if(jikan > 25.0)
                printf("もうちょいがんばれ。 \n");
        else if(jikan > 15.0)
                printf("いいね。 \n");

        return (jikan);
}

int main(void){

        int retry;                      // もう1度?
        double score;           // 得点
        double best;            // 最高得点

        best = get_data();

        srand(time(NULL)*getpid());

        score = go();                   // トレーニング実行

        if(score < best){
                printf("最高得点(所要時間)を更新しました。\n\r");
                best = score;
        }

        put_data(score, best);

        return 0;
}

実行結果

$ ./a.out

過去の履歴
--------------------------
2014年 3月 23日 19時 53分 51秒
得点(所要時間)は33.0秒

2014年 3月 23日 19時 54分 55秒
得点(所要時間)は49.0秒

2014年 3月 23日 19時 56分 9秒
得点(所要時間)は42.0秒

2014年 3月 23日 19時 58分 48秒
得点(所要時間)は48.0秒

2014年 3月 23日 20時 0分 27秒
得点(所要時間)は35.0秒

2014年 3月 23日 20時 1分 9秒
得点(所要時間)は29.0秒

2014年 3月 23日 20時 3分 39秒
得点(所要時間)は39.0秒

2014年 3月 24日 8時 34分 53秒
得点(所要時間)は41.0秒

最高記録は2014年 3月 23日 20時 1分 9秒
得点(所要時間)は 29.0秒です。
欠けている数字を入力してください。
スペース>エンターで練習開始

ランキングに関しては、ポインタと構造体を使っている方法があるらしいけど、よくわからんので、別の方法を考えたけどうまくいかなかった。

いまいろいろと考えていることを実行するにはまだまだ時間がかかりそうだわい。

くやじいなあ。

 

Related Posts


投稿者: Takeken

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

「明解C言語中級編 9章の自由課題1~3を簡易版で解いた」への3件のフィードバック

  1. l.57: fclose(fp2);
    の位置がおかしいです.

    l.44: if((fp2 =fopen(dtfile2, “rb”)) == NULL){
    でファイルが存在せず,オープンできなかったときもクローズしようとするのでセグメントフォルトを起こします.

    l.56とl.57を入れ替えることで解決します.

    今からソースで遊ばせてもらいます〜.

    1. モジュールが強く結合しているような気がして,結合度をさげてみようかと思いましたが,最終的にfreadのラッパができただけでした(笑

      しいて明らかな問題をあげるなら,先のコメントの内容と,Linux環境からではgetpid()を呼ぶためにunistd.hとsys/types.hが必要なことくらいでしょうか.

      1. こんばんわ。
        >l.57: fclose(fp2);
        >の位置がおかしいです.
        おお(´・ω・`)
        ほんとですね。。

        >しいて明らかな問題をあげるなら,先のコメントの内容と
        >Linux環境からではgetpid()を呼ぶためにunistd.hとsys/types.hが必要
        まっまじですか!
        ↓ で調べてみましたら
        getpid
        おおおおー((+_+))
        ありがとうございます。。mm

        コンパイルエラーなし+デバッグ少々で、ダメだこりゃですね(笑)

コメントを残す

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