メニューを常に表示させたい。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
cale

Re: メニューを常に表示させたい。

#31

投稿記事 by cale » 14年前

softya(ソフト屋) さんが書きました: (1) 西暦の入力。エラーなら(1)に戻る。
(1.5)MENU操作 s:(1)へ b:(1)へ g:(2)へ c:エラーなら(1)へ OKなら(3)へ m:メニューの一覧表示して(1.5)へ x:終了へ
以下同様。quote]
見直したらそうでした。
すいません。
select_1(MENU,INPUT_YEAR,INPUT_YEAR,INPUT_MONTH,ERROR,END,ERROR);
で次のメニューを決めているので出来るとは思いますが、それで操作に問題がないか一度仕様を書いてみてください。
ここはまだ、RorW以降ができてないのでまだ、これだ!っていう仕様を決めかねてます。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: メニューを常に表示させたい。

#32

投稿記事 by softya(ソフト屋) » 14年前

cale さんが書きました:ここはまだ、RorW以降ができてないのでまだ、これだ!っていう仕様を決めかねてます。
仕様というのは作る前に決めるものですよ。
とりあえず問題があるかも知れないが、とりあえず「これなら行けそうだ」と言うレベルで決めてしまわないと作る予定・スケジュールが立ちません。
それが設計であり、仕様の策定です。

RorW以降の掘り下げが足らないのでは無いのですか?
コンソールで行う操作を仮想的に書いてみてください。
見直したらそうでした。
すいません。
現状のプログラムはそうなっていませんので、何処が悪いか何処を直すべきか見直してみてください。
私は仕様を整理してみるとstate MENUは無い方が良かったと言えると思います。
mを押したらメニュー項目一覧を表示するだけで良いので、select内で完結できたのでは?
※ メニュー項目一覧の関数化が放置されますが、関数化をお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

cale

Re: メニューを常に表示させたい。

#33

投稿記事 by cale » 14年前

関数化忘れてました一番下にこれ追加です。

コード:

/*==============================================================*/
/*                      MENU表示                                */
/*==============================================================*/ 

int menuprint(int)
{
			printf("\n***********メモ機能付きカレンダー************\n\n");
			printf("* * * * * * * * * M E N U * * * * * * * * * *\n");
			printf("*   (注)スペース等は入力しないでください    *\n");
			printf("*                                           *\n");
			printf("*      最初から入力の場合は 「s」を入力     *\n");
			printf("*      前に戻りたい場合は   「b」を入力     *\n");
			printf("*      次の処理に行くには   「g」を入力     *\n");
			printf("*      メニューの確認には   「m」を入力     *\n");
			printf("*      カレンダーの確認は   「c」を入力     *\n");
			printf("*      プログラムの終了は   「x」を入力     *\n");
			printf("* * * * * * * * * * * * * * * * * * * * * * *\n\n");

			return 0;

}
MENUは関数でなんとかできました。
case MENUのstateの値を、if~でstate(1,2,3)の切替を行えばなんとか先ほどの3と4で分けれそうです。

コンソールだとこのような感じで表示させたいです。

******2011年6月*****
日 月 火 水 木 金 土
--------------------
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
---------------------
と表示されたあとですが。

RorW?>>W
メニュー処理(カレンダー表示後)
何日に書きこむ?>>16
メニュー処理(カレンダー表示後)
メモ(50文字まで)>>abc

******2011年6月*****
日 月 火 水 木 金 土
--------------------
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 *16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
--------------------

メニュー処理
西暦からか、RorWからか、終了か。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: メニューを常に表示させたい。

#34

投稿記事 by softya(ソフト屋) » 14年前

case MENUのstateの値を、if~でstate(1,2,3)の切替を行えばなんとか先ほどの3と4で分けれそうです。
それよりは、select()関数内でmが押されたらmenuprint()して再び
printf("操作を「M E N U」から選んでください>>");
にもどる方が良いと思うのですが。

あと、後半の流れですが
RorW?>>W
Rの時はどうなるのでしょうか?

そして、
******2011年6月*****
日 月 火 水 木 金 土
--------------------
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 *16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
--------------------
の*マークの位置は既にメモが記録されていた場合は、最初のカレンダー表示の時点でマークは表示されているんですよね?
何時ファイルをチェックするのでしょうか?
幾つも日付にマークされる場合も当然有りますよね?

※ 今気づいたが、W時に既にその日付にメモが書いてあったらどうしましょう?

