IT コード最新

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

#define WORD 100
#define EXPLAIN 200
#define TOPIC_WORD 50
#define TOPIC_NUM 7

typedef struct {
    char explain[EXPLAIN];
    char word[WORD];
    int miss_count;
} IT;

int question(IT *date, int *str_num, int *privious);
int write_date(IT * date, char txt[], int str_num, int privious, int lap, char topic[]);
void end_step(IT * date, int miss_subscript[], int try_count, int miss_count);

void end_step(IT * date, int miss_subscript[], int try_count, int miss_count)
{
    puts("\n-----結果-----");
    printf("%3d  /%3d 正解\n", try_count - miss_count, try_count);

    puts("\n~間違えたワード~");

    for (int i = 0; i < miss_count; i++) {
        printf("No.%03d %s\n", miss_subscript[i] + 2, date[miss_subscript[i]].word); //+2は添え字の0と最上段の分
    }
}

/**
 * 
 * @retval 1 完走
 * @retval 2 途中終了
 * @retval 3 何もせずに終了
*/
int question(IT *date, int *str_num, int *privious)
{
    char finishEng[] = "fin";
    char helpHatena[] = "?";
    char remove[] = "remove";
    int *miss_subscript = calloc(*str_num, sizeof(int)); //free ok
    int miss_count = 0;
    int try_count = 0;

    for (int i = *privious; i < *str_num; i++) {
        char buff[WORD];
        int judge = 0;
        int judge_count = 0;
        int removeFlag = 1;

        printf("No.%03d %s\n", i + 2, date[i].explain);

        do {
            int help_call = 0;     
            printf("入力 : ");
            scanf("%s", buff);

            // 途中終了
            if (strcmp(buff, finishEng) == 0) { 
                if (try_count == 0) {
                    free(miss_subscript);
                    return 3;
                }
                *privious = i;
                end_step(date, miss_subscript, try_count, miss_count);
                free(miss_subscript);
                return 2;
            }
            // 削除(削除だけして途中終了すると保存されない)
            else if (strcmp(buff, remove) == 0) {
                
                printf("削除(No.%03d %s %s)\n\n", i + 2, date[i].word, date[i].explain);
                for (int j = i; j < *str_num - 1; j++) {
                    date[j].miss_count = date[j + 1].miss_count;
                    strcpy(date[j].word, date[j + 1].word);
                    strcpy(date[j].explain, date[j + 1].explain);
                }
                *str_num -= 1;
                i--;
                removeFlag = 0;
                continue;
            }
            // 答え表示
            else if (strcmp(buff, helpHatena) == 0) {
                printf("答え : %s\n", date[i].word);
                date[i].miss_count++;
                miss_subscript[miss_count] = i;
                miss_count++;
                help_call++;
            } 

            judge = strcmp(buff, date[i].word);

            if (judge != 0 && help_call == 0) {
                printf("違います。\n");
                judge_count++;
            }
            if (judge_count == 3) {
                judge_count++;
                printf("答え : %s\n", date[i].word);
                date[i].miss_count++;
                miss_subscript[miss_count] = i; //わざわざ文字列コピーしなくても添え字番号分かれば参照できる
                miss_count++;
            }
        } while (judge != 0);

        if (removeFlag == 1) {
            puts("正解!!");
            try_count++;
        }  
    }
    end_step(date, miss_subscript, try_count, miss_count);
    free(miss_subscript);
    return 1;
}

int write_date(IT * date, char txt[], int str_num, int privious, int lap, char topic[])
{
    FILE *fp;

    if ((fp = fopen(txt, "w")) == NULL) {
        puts("ファイルを開けませんでした。");
        return 0;
    }
    else {
        fprintf(fp, "%s %d %d %d\n", topic, str_num, privious, lap); //改行ないとだめみたい

        for(int i = 0; i < str_num; i++) {
            fprintf(fp, "%d %s %s\n", date[i].miss_count, date[i].word, date[i].explain);
        }
        return 1; 
    }
}

int check_str(char str[TOPIC_NUM][TOPIC_WORD], char argv_check[])
{
    for (int i = 0; i < TOPIC_NUM; i++) {
        if (strcmp(str[i], argv_check) == 0) {
            return 1;
        }
    }
    return 0;
}

