问题描述
编写一个帮助小学生练习数学的程序,帮助小学生练习 100 以内的四种数学运算:加、减、乘、除。
基本要求
a) 程序应先询问用户的 ID 号(ID 号包括两个大写字母和 4 位数字),例如:
请输入用户 ID 号:AB1234
程序应对输入的 ID 号验证,符合 ID 号要求的格式,然后程序提示三种选择:
(1)开始测试
(2)检查分数
(3)退出
b) 测试:该程序将给出 10 道数学题,例如:
12 * 3 =36
48 + 32 =80
56 / 28 =2
注意:
i)学生将依次回答每一个问题(在等于号后面给出答案),然后给出下一道题。
ii)试题应包含四种数学运算:加、减、乘、除,它们是随机产生的。相邻的问题应该是不同的操作,每个操作必须至少出现一次。
iii)为每道题随机生成数字,但必须确保参与运算的数字和结果都小于 100 且大于零的整数。
iv)十道题做完后,记录学生完成这十道题所用的时间。
v)给每个学生一个分数。将该学生的 ID、成绩和使用时间保存到一个名为 record.txt 的文件中。
vi)在屏幕上输出以下信息:
问题 | 正确答案 | 你的答案
c) 成绩检查:从文件“record.txt”中列出该学生的所有历史成绩。例如:
你以前的记录是:
AB1234 80 150 秒
AB1234 50 182 秒
AB1234 90 98 秒
水平有限,大神轻喷
/* Program description: addition, subtraction, multiplication and division within 100
* Author: HelloW0r1d_1024
* Date: 2020/10/10
* P.S :
* ATTENTION! encoding with UTF-8
* The source code can be compiled and run in the following environment after testing
* win compiler ver: gcc 9.2.0(MinGW) please use c99 OR c11 standard
* linux compiler ver: gcc 9.3.0(wsl Ubuntu);
* please use c99 OR c11 standard,and add "-lm" at the end of the complie command // <math.h>
*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<string.h>
#define True 1
#define False 0
#define DIGIT 7 // digit of id 6 + 1('\0')
#define NUM_OF_QUESTIONS 10
#if _WIN32
#define FILE_PATH "D://record.txt"
#elif __linux__
#define FILE_PATH "/tmp/record.txt"
#endif
const char op_list[4] = {'+', '-', '*', '/'};
char questions[NUM_OF_QUESTIONS][11] = {'\0'};
int usr_ans[NUM_OF_QUESTIONS];
int std_ans[NUM_OF_QUESTIONS];
typedef struct {
char id[10];
int score;
int time;
} student;
int id_identify(student * stu);
/* Ask user to enter a string, store it in stu->id[10],
* then check if the ID user entered is legal
* PARAM: stu - a pointer to type "student"
* RETURN: True for legal, False for illegal
*/
int list_factor(int num, int factor[]);
/* Put all the factors of the dividend into an array
* PARAM: num - Number to be decomposed
* factor - a array to store all the factors of num
* RETURN: False when num is prime, otherwise True
*/
void op_generator(int arr[]);
/* Generate 10 adjacent operators that do not repeat and each appear at least once,
* and store them in an array
* PARAM: arr - to store 10 operators
*/
void formula_generator(int arr[]);
/* Randomly generate formulas,
* then store them in array "questions"
* PARAM: arr - including 10 operators
*/
int scorer(int a[], int b[]);
/* Calculate user's score
* PARAM: usr - including user's answer of 10 questions
* std - including standard answer of 10 questions
* RETURN: user's score
*/
void print_ans();
/* Print question, correct answer, user answer
*/
void clbf();
/* Clear the buffer
*/
int main(void) {
int current_op_list[NUM_OF_QUESTIONS]; // Store the currently randomly generated op
int begin, end; // Timing
int option; // 3 options
char str[81]; // Store each line of the file
FILE * fp;
student stu1;
// If the input is illegal, prompt the user to re-enter
while (!id_identify(&stu1))
printf("This id is invalid, please re-enter\n");
while (True) {
printf("options:\n");
printf("(1)start testing\n");
printf("(2)check score\n");
printf("(3)exit\n");
char ch1;
while (scanf("%d", &option) == 0 || option < 1 || option > 3 || (ch1 = getchar()) != '\n') {
printf("please enter an integer from 1 to 3!\n");
clbf();
}
if (3 == option)
break;
switch (option) {
// option1 -- start testing
case 1:
if ((fp = fopen(FILE_PATH, "a")) == NULL) {
printf("Error! opening file\n");
exit(1);
}
// question
srand((unsigned int)time(NULL));
op_generator(current_op_list);
formula_generator(current_op_list);
// answer
char ch2;
begin = time(NULL); // Timing begins
for (int i = 0; i < NUM_OF_QUESTIONS; i++) {
printf("%s", questions[i]); // Print a question
if (scanf("%d", &usr_ans[i]) == 0 || (ch2 = getchar()) != '\n') {
printf("Please enter an integer! Try again.\n");
i--; // Answer not finished yet, thus i--
clbf();
}
}
end = time(NULL); // Timing ends
stu1.score = scorer(usr_ans, std_ans);
stu1.time = end - begin;
// Write id, score, time to file
fprintf(fp, "%s\t%d\t%ds\n", stu1.id, stu1.score, stu1.time);
fclose(fp);
// Print question, correct answer, user answer
printf("Your score : %d\n", stu1.score);
print_ans();
break;
// option2 -- check score
case 2 :
if ((fp = fopen(FILE_PATH, "r")) == NULL) {
printf("Error! opening file\n");
exit(1);
}
// Read records from file
printf("Your previous records are:\n");
while (!feof(fp)) {
fgets(str, 81, fp);
if (feof(fp)) // Prevent the last line of the file from being printed twice
break;
char tmp[7];
for (int i = 0; i < 6; i++)
tmp[i] = str[i];
if (!strcmp(tmp, stu1.id))
fputs(str, stdout);
}
fclose(fp);
break;
}
}
}
int id_identify(student * stu) {
printf("Please enter your id:");
// safer than gets()
if (fgets(stu->id, 10, stdin) && stu->id[0] != '\n') {
int j = 0;
while (stu->id[j] != '\n' && stu->id[j] != '\0')
j++;
if (stu->id[j] == '\n')
stu->id[j] = '\0';
else
while (getchar() != '\n')
continue;
}
int flag = True;
if (strlen(stu->id) != 6)
flag = False;
for (int i = 0; i < DIGIT - 1; i++) {
if (i < 2) {
if (stu->id[i] < 65 || stu->id[i] > 90)
flag = False;
}
else {
if (stu->id[i] < 48 || stu->id[i] > 57)
flag = False;
}
}
return flag;
}
int list_factor(int num, int factor[]) {
int tmp = (int)sqrt(num); // Round down
int cnt = 0;
for (int i = 2, j = 0; i <= tmp; i++) {
if (num % i == 0) {
factor[j] = i;
cnt++;
j++; // Index j will only increase if there is a deposit in the array
if (i != num / i) {
factor[j] = num / i;
j++;
}
}
}
return 0 == cnt ? False : True;
}
void op_generator(int op[]) {
int op_index; // Temporarily store the random number in [0, 3], compare with the last generated
int flag[4] = {False};
// Once each operator does not appear at least once, then regenerate
while (!(flag[0] && flag[1] && flag[2] && flag[3])) {
op[0] = rand() % 4;
for (int i = 1; i < NUM_OF_QUESTIONS; i++) {
// If the randomly generated operator is the same as the last time,
// then regenerate until it is different
do {
op_index = rand() % 4;
} while (op_index == op[i - 1]);
// Once an operator appears randomly, its corresponding flag is changed to True
flag[op_index] = True;
op[i] = op_index;
}
}
}
void formula_generator(int op[]) {
int a, b;
int factor[20] = {0}; // Store all factors of the dividend
for(int i = 0; i < NUM_OF_QUESTIONS; i++) {
a = rand() % 99 + 1; // a∈[1, 99]
switch (op_list[op[i]]) {
case '+':
b = rand() % (99 - a) + 1; // b∈[1, 99 - a]
std_ans[i] = a + b;
break;
case '-':
b = rand() % (a - 1) + 1; // b∈[1, a - 1]
std_ans[i] = a - b;
break;
case '*':
a = rand() % 48 + 2; // a∈[2, 49]
b = rand() % ((99 / a) - 1) + 2; // b∈[2, 99 / a]
std_ans[i] = a * b;
break;
case '/':
// Put all the factors of the dividend in factor[], and regenerate if a is prime
while (!list_factor(a, factor)) {
// factor[] is cleared after each loop
for (int i = 0; i < 20; i++)
factor[i] = 0;
a = rand() % 96 + 4; // a∈[4, 99]
}
int length = 0;
for (int j = 0; factor[j]; j++)
length++;
b = factor[rand() % length]; // Randomly take from the non-1 and non-self factors of a
for (int i = 0; i < 20; i++)
factor[i] = 0;
std_ans[i] = a / b;
break;
}
snprintf(questions[i], 11, "%2d %c %-2d = ", a, op_list[op[i]], b);
}
}
int scorer(int usr_ans[], int std_ans[]) {
int score = 0;
for (int i = 0; i < NUM_OF_QUESTIONS; i++) {
if (usr_ans[i] == std_ans[i])
score += 10;
}
return score;
}
void print_ans() {
printf("questions\tcorrect answer\tyour answer\n");
for (int i = 0; i < NUM_OF_QUESTIONS; i++)
printf("%s\t%d\t\t%d\t\n", questions[i], std_ans[i], usr_ans[i]);
}
void clbf() {
while (getchar() != '\n')
continue;
}