それと
メニュー処理(カレンダー表示後)
メニュー処理
西暦からか、RorWからか、終了か。
これもちゃんと書いてみてください。
曖昧だとイメージもはっきりしないのでプログラム化がやはり出来ません。

どうです?仮想的にでも書いてみると色々見えてきませんか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

cale

Re: メニューを常に表示させたい。

#35

投稿記事 by cale » 14年前

RorW>>
R処理→(1)日付選択、*の有無でエラー(1)か(1.5)へ
(1.5)メニュー処理(カレンダー表示後)
m:RorW後のMENU, s:RorW, b:RorW, g:次へ, c:check, x:終了
(2)読み込み、エラー(1)か(2.5)へ
(2.5)メニュー処理(カレンダー表示後)
m:RorW後のMENU, s:RorW, b:RorW, g:次へ, c:check, x:終了
(3)メモ閲覧後、RorWへ戻る。

W処理→(1)日付選択、*の有無でエラー(1)か(1.5)へ
(1.5)メニュー処理(カレンダー表示後)
m:RorW後のMENU, s:RorW, b:RorW, g:次へ, c:check, x:終了
(2)書き込み(50文字,書き込み日に*)、エラー(1)か(2.5)へ
(2.5)メニュー処理(カレンダー表示後),
      m:RorW後のMENU, s:RorW, b:RorW, g:次へ, c:check, x:終了
(3)書き込み後MENU処理(3.5)へ
(3.5)MENU処理最終
m:MENU処理最終の表示、S:西暦から入力、b:RorWから入力、c:check、x:終了。

ふぅ、詳しく書いてみましたがどうでしょう?
MENUはやはり、あと二つ別に作ったほうがよろしいですかね。

カレンダー表示後のRorWに戻れるメニューと、
最後の、西暦からか、RorWか、カレンダーのチェックか終了。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: メニューを常に表示させたい。

#36

投稿記事 by softya(ソフト屋) » 14年前

気になるとことろ羅列
・c:check, ってなんでしょうか?
・(3)メモ閲覧後、RorWへ戻る。メモ閲覧後って具体的に何をするのでしょうか?
・*の有無でエラー(1)か(1.5)へ。ってことは一度書いたら修正できないのでしょうか?
・(2)書き込み(50文字,書き込み日に*)、エラー(1)か(2.5)へ。ここでカレンダーは表示されるのでしょうか?

それとmenuprint()やselect()の仕組みが少々変わる程度なら引数でmenuprint(引数)やselect(引数)の動作を変えてはどうでしょうか?

で大変だとは思いますが、全体の仕様を書きなおしてみてください。これが出来れば、後はプログラム化するだけです。

仕様ですが、今回はここから始めましょう。これで全部書いてみてください。
(1)MENU操作の表示(最初)
(2) 西暦の入力。エラーなら(2)に戻る。
(2.5)MENU操作(最初) s:(2)へ b:(2)へ g:(3)へ c:エラーなら(2)へ OKなら(4)へ m:メニューの一覧表示して(2.5)へ x:終了へ
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

かずま

Re: メニューを常に表示させたい。

#37

投稿記事 by かずま » 14年前

cal さんが書きました: MENUはやはり、あと二つ別に作ったほうがよろしいですかね。

カレンダー表示後のRorWに戻れるメニューと、
最後の、西暦からか、RorWか、カレンダーのチェックか終了。
そんなにメニューがたくさんあったら、使いにくくないですか?
また、メニューにある、『次の処理に行くには 「g」を入力』の
次の処理が何を意味するのか分かりにくいと思います。

カレンダーを表示するために、年と月の入力が必要ですが、初期値として
現在の年と月を使い、あとはコマンドで変更するだけでよいのでは?

試しに作ってみました。
1901~2099 を入力すると、年を変更し、カレンダーを表示します。
m1 ~m12 で、月を変更し、カレンダーを表示します。
m だけだと、カレンダーの再表示です。
1~31 を入力すると、その日のメモを表示します。
メモはなくても日付を表示しますから、続けて w で書き込みができます。
d で削除もできます。
w1 ~ w31 で、日付指定で書き込みできます。
d1 ~ d31 で、日付指定で削除できます。

コード:

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

typedef struct Message {
    int date;
    char *msg;
    struct Message *prev, *next;
} Message;

typedef struct {
    int year, month, day;
    Message root, *message[32];
} Data;

