- 小学算术能力训练系统
设计并实现一个进行小学程度的四则混合运算的算术能力训练系统,能够生成运
算对象为 100 以内的四则混合运算题,要进行合法性检查,即保证除数不为 0。用户
在输入答案后,可显示答案正确或错误。该系统应实现以下基本功能:
(1)随机出题,并判定答案是否正确。
(2)设置两种可选的答题模式:练习模式和考试模式。
(3)练习模式不断的循环出题,直到用户要求终止。并且每答完一题,还应显示
当前的正确率(已答对题数/已答题数)。
(4)考试模式可由用户指定题目总数量(如 10、50、100),在答完全部题目后
显示总题数、答对题数、和正确率。
(5)每一次进入考试模式的考试结果(总题数、答对题数、正确率)都应写入文
件保存,用户可随时查看过去的考试结果。
(6)合理组织排列各项功能,界面可使用键盘操作。
运行结果(输入流已经被我关了)
出题过程
先看流程图吧
就拿一个数组装题目
do
{
t = 0;
memset(m, 0, sizeof(m));
set_title_1st(m);
mans=getans(m);
while (t < 2||getrand_mod_unpasstime(2)||t>10 )//保底也生成两个符号的算式,当然生成更多就听天由命了
{
set_title_next(m, mans);
mans=getans(m);
t++;
}
if (mans <= 10 || mans >= 90&&mans!=1&&mans!=100)
time++;
else time = 0;
} while (mans>=MOD||mans<=1||mans!=(int)mans||time ==1);//这里一堆条件全是因为我菜,生成ans=1和100的概率加起来有25了,生成ans《10和ans》90的概念加起来有50
题目生成
void set_title_1st(char* ti)//生成第一个式子
{
int a, b, c;
a = getrand_mod(MOD);
b = getrand_mod(MOD);
while (a < b)
{
a = a + 100 - b;
}
c = getrand_mod_unpasstime(6);
xiuzheng(&a,& b, &c);
int len = strlen(ti);
len = fillint(a, ti, len);
*(ti + len) = c + '*'; len++;
len = fillint(b, ti, len);
}
void set_title_next(char* ti,double ans)//生成接下来的题
{
int b, c;
int a = (int)ans;
c = getrand_mod(6);
b = getrand_mod(MOD);
xiuzheng(&a,&b,&c);
int len = strlen(ti);
*(ti + len++) = c + '*';
len = fillint(b, ti, len);
}
括号生成
直接把一个数拆成两个数就行了
int fillint(int a, char* ti, int len)
{
if (a > 27 && getrand_mod_unpasstime(4)==1)
{
int b = getrand_mod_unpasstime(a);
*(ti + len) = '('; len++;
sprintf(ti + len, "%d", b);
len = strlen(ti);
*(ti + len) = '+'; len++;
sprintf(ti + len, "%d", a - b);
len = strlen(ti);
*(ti + len) = ')'; len++;
return len;
}//在往题目字符串组中存a的时候,把a拆成两个数相加,并且带上括号
else if (a > 7&&a<80&& getrand_mod_unpasstime(4)==1)
{
int b = MOD;
while (a + b >= MOD)
{
b=getrand_mod_unpasstime(a);
}
*(ti + len) = '('; len++;
sprintf(ti + len, "%d", a+b);
len = strlen(ti);
*(ti + len) = '-'; len++;
sprintf(ti + len, "%d", b);
len = strlen(ti);
*(ti + len) = ')'; len++;
return len;
}//改成相减,带括号
else
{
sprintf(ti + len, "%d", a);
return strlen(ti);
} //正常生成
}
怎么从一个字符串式子中获得答案呢?
用栈就行了
double getans(char* t)//用的是栈的原理
{
double ans = 0;
double temp[1000];
memset(temp, 0, sizeof(temp));
int len = strlen(t);
int top = 0;
int i = 0;
if (*(t + i) == '(')
{
i++;
temp[++top] = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
temp[top] += getemp(t, &i, len);
}
else
{
i++;
temp[top] -= getemp(t, &i, len);
}
i++;
}
else
{
temp[top] = getemp(t, &i, len);
}
for (; i < len; )
{
{
if (*(t + i) - '*' == 1)
{
i++;
if (*(t + i) == '(')
{
i++;
temp[++top] = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
temp[top] += getemp(t, &i, len);
}
else
{
i++;
temp[top] -= getemp(t, &i, len);
}
i++;
}
else
{
temp[++top] = getemp(t, &i, len);
}
}
if (*(t + i) - '*' == 3)
{
i++;
if (*(t + i) == '(')
{
i++;
temp[++top] -= getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
temp[top] -= getemp(t, &i, len);
}
else
{
i++;
temp[top] += getemp(t, &i, len);
}
i++;
}
else
{
temp[++top] -= getemp(t, &i, len);
}
}
if (*(t + i) =='*' )
{
i++;
if (*(t + i) == '(')
{
double tt=0;
i++;
tt = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
tt += getemp(t,& i, len);
}
else
{
i++;
tt -= getemp(t, &i, len);
}
i++;
temp[top] *= tt;
}
else
{
temp[top] *= getemp(t, &i, len);
}
}
if (*(t + i) - '*' == 5)
{
i++;
if (*(t + i) == '(')
{
double tt = 0;
i++;
tt = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
tt += getemp(t,& i, len);
}
else
{
i++;
tt -= getemp(t, &i, len);
}
i++;
temp[top] /= tt;
}
else
{
temp[top] /= getemp(t, &i, len);
}
}
}
}
for (int i = 0; i <=top; i++)
{
ans += temp[i];
}
return ans;
}
源代码
/*2. 小学算术能力训练系统
设计并实现一个进行小学程度的四则混合运算的算术能力训练系统,能够生成运
算对象为 100 以内的四则混合运算题,要进行合法性检查,即保证除数不为 0。用户
在输入答案后,可显示答案正确或错误。该系统应实现以下基本功能:
(1)随机出题,并判定答案是否正确。
(2)设置两种可选的答题模式:练习模式和考试模式。
(3)练习模式不断的循环出题,直到用户要求终止。并且每答完一题,还应显示
当前的正确率(已答对题数/已答题数)。
(4)考试模式可由用户指定题目总数量(如 10、50、100),在答完全部题目后
显示总题数、答对题数、和正确率。
(5)每一次进入考试模式的考试结果(总题数、答对题数、正确率)都应写入文
件保存,用户可随时查看过去的考试结果。
(6)合理组织排列各项功能,界面可使用键盘操作。*/
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<ctype.h>
#include<windows.h>
#define MOD 100
int chumod = -1;
int zhuobi = 0;
double mans;
char hihi[20] = "liuquanzhuishuai";//作弊码:刘权最帅
int issusu(int n)//定义函数 判断一个数是否为素数
{
if (n == 0 || n == 1) return 1;
int i = 0;//定义参数 控制循环
for (i = 2; i <=n/2; i++)
{
if (n % i == 0)//判断这个数与2至本身相模 是否有为零的数
return 0;//有模为零的数 直接返回-1
}
return 1;//执行完循环还没有模为零的数 则是个素数 返回0
}
int ma(int a, int b)
{
return a > b ? a : b;
}
int mi(int a, int b)
{
return a < b ? a : b;
}
int getrand_mod(int mod)
{
int b = 0;
srand((unsigned)clock());
b = rand() * 91;//随便乘一个数
b %= mod;
Sleep(3);//随便经过一段时间
return b;
}//耗时随机生成器
int getrand_mod_unpasstime(int mod)
{
srand((unsigned)clock());
int a = rand();
a %= mod;
return a;
}//无耗时随机生成器
int setchu(int a)//随机生成a的因数作为除数
{
int temp[100] = { 0 }; int j = 0;
int i = 2;
while (j == 0)
{
i = 2;
for (; i <a; i++)
{
if (a % i == 0)
{
temp[j] = i;
j++;
}
}
}
int time = 0;
do {
i = getrand_mod_unpasstime(j);//给i付个在0~j-1的随机数
time++;
} while (time < 2 && (temp[i] == 2 || temp[i] == a / 2));//减少除数=2,或=a/2的概率
return temp[i];
}
void xiuzheng(int *a, int * b, int *c)//只是堆abc的合法性进行修正而已
{
if (*(c) == 2) { if (getrand_mod_unpasstime(2)) *(c) = 3; else *(c) = 0; }
if (*(c) == 4) { if (getrand_mod_unpasstime(2)) *(c) = 1; else *(c) = 5; }
if (issusu( *(a) ) )
{
if (*(c) == 5)
{
*(c) = getrand_mod_unpasstime(4);
if (*(c) == 2) *(c) = 1;
}
}
if (*(c) == 5 && *(b) == 0)
{
while (*(b) == 0)
{
*(b) = getrand_mod(MOD);
}//若除 b!=0
}
if (*(c) == 0)//*c!=*(c)
{
if (*(a) > MOD / 2)
*(c) =3;
else
{
while (*(a) * *(b) >= MOD)
{
*(b)/=2;
if (*(b) == 0)
*(b) = getrand_mod(MOD);// 保证乘数不为0或1,不让也太简单了吧 ;
}// 若乘大于100,转化一下
}
}
if (*(c) == 1)
{
if ((*(b)+*(a)) > MOD)
{
*(b) = *(b) / 2;
}
}
if (*(c) == 3)
{
if (*(a) < *(b))
{
if (*(a)<=8)
{
*(b) = getrand_mod_unpasstime(90);
*(c) = 1;
}
else
{
while (*(b) >= *(a))
{
*(b) /= 2;
}
}
}
//防止ans小于0
}
if (*(c) == 5)
{
if (chumod == 1);
else
{
*(b) = setchu(*(a));
}
}
}//对于c的修正,由于在ASCLL码中加减乘除不是连续的,将非加减乘除的转成加和减,减少点难度;
int fillint(int a, char* ti, int len)
{
if (a > 27 && getrand_mod_unpasstime(4)==1)
{
int b = getrand_mod_unpasstime(a);
*(ti + len) = '('; len++;
sprintf(ti + len, "%d", b);
len = strlen(ti);
*(ti + len) = '+'; len++;
sprintf(ti + len, "%d", a - b);
len = strlen(ti);
*(ti + len) = ')'; len++;
return len;
}//在往题目字符串组中存a的时候,把a拆成两个数相加,并且带上括号
else if (a > 7&&a<80&& getrand_mod_unpasstime(4)==1)
{
int b = MOD;
while (a + b >= MOD)
{
b=getrand_mod_unpasstime(a);
}
*(ti + len) = '('; len++;
sprintf(ti + len, "%d", a+b);
len = strlen(ti);
*(ti + len) = '-'; len++;
sprintf(ti + len, "%d", b);
len = strlen(ti);
*(ti + len) = ')'; len++;
return len;
}//改成相减,带括号
else
{
sprintf(ti + len, "%d", a);
return strlen(ti);
} //正常生成
}
//存下单个数据
double getemp(char* te, int *i,int len)//获得数字
{
double temp = 0;
while (isdigit(te [*(i)])&&*i<len)
{
temp *= 10;
temp += *(te + *(i)) - '0';
( *i)++;
}
return temp;
}
//从字符组中得到数据
void set_title_1st(char* ti)//生成第一题
{
int a, b, c;
a = getrand_mod(MOD);
b = getrand_mod(MOD);
while (a < b)
{
a = a + 100 - b;
}
c = getrand_mod_unpasstime(6);
xiuzheng(&a,& b, &c);
int len = strlen(ti);
len = fillint(a, ti, len);
*(ti + len) = c + '*'; len++;
len = fillint(b, ti, len);
}
//向题中存a数据,生成题目
void set_title_next(char* ti,double ans)//生成接下来的题
{
int b, c;
int a = (int)ans;
c = getrand_mod(6);
b = getrand_mod(MOD);
xiuzheng(&a,&b,&c);
int len = strlen(ti);
*(ti + len++) = c + '*';
len = fillint(b, ti, len);
}
double getans(char* t)//用的是栈的原理
{
double ans = 0;
double temp[1000];
memset(temp, 0, sizeof(temp));
int len = strlen(t);
int top = 0;
int i = 0;
if (*(t + i) == '(')
{
i++;
temp[++top] = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
temp[top] += getemp(t, &i, len);
}
else
{
i++;
temp[top] -= getemp(t, &i, len);
}
i++;
}
else
{
temp[top] = getemp(t, &i, len);
}
for (; i < len; )
{
{
if (*(t + i) - '*' == 1)
{
i++;
if (*(t + i) == '(')
{
i++;
temp[++top] = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
temp[top] += getemp(t, &i, len);
}
else
{
i++;
temp[top] -= getemp(t, &i, len);
}
i++;
}
else
{
temp[++top] = getemp(t, &i, len);
}
}
if (*(t + i) - '*' == 3)
{
i++;
if (*(t + i) == '(')
{
i++;
temp[++top] -= getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
temp[top] -= getemp(t, &i, len);
}
else
{
i++;
temp[top] += getemp(t, &i, len);
}
i++;
}
else
{
temp[++top] -= getemp(t, &i, len);
}
}
if (*(t + i) =='*' )
{
i++;
if (*(t + i) == '(')
{
double tt=0;
i++;
tt = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
tt += getemp(t,& i, len);
}
else
{
i++;
tt -= getemp(t, &i, len);
}
i++;
temp[top] *= tt;
}
else
{
temp[top] *= getemp(t, &i, len);
}
}
if (*(t + i) - '*' == 5)
{
i++;
if (*(t + i) == '(')
{
double tt = 0;
i++;
tt = getemp(t, &i, len);
if ((*(t + i) - '*') == 1)
{
i++;
tt += getemp(t,& i, len);
}
else
{
i++;
tt -= getemp(t, &i, len);
}
i++;
temp[top] /= tt;
}
else
{
temp[top] /= getemp(t, &i, len);
}
}
}
}
for (int i = 0; i <=top; i++)
{
ans += temp[i];
}
return ans;
}
//得到答案
int core()//核心代码
{
char m[10000];
int time = 0;
int t = 0;
do
{
t = 0;
memset(m, 0, sizeof(m));
set_title_1st(m);
mans=getans(m);
while (t < 2||getrand_mod_unpasstime(2)||t>10 )//保底也生成两个符号的算式,当然生成更多就听天由命了
{
set_title_next(m, mans);
mans=getans(m);
t++;
}
if (mans <= 10 || mans >= 90&&mans!=1&&mans!=100)
time++;
else time = 0;
} while (mans>=MOD||mans<=1||mans!=(int)mans||time ==1);//这里一堆条件全是因为我菜,生成ans=1和100的概率加起来有25了,生成ans《10和ans》90的概念加起来有50
char cr='\n';
puts(m);
double ans = 1;
if (zhuobi == 1)
printf("ans:%lf\n", mans);
rewind(stdin);
t = 1;
// t = scanf("%lf%c", &ans, &cr);
if (t == 0) { return 2; }
else {
if (cr != '\n') { return 2; }
if (fabs(ans - mans) <= 0.001)//浮点误差
{
return 1;
}
else { return 0; }
}
}
void ininin(double a, double b, double c)
{
FILE* p;
p = fopen("t.txt", "ab+");
// fseek(p,-1,2);
fprintf(p, "%lf ", a);
fprintf(p, "%lf ", b);
fprintf(p, "%lf ", c);
fclose(p);
}//存数据
void practice()//练习模式
{
int t = 0;
double r = 0, w = 0;
printf("练习模式启动,输入非数字结束\n");
while (1)
{
t = core();
if (t == 2) { printf("练习模式结束\n"); break; }
if (t == 1) { printf("回答正确,正在生成下一题\n"); r++; }
if (t == 0) { printf("回答错误,正确答案:%.0lf,正在生成下一题\n",mans); w++; }
printf("正确率:%2.1f%%\n", (r / (w + r)) * 100);
}
}
void text()
{
int sum;
printf("考试模式启动,请输入考试的题目数:");
scanf("%d", &sum);
int bn = 0;
double r = 0, w = 0;
int t;
while (bn < sum)
{
printf("第%d题:\n", bn + 1);
t = core();
if (t == 2) { printf("请不要输入无关的字符\n"); w++; }
if (t == 1) r++;
if (t == 0) w++;
bn++;
}
printf("考试结束,本次考试总题数:%.0f,答对题数:%.0f,正确率:%2.1f%%\n", w + r, r, (r / (w + r)) * 100);
ininin(w + r, r, (r / (w + r)) * 100);
}//考试模式
void vi()
{
FILE* p;
if (!(p = fopen("t.txt", "r")))
{
printf("您没进行过考试\n");
}
int n = 1;
double a, b, c;
while (fscanf(p, "%lf %lf %lf\n", &a, &b, &c) != EOF)
{
printf("第%d次考试: 总题数:%.0f,答对题数:%.0f,正确率:%2.1f%%\n", n, a, b, c);
n++;
}
fclose(p);
}//查看考试数据
char al[5]= "alll";
void de()
{
char in[30];
printf("您确定要删除考试数据吗?确定输入1,否则输入0\n");
int t;
scanf("%d", &t);
vi();
printf("请输入要删除第几次考试数据,如果全要删除,输入'all'\n");
scanf("%s", in);
if (t)
{
if (strcmp(in,al)==0)
{
remove("t.txt");
printf("考试数据已经删除\n");
}
else if(isdigit(in[0]))
{
int tt;
tt = atoi(in);
FILE* p;
FILE* q;
double te1, te2, te3;
p = fopen("t.txt", "r");
q = fopen("e.txt", "w");
int i = 1;
while (~fscanf(p, "%lf %lf %lf", &te1, &te2, &te3))
{
if (i != tt)
fprintf(q, "%lf %lf %lf ", te1, te2, te3);
i++;
}
fclose(p);
fclose(q);
remove("t.txt");
rename("e.txt", "t.txt");
printf("考试数据已经删除\n");
}
else
{
printf("您未删除任何考试数据,删除模式结束\n ");
}
}
}
int main()
{
char mode[100];
while (1)
{
printf("---------------------------------------------------------\n输入'p'开启练习模式\n输入't'开启考试模式\n输入'v'查看历史考试情况\n输入'd'删除考试数据\n");
printf("保证结果是整数\n");
printf("输入'e'退出程序\n---------------------------------------------------------\n");
rewind(stdin);
scanf("%s", mode);
if (mode[0] == 'p')
{
practice();
}
else if (strcmp(hihi, mode) == 0)
{
if (zhuobi == 0)
{
printf("作弊系统激活\n"); zhuobi = 1;
}
else
{
printf("作弊系统关闭\n"); zhuobi = 0;
}
}
else if (mode[0] == 'e')
break;
else if (mode[0] == 't')
{
text();
}
else if (mode[0] == 'v')
{
vi();
}
else if (mode[0] == 'd')
{
de();
}
else
{
printf("无效输入\n");
}
}
}