int main(int argc, char *argv[])
{
    char topic_str_none[TOPIC_NUM][TOPIC_WORD] = {"security", "law", "strategy", "activity", 
                                                  "network", "audit", "servicemanagement"}; 
    char topic_str_txt[TOPIC_NUM][TOPIC_WORD] = {"security.txt", "law.txt", "strategy.txt", "activity.txt", 
                                                 "network.txt", "audit.txt", "servicemanagement.txt"}; 
    char txt[TOPIC_WORD + 4]; //.txt分で+4

    // segmetation faultになる
    if (argc == 1) { //必ずargcは1入ってる
        puts("コマンドラインから分野を指定しませんでしたね。");
        int buff_num;
        for (int i = 0; i < TOPIC_NUM; i++) {
            printf("No.%d %s\n", i, topic_str_txt[i]);
        }
        printf("分野番号 : ");
        scanf("%d", &buff_num);
        // printf("%d\n", buff_num); チェック
        strcpy(txt, topic_str_txt[buff_num]); //argv[1]はNULL領域が確保されていない
    }
    
    else if (argc >= 2) {

        if (argv[1][0] >= '0' && argv[1][0] <= '9') {
            int topic_subscript = argv[1][0] - '0';
            strcpy(txt, topic_str_txt[topic_subscript]);
        }
        else {
            strcpy(txt, argv[1]);
        }
        if (check_str(topic_str_none, argv[1])) {
            char addition[] = ".txt";
            strcat(txt, addition);
            puts(".txtが付いていなかったので追記しました。");
        }
    }

    putchar('\n');

    FILE *fp;

    if ((fp = fopen(txt, "r")) == NULL) {
        puts("ファイルを開けませんでした。");
        return 0;
    }
    else {
        int str_num; //配列の数
        int privious; //前回終了した時の添え字
        int lap; //何周目か
        char topic[TOPIC_WORD]; //分野のテーマ

        fscanf(fp, "%s %d %d %d", topic, &str_num, &privious, &lap);

        IT *date = calloc(str_num, 304); //free ok

        int subscript = 0;
        while ((fscanf(fp, "%d %s %s", &date[subscript].miss_count, date[subscript].word, date[subscript].explain)) == 3) {
            subscript++;
        }
        fclose(fp);

        /* 読み込みできているかチェック用
        for (int i = 0; i < str_num; i++) {
            printf("%d %s %s\n", date[i].miss_count, date[i].word, date[i].explain);
        }
        */

        printf("ITテスト -%s分野-\n", topic);
        puts("\"fin\"→途中終了");
        puts("\"?\"→答え表示");
        puts("\"remove\"→問題の削除");
        printf("前回は");
        if (privious == str_num) {
            printf("完走しています。%d周目に入ります。\n", lap + 1);
            privious = 0;
            lap++;
        }
        else {
            printf("%d番目です。\n\n", privious + 2);
        }

        int result = question(date, &str_num, &privious);

        if (result == 1) {
            privious = str_num;
            puts("\n完走おめでとう。");
        }
        else if (result == 2) {
            puts("途中終了しました。");
        }
        else if (result == 3) {
            puts("挑戦せずに終わりました。");
            free(date);
            return 0;
        }

        char backUp[] = "backup";
        char no[] = "しません";
        char save[20];
        printf("\n保存処理 (\"しません\"以外保存、\"backup\"→バックアップ更新) : ");
        scanf("%s", save);

        int write_check;

        if (strcmp(save, backUp) == 0) {
            char path[] = "../backup/"; // 1階層上にbackupフォルダを作成する必要がある
            strcat(path, txt);
            write_check = write_date(date, path, str_num, privious, lap, topic);
            puts("バックアップを申請しました。");

            if (write_check == 1) {
                puts("バックアップに成功しました。");
            }
            else {
                puts("バックアップに失敗しました。");
            }
        }

        if (strcmp(save, no) != 0) {
            write_check = write_date(date, txt, str_num, privious, lap, topic);
            puts("保存を申請しました。");

            if (write_check == 1) {
                puts("保存に成功しました。");
            }
            else {
                puts("保存に失敗しました。");
            }
        }
        else {
            puts("保存しませんでした。");
        }
        
        free(date);
    
    }
    return 0;
}