int day_of_week(int y, int m, int d)
{
    y -= m < 3;
    return (y + y/4 - y/100 + y/400 + ".bed=pen+mad."[m] + d) % 7;
}

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

int last_day(int y, int m)
{
    return (m == 2) ? is_leap(y) + 28 : (0x15aa>>m & 1) + 30;
}

void print_calendar(Data *dp)
{
    int w = day_of_week(dp->year, dp->month, 1);
    int z = last_day(dp->year, dp->month), d;

    printf("%13d年 %d月\n" " 日  月  火  水  木  金  土\n" "%*s",
        dp->year, dp->month, w * 4, "");
    for (d = 1; d <= z; d++)
        printf("%*c%d%c", (d<10)+1, dp->message[d]?'*':' ', d, ++w%7?' ':'\n');
    printf(w % 7 ? "\n\n" : "\n"); 
}

void print_help(void)
{
    puts(" q      : 終了 (quit)\n"
         " h      : ヘルプ (help)\n"
         " nnnn   : 年の変更 (1901~2099)\n"
         " m [nn] : 月(month)の変更とカレンダー表示\n"
         " nn     : その日のメモ表示 (1~31)\n"
         " w [nn] : メモの書き込み (write)\n"
         " d [nn] : その日のメモの削除 (delete)\n");
}

void print_message(Data *dp)
{
    printf("%d/%d/%d: %s", dp->year, dp->month, dp->day,
        dp->message[dp->day] ? dp->message[dp->day]->msg : "\n");
}

int confirm(const char *message)
{
    char buf[1024];
    printf("%s (y/n): ", message);
    return fgets(buf, sizeof(buf), stdin) && buf[0] == 'y';
}

void load_message(Data *dp)
{
    char buf[1024];
    FILE *fp = fopen("Calendar.txt", "r");
    if (!fp) return;
    dp->root.prev = dp->root.next = &dp->root;
    while (fgets(buf, sizeof(buf), fp)) {
        int y, m, d, n;
        if (sscanf(buf, "%d/%d/%d %n", &y, &m, &d, &n) == 3) {
            Message *mp = malloc(sizeof(Message));
            mp->date = y << 9 | m << 5 | d;
            mp->msg = strdup(buf + n);
            mp->prev = dp->root.prev;
            mp->next = &dp->root;
            dp->root.prev = dp->root.prev->next = mp;
        }
    }
    fclose(fp);
}

void save_message(Data *dp)
{
    FILE *fp = fopen("Calendar.txt", "w");
    if (fp) {
        Message *mp = dp->root.next;
        while (mp != &dp->root) {
            Message *np = mp->next;
            fprintf(fp, "%d/%02d/%02d %s", mp->date >> 9,
                mp->date >> 5 & 0x0f, mp->date & 0x1f, mp->msg);
            free(mp->msg);
            free(mp);
            mp = np;
        }
    }
}

void set_message(Data *dp)
{
    int date1 = dp->year << 9 | dp->month << 5 | 1;
    int date31 = dp->year << 9 | dp->month << 5 | 31;
    Message *mp = dp->root.next;
    int d;
    for (d = 0; d < 32; d++) dp->message[d] = 0;
    for (; mp != &dp->root && mp->date <= date31; mp = mp->next)
        if (mp->date >= date1) dp->message[mp->date & 0x1f] = mp;
}

void delete_message(Data *dp)
{
    Message *mp = dp->message[dp->day];
    if (mp) {
        mp->prev->next = mp->next;
        mp->next->prev = mp->prev;
        free(mp->msg);
        free(mp);
        dp->message[dp->day] = 0;
    }
}

void write_message(Data *dp, const char *buf)
{
    Message *mp = dp->message[dp->day];
    if (mp) {
        free(mp->msg);
        mp->msg = strdup(buf);
    } else {
        int date = dp->year << 9 | dp->month << 5 | dp->day;
        Message *np = dp->root.next;
        for ( ; np != &dp->root && np->date < date; np = np->next) ;
        mp = malloc(sizeof(Message));
        mp->date = date;
        mp->msg = strdup(buf);
        mp->prev = np->prev;
        mp->next = np;
        np->prev = np->prev->next = mp;
        dp->message[dp->day] = mp;
    }
}

