diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.c | 83 | ||||
| -rw-r--r-- | src/questions.c | 92 | ||||
| -rw-r--r-- | src/utils.c | 34 |
3 files changed, 209 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..33d4b39 --- /dev/null +++ b/src/main.c | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <time.h> | ||
| 4 | #include <sys/stat.h> | ||
| 5 | #include <sys/types.h> | ||
| 6 | |||
| 7 | #include "questions.h" | ||
| 8 | #include "utils.h" | ||
| 9 | |||
| 10 | int main(void) { | ||
| 11 | srand((unsigned)time(NULL)); | ||
| 12 | |||
| 13 | // utwórz katalog data/ jeśli nie istnieje | ||
| 14 | struct stat st = {0}; | ||
| 15 | if (stat("data", &st) == -1) { | ||
| 16 | #ifdef _WIN32 | ||
| 17 | _mkdir("data"); | ||
| 18 | #else | ||
| 19 | mkdir("data", 0755); | ||
| 20 | #endif | ||
| 21 | } | ||
| 22 | |||
| 23 | QuestionSet qs; | ||
| 24 | if (load_questions("data/questions.txt", &qs) != EXIT_SUCCESS) { | ||
| 25 | fprintf(stderr, "Error: cannot load questions file\n"); | ||
| 26 | return EXIT_FAILURE; | ||
| 27 | } | ||
| 28 | |||
| 29 | FILE *csv = fopen("data/results.csv", "a"); | ||
| 30 | if (!csv) { | ||
| 31 | perror("CSV open"); | ||
| 32 | free_questions(&qs); | ||
| 33 | return EXIT_FAILURE; | ||
| 34 | } | ||
| 35 | |||
| 36 | int limit = 0; | ||
| 37 | printf("Time limit (sec, 0 = unlimited): "); | ||
| 38 | if (scanf("%d", &limit) != 1) limit = 0; | ||
| 39 | wait_enter(NULL); | ||
| 40 | |||
| 41 | size_t total = 0, correct = 0; | ||
| 42 | char cont = 'y'; | ||
| 43 | |||
| 44 | while (cont == 'y' || cont == 'Y') { | ||
| 45 | const char *g = qs.general[rand_index(qs.general_count)]; | ||
| 46 | const char *m = qs.major[rand_index(qs.major_count)]; | ||
| 47 | |||
| 48 | print_line(); | ||
| 49 | printf("GENERAL:\n%s\n\nMAJOR:\n%s\n", g, m); | ||
| 50 | print_line(); | ||
| 51 | |||
| 52 | wait_enter("Press ENTER to start..."); | ||
| 53 | time_t start = time(NULL); | ||
| 54 | |||
| 55 | wait_enter("Press ENTER when done..."); | ||
| 56 | double duration = difftime(time(NULL), start); | ||
| 57 | |||
| 58 | if (limit > 0 && duration > limit) | ||
| 59 | printf("Time exceeded!\n"); | ||
| 60 | |||
| 61 | char ans = ask_yes_no("Correct? (y/n): "); | ||
| 62 | if (ans == 'y' || ans == 'Y') correct++; | ||
| 63 | total++; | ||
| 64 | |||
| 65 | char ts[32]; | ||
| 66 | now_str(ts, sizeof(ts)); | ||
| 67 | fprintf(csv, "\"%s\",\"%s\",\"%s\",%c,%.0f\n", ts, g, m, ans, duration); | ||
| 68 | |||
| 69 | printf("Score: %zu/%zu (%.1f%%)\n", | ||
| 70 | correct, total, | ||
| 71 | total ? (double)correct / total * 100 : 0.0); | ||
| 72 | |||
| 73 | cont = ask_yes_no("Next? (y/n): "); | ||
| 74 | } | ||
| 75 | |||
| 76 | printf("\nSession score: %.1f%%\n", | ||
| 77 | total ? (double)correct / total * 100 : 0.0); | ||
| 78 | |||
| 79 | fclose(csv); | ||
| 80 | free_questions(&qs); | ||
| 81 | |||
| 82 | return EXIT_SUCCESS; | ||
| 83 | } | ||
diff --git a/src/questions.c b/src/questions.c new file mode 100644 index 0000000..88671a7 --- /dev/null +++ b/src/questions.c | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | #include "questions.h" | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | #include <string.h> | ||
| 5 | |||
| 6 | #define MAX_LINE 512 | ||
| 7 | |||
| 8 | static int add_question(char ***arr, size_t *count, const char *text) { | ||
| 9 | char **tmp = realloc(*arr, (*count + 1) * sizeof(char *)); | ||
| 10 | if (!tmp) | ||
| 11 | return EXIT_FAILURE; | ||
| 12 | *arr = tmp; | ||
| 13 | |||
| 14 | (*arr)[*count] = malloc(strlen(text) + 1); | ||
| 15 | if (!(*arr)[*count]) | ||
| 16 | return EXIT_FAILURE; | ||
| 17 | |||
| 18 | strcpy((*arr)[*count], text); | ||
| 19 | (*count)++; | ||
| 20 | return EXIT_SUCCESS; | ||
| 21 | } | ||
| 22 | |||
| 23 | int load_questions(const char *filename, QuestionSet *qs) { | ||
| 24 | if (!filename || !qs) | ||
| 25 | return EXIT_FAILURE; | ||
| 26 | |||
| 27 | FILE *f = fopen(filename, "r"); | ||
| 28 | if (!f) | ||
| 29 | return EXIT_FAILURE; | ||
| 30 | |||
| 31 | qs->general = NULL; | ||
| 32 | qs->major = NULL; | ||
| 33 | qs->general_count = 0; | ||
| 34 | qs->major_count = 0; | ||
| 35 | |||
| 36 | char line[MAX_LINE]; | ||
| 37 | enum { NONE, GENERAL, MAJOR } mode = NONE; | ||
| 38 | |||
| 39 | while (fgets(line, sizeof(line), f)) { | ||
| 40 | line[strcspn(line, "\n")] = '\0'; | ||
| 41 | if (line[0] == '\0') | ||
| 42 | continue; | ||
| 43 | |||
| 44 | if (strcmp(line, "#GENERAL") == 0) { | ||
| 45 | mode = GENERAL; | ||
| 46 | continue; | ||
| 47 | } | ||
| 48 | if (strcmp(line, "#MAJOR") == 0) { | ||
| 49 | mode = MAJOR; | ||
| 50 | continue; | ||
| 51 | } | ||
| 52 | |||
| 53 | int res = EXIT_FAILURE; | ||
| 54 | switch (mode) { | ||
| 55 | case GENERAL: | ||
| 56 | res = add_question(&qs->general, &qs->general_count, line); | ||
| 57 | break; | ||
| 58 | case MAJOR: | ||
| 59 | res = add_question(&qs->major, &qs->major_count, line); | ||
| 60 | break; | ||
| 61 | default: | ||
| 62 | continue; // ignore lines before section | ||
| 63 | } | ||
| 64 | |||
| 65 | if (res != EXIT_SUCCESS) { | ||
| 66 | fclose(f); | ||
| 67 | free_questions(qs); | ||
| 68 | return EXIT_FAILURE; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | fclose(f); | ||
| 73 | return (qs->general_count && qs->major_count) ? EXIT_SUCCESS : EXIT_FAILURE; | ||
| 74 | } | ||
| 75 | |||
| 76 | void free_questions(QuestionSet *qs) { | ||
| 77 | if (!qs) | ||
| 78 | return; | ||
| 79 | |||
| 80 | for (size_t i = 0; i < qs->general_count; i++) | ||
| 81 | free(qs->general[i]); | ||
| 82 | for (size_t i = 0; i < qs->major_count; i++) | ||
| 83 | free(qs->major[i]); | ||
| 84 | |||
| 85 | free(qs->general); | ||
| 86 | free(qs->major); | ||
| 87 | |||
| 88 | qs->general = NULL; | ||
| 89 | qs->major = NULL; | ||
| 90 | qs->general_count = 0; | ||
| 91 | qs->major_count = 0; | ||
| 92 | } | ||
diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..c139929 --- /dev/null +++ b/src/utils.c | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #include "utils.h" | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | #include <time.h> | ||
| 5 | |||
| 6 | void print_line(void) { | ||
| 7 | printf("--------------------------------------------------\n"); | ||
| 8 | } | ||
| 9 | |||
| 10 | void wait_enter(const char *msg) { | ||
| 11 | if (msg) | ||
| 12 | printf("%s", msg); | ||
| 13 | int c; | ||
| 14 | while ((c = getchar()) != '\n' && c != EOF) | ||
| 15 | ; | ||
| 16 | } | ||
| 17 | |||
| 18 | char ask_yes_no(const char *msg) { | ||
| 19 | char c = 'n'; | ||
| 20 | printf("%s", msg); | ||
| 21 | if (scanf(" %c", &c) != 1) | ||
| 22 | c = 'n'; | ||
| 23 | int flush; | ||
| 24 | while ((flush = getchar()) != '\n' && flush != EOF) | ||
| 25 | ; | ||
| 26 | return c; | ||
| 27 | } | ||
| 28 | |||
| 29 | void now_str(char *buf, size_t size) { | ||
| 30 | time_t t = time(NULL); | ||
| 31 | strftime(buf, size, "%Y-%m-%d %H:%M:%S", localtime(&t)); | ||
| 32 | } | ||
| 33 | |||
| 34 | size_t rand_index(size_t max) { return max ? (size_t)(rand() % max) : 0; } | ||
