/*********************************************************************** * * Multiplication Tables Trainer: practice multiplication tables * and beat your best time. * * Program.......: mt_trainer * Date..........: August 30, 2022 * Author........: yetimach * * **********************************************************************/ #include #include #include #include #include #include #include #include #define MAX_UN 20 #define MAX_FN 30 #define TABLE_SIZE 13 #define MAX_ANSWER_LEN 4 // swap int element with last element in array void swap_with_last(int *arr, int size, int elem){ int temp = arr[size - 1]; arr[size - 1] = arr[elem]; arr[elem] = temp; } void shuffle_int_arr(int *arr, int size){ int num, temp_arr[size], pos = 0, i; srand(time(0)); while (size > 0){ num = (rand() % size); temp_arr[pos++] = arr[num]; swap_with_last(arr, size, num); --size; } for (i = 0; i < pos; i++) arr[i] = temp_arr[i]; } // check if user answer is the correct answer int match(int ca, int ua){ return (ca == ua) ? 1 : 0; } // read a positive int int read_int(){ int num = 0, si = 0, ch; char string[MAX_ANSWER_LEN]; while (!isdigit(ch = getchar())) ; string[si++] = ch; while ((ch = getchar()) != '\n'){ if (si < MAX_ANSWER_LEN - 1) if (isdigit(ch)) string[si++] = ch; } string[si] = '\0'; num = atoi(string); return num; } void print_time(long int t){ if (t > 60) printf("%ld min %ld sec", t / 60, t % 60); else printf("%ld sec", t); } void practice_table(int *nums, time_t *tt){ int i, t = 0; do { if (t > TABLE_SIZE - 1) printf("\n\t%d is invalid.", t); printf("\n\tTable to practice: "); t = read_int(); } while (t > TABLE_SIZE - 1); shuffle_int_arr(nums, TABLE_SIZE); printf("\n\t%d Table\n", t); long int best_time = tt[t]; if (best_time > 0){ printf("\n\tThe time to beat is "); print_time(best_time); printf(".\n"); } printf("\n\tPress enter to begin "); time_t start = time(NULL); while (getchar() != '\n') ; printf("\n\tGo!\n\n"); for (i = 0; i < TABLE_SIZE;){ printf("\t%2d x %2d = ", t, nums[i]); while (match((t * nums[i]), read_int()) == 0){ printf("\tSorry, try again."); printf("\n\t%2d x %2d = ", t, nums[i]); } ++i; } time_t finish = time(NULL); long int current_time = finish - start; if (current_time < best_time || best_time == 0){ printf("\n\t"); print_time(current_time); putchar('\n'); printf("\n\tA new record!\n"); tt[t] = current_time; }else{ printf("\n\t"); print_time(current_time); printf("\n\tKeep practicing!\n"); } } int read_username(char *un){ int success = 0, ch, count = 0; while ((!isalpha(ch = getchar()))) ; //read to a letter un[count++] = ch; while ((isalpha(ch = getchar())) && ch != ' ' && ch != '\n' && ch != '\t' && count < MAX_UN - 1) un[count++] = ch; if (count > 1) success = 1; if (ch != '\n') while ((ch = getchar() != '\n')) ; // read to newline un[count] = '\0'; return success; } void make_record(FILE *uf, char *file_name, time_t *tt){ int i; uf = fopen(file_name, "w"); for (i = 0; i < TABLE_SIZE; i++) fprintf(uf, "%ld\n", tt[i]); fclose(uf); } void read_record(FILE *uf, char *file_name, time_t *tt){ int i; uf = fopen(file_name, "r"); for (i = 0; i < TABLE_SIZE; i++) fscanf(uf, "%ld\n", &tt[i]); fclose(uf); } int read_option(void){ int opt; while ((tolower(opt = getchar())) != 'v' && opt != 'p' && opt != 'q'){ if (opt != '\n') printf("\n\tInvalid input. Tray again: "); } while (getchar() != '\n') ; // read to newline return opt; } void view_table(void){ int i, t; printf("\n\tTable to view: "); t = read_int(); putchar('\n'); for (i = 0; i < TABLE_SIZE; i++) printf("\n\t%2d x %2d = %3d", t, i, t*i); putchar('\n'); } int print_and_process_opts(time_t *tt){ int i, numbers[TABLE_SIZE]; for (i = 0; i < TABLE_SIZE; i++) numbers[i] = i; printf("\n\t'v' view table, 'p' practice table, 'q' quit: "); int option = read_option(); if (option == 'q') return 0; else if (option == 'v') view_table(); else if (option == 'p') practice_table(numbers, tt); return 1; } int main(void) { FILE *user_file; time_t table_times[TABLE_SIZE]; // check for users directory; create it if none. struct stat st = {0}; if (stat("users", &st) == -1) mkdir("users", 0751); char username[MAX_UN]; printf("\n\tMultiplication Tables Trainer\n" "\n\tPractice the multiplication tables and try to beat" "\n\tyour best time. Enter existing username to access" "\n\tan account or enter a new username to create one." "\n\t(letters only--at least two)\n" "\n\tEnter username: "); while ((read_username(username) == 0)) printf("\n\tInvalid username. Try again: "); char user_file_name[MAX_FN] = ""; strcpy(user_file_name, "users/"); strcat(user_file_name, username); strcat(user_file_name, "_records.txt"); if( access( user_file_name, F_OK ) != -1 ) { read_record(user_file, user_file_name, table_times); }else{ int i; for (i = 0; i < TABLE_SIZE; i++) table_times[i] = 0; make_record(user_file, user_file_name, table_times); printf("\n\tAccount created for %s.", username); } printf("\n\n\tWelcome, %s!\n", username); //print and process options while (print_and_process_opts(table_times)) ; make_record(user_file, user_file_name, table_times); printf("\n\tGoodbye\n\n"); return 0; }