int main(void)
{
    Data data;
    char buf[1024];
    time_t t = time(0);
    struct tm *tp = localtime(&t);
    data.year = tp->tm_year + 1900;
    data.month = tp->tm_mon + 1;
    data.day = tp->tm_mday;

    load_message(&data);
    set_message(&data);
    print_help();
    print_calendar(&data);
    print_message(&data);
    while (printf("> "),fgets(buf, sizeof(buf), stdin)) {
        int n = atoi(buf);
        if (n > 1900 && n < 2100 && n != data.year)  // change year
            data.year = n, print_calendar(&data);
        else if (n >= 1 && n <= 31)  // print message of the day
            data.day = n, print_message(&data);
        else if (buf[0] == 'm') {  // change month and print calendar
            n = atoi(buf + 1);
            if (n >= 1 && n <= 12 && n != data.month)
                data.month = n, set_message(&data);
            print_calendar(&data);
        } else if (buf[0] == 'w') {  // write
            n = atoi(buf + 1);
            if (n >= 1 && n <= last_day(data.year, data.month)) data.day = n;
            printf("%d/%d/%d: ", data.year, data.month, data.day);
            if (fgets(buf, sizeof(buf), stdin) && buf[0] != '\n') {
                if (!data.message[data.day] || confirm("上書きしますか?"))
                    write_message(&data, buf), print_calendar(&data);
            }
        } else if (buf[0] == 'd') {  // delete
            n = atoi(buf + 1);
            if (n >= 1 && n <= last_day(data.year, data.month)) data.day = n;
            if (data.message[data.day] && confirm("削除しますか?"))
               delete_message(&data), print_calendar(&data);
        } else if (buf[0] == 'q') {  // quit
            if (confirm("終了しますか?")) break;
        } else if (buf[0] == 'h') print_help();
    }
    save_message(&data);
    return 0;
}

かずま

Re: メニューを常に表示させたい。

#38

投稿記事 by かずま » 14年前

かずま さんが書きました: 試しに作ってみました。
即席で作って、すぐに投稿すると、やはり多くのバグが入ってしまうようです。
Calendar.txt がないと起動しないとか、6/31 を指定できてしまうとか、save_message() の中で fclose していないとか。
malloc や strdup の結果のチェックはわざとしていません。
他にも変な記述がたくさんあります。
元の質問者が課題としてを与えられていた問題だとしても、そのまま解答として提出できないようにと考えています。
あくまでも、参考程度に利用してください。
いろいろアドバイスすることが教育的でよいのかもしれませんが、ある程度動くプログラムを一所懸命読んでもらって、わからないところを自分で調べてみることも十分勉強になることだと思います。

コード:

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

typedef struct Message {
    int date;
    char *msg;
    struct Message *prev, *next;
} Message;

typedef struct {
    int year, month, day;
    Message root, *message[32];
} Data;

void print_help(void)
{
    puts(" q          : 終了 (quit)\n"
         " h          : ヘルプ (help)\n"
         " 1901~2099 : 年の指定\n"
         " m [1~12]  : 月の指定とカレンダーの表示 (month)\n"
         " 1~31      : 日の指定とメモの表示\n"
         " w [1~31]  : 日の指定とメモの書き込み (write)\n"
         " d [1~31]  : 日の指定とメモの削除 (delete)\n");
}

int day_of_week(int y, int m, int d)
{
    y -= m < 3;
    return (y + y/4 - y/100 + y/400 + ".bed=pen+mad."[m] + d) % 7;
}

#define IS_LEAP(y) ((y) % 4 == 0 && ((y) % 100 || (y) % 400 == 0))

int last_day(int y, int m)
{
    return (m == 2) ? IS_LEAP(y) + 28 : (0x15aa>>m & 1) + 30;
}

void print_calendar(Data *dp)
{
    int w = day_of_week(dp->year, dp->month, 1);
    int z = last_day(dp->year, dp->month), d;

    printf("%13d年 %d月\n" " 日  月  火  水  木  金  土\n" "%*s",
        dp->year, dp->month, w * 4, "");
    for (d = 1; d <= z; d++)
        printf("%*c%d%c", (d<10)+1, dp->message[d]?'*':' ', d, ++w%7?' ':'\n');
    puts(w % 7 ? "\n" : ""); 
}

void print_message(Data *dp)
{
    printf("%d/%d/%d: %s", dp->year, dp->month, dp->day,
        dp->message[dp->day] ? dp->message[dp->day]->msg : "\n");
}

int confirm(const char *message)
{
    char buf[1024];
    printf("%s (y/n): ", message);
    return fgets(buf, sizeof(buf), stdin) && buf[0] == 'y';
}

Message *insert(Message *pos, int date, const char *msg)
{
	Message *mp = malloc(sizeof(Message));
	mp->date = date;
	mp->msg  = strdup(msg);
	mp->prev = pos->prev;
	mp->next = pos;
	return pos->prev = pos->prev->next = mp;
}

void load_message(Data *dp)
{
    char buf[1024];
    int y, m, d, n;
    FILE *fp = fopen("Calendar.txt", "r");
    dp->root.prev = dp->root.next = &dp->root;
    if (!fp) return;
    while (fgets(buf, sizeof(buf), fp))
        if (sscanf(buf, "%d/%d/%d %n", &y, &m, &d, &n) == 3)
			insert(&dp->root, y << 9 | m << 5 | d, buf + n);
    fclose(fp);
}

void save_message(Data *dp)
{
    FILE *fp = fopen("Calendar.txt", "w");
    if (fp) {
        Message *mp = dp->root.next;
        while (mp != &dp->root) {
            Message *np = mp->next;
            fprintf(fp, "%d/%02d/%02d %s", mp->date >> 9,
                mp->date >> 5 & 0x0f, mp->date & 0x1f, mp->msg);
            free(mp->msg);
            free(mp);
            mp = np;
        }
        fclose(fp);
    }
}

void set_message(Data *dp)
{
    int date1 = dp->year << 9 | dp->month << 5 | 1;
    int date31 = dp->year << 9 | dp->month << 5 | 31;
    Message *mp = dp->root.next;
    int d;
    for (d = 0; d < 32; d++) dp->message[d] = 0;
    for (; mp != &dp->root && mp->date <= date31; mp = mp->next)
        if (mp->date >= date1) dp->message[mp->date & 0x1f] = mp;
}

void delete_message(Data *dp)
{
    Message *mp = dp->message[dp->day];
    if (mp) {
        mp->prev->next = mp->next;
        mp->next->prev = mp->prev;
        free(mp->msg);
        free(mp);
        dp->message[dp->day] = 0;
        print_calendar(dp);
    }
}

void write_message(Data *dp, const char *buf)
{
    Message *mp = dp->message[dp->day];
    if (mp) {
        free(mp->msg);
        mp->msg = strdup(buf);
    } else {
        int date = dp->year << 9 | dp->month << 5 | dp->day;
        for (mp = dp->root.next; mp != &dp->root && mp->date < date; mp = mp->next) ;
        dp->message[dp->day] = insert(mp, date, buf);
    }
    print_calendar(dp);
}

int main(void)
{
    Data data;
    char buf[1024];
    time_t t = time(0);
    struct tm *tp = localtime(&t);
    data.year = tp->tm_year + 1900;
    data.month = tp->tm_mon + 1;
    data.day = tp->tm_mday;

    load_message(&data);
    set_message(&data);
    print_help();
    print_calendar(&data);
    print_message(&data);

    while (printf("> "), fgets(buf, sizeof(buf), stdin)) {
        int n = atoi(buf);
        if (n > 1900 && n < 2100 && n != data.year)  // change year
            data.year = n, print_calendar(&data);
        else if (n >= 1 && n <= last_day(data.year, data.month)) // the day
            data.day = n, print_message(&data);
        else if (buf[0] == 'm') {  // change month and print calendar
            n = atoi(buf + 1);
            if (n >= 1 && n <= 12 && n != data.month)
                data.month = n, set_message(&data);
            print_calendar(&data);
        } else if (buf[0] == 'w') {  // write
            n = atoi(buf + 1);
            if (n >= 1 && n <= last_day(data.year, data.month)) data.day = n;
            printf("%d/%d/%d: ", data.year, data.month, data.day);
            if (fgets(buf, sizeof(buf), stdin) && buf[0] != '\n')
                if (!data.message[data.day] || confirm("上書きしますか?"))
                    write_message(&data, buf);
        } else if (buf[0] == 'd') {  // delete
            n = atoi(buf + 1);
            if (n >= 1 && n <= last_day(data.year, data.month)) data.day = n;
            if (data.message[data.day] && confirm("削除しますか?"))
               delete_message(&data);
        } else if (buf[0] == 'q') {  // quit
            if (confirm("終了しますか?")) break;
        } else if (buf[0] == 'h') print_help();
    }
    save_message(&data);
    return 0;
}

閉鎖

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