• 实现一个自动生成小学四则运算题目的命令行程序


    C语言实现简单自动生成小学四则运算题目

    作者:邱彬

    协作者:麦狄龙(麦狄龙指导我指导他为指导我的指导人)

    1.GitHub项目网址:

     https://github.com/QiuBin666/MyApp.exe

    2.个人PSP

    PSP(严格来说是基于团队的PSP)

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划 10  
    · Estimate · 估计这个任务需要多少时间 20  
    Development 开发 1200  
    · Analysis · 需求分析 (包括学习新技术) 180  
    · Design Spec · 生成设计文档 60  
    · Design Review · 设计复审 (和同事审核设计文档) 20  
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 60  
    · Design · 具体设计 120  
    · Coding · 具体编码 360  
    · Code Review · 代码复审 60  
    · Test · 测试(自我测试,修改代码,提交修改) 180  
    Reporting 报告 60  
    · Test Report · 测试报告 60  
    · Size Measurement · 计算工作量 10  
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30  
    合计   2430  

    3.题目介绍与解题思路

    3.1题目介绍:

    1. 使用 -n 参数控制生成题目的个数,例如:Myapp.exe -n 10 将生成10个题目。

    2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如 Myapp.exe -r 10 ,将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

    3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。

    4. 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数

    5. 每道题目中出现的运算符个数不超过3个。

    6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

    7. 生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:

      四则运算题目1

      四则运算题目2

      ……

      其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

      在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

      1.答案1

      2.答案2

      特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

    8. 程序应能支持一万道题目的生成。

    9. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

      Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

      统计结果输出到文件Grade.txt,格式如下:

      Correct: 5 (1, 3, 5, 7, 9)

      Wrong: 5 (2, 4, 6, 8, 10)

      其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

    3.2解题思路:

    1. 生成表达式:表达式由随机数和运算符两部分组成,运算符生成运用rand函数来随机生成一个1到4的变量,分别对应加号,减号,乘号,除号,当运算符为除号的时候我们采用了辗转相除法,写一个gcd函数来求出两个数的最大公约数,这样来实现输出分数的要求;随机数生成也运用rand函数来实现。

    2. 生成题目文件和答案文件:先定义两个文件指针,指向相对应要写入的文件Answer.txt和Exercise.txt,然后生成文件并打开文件,通过fprinft函数将生成的题目和答案写入到相应的文件。

            3.  判定答案中的对错并进行数量统计:只需对前面生成的题目文件和答案文件进行操作,分三步:

                (1).计算题目的数量x:遍历Exercise.txt,遇到换行符x加1。

        (2).分别读取Answer.txt和Exercise.txt的答案:读取等号右边的数据。

        (3).判断第二步读取的两个答案是否相等,记录序号并生成Grade.txt文件。

    4.设计实现过程

     

     5.关键代码展示与说明

    主函数:

     1 int main()
     2 {
     3         int subnumber,max;
     4         int opnum;
     5         int caseone(int numb1,int numb2,int max,int i);        //函数的声明
     6         int casetwo(int numb1,int numb2,int numb3,int max,int i);
     7         FILE *fp;
     8         fp=fopen("Exercises.txt","w");
     9         fp=fopen("Answers.txt","w");            //建立文件
    10         fclose(fp);
    11         srand((unsigned)time(0));                //为保证每次运行程序的时候生成的题目都不一样
    12         printf("***************随机生成四则运算题目*****************************
    ");
    13         printf("1.使用 -n 参数控制生成题目的个数
    ");
    14         printf("2.使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
    ");
    15         printf("请输入n:");
    16         scanf("%d",&subnumber); 
    17         printf("请输入r:");
    18         scanf("%d",&max); 
    19         printf("题目生成中,请稍后...
    "); 
    20         for(i=1;i<=subnumber;i++)        //for循环生成题目
    21         {
    22             opnum=rand()%2+1;
    23             switch(opnum)        
    24             {
    25             case 1 :                            //当随机数是生成1个运算符时
    26                 numb1=rand()%max;
    27                 numb2=rand()%max;
    28                 caseone(numb1,numb2,max,i);        //执行函数的同时得同时执行把表达式输出到txt文件中
    29                 break;
    30             case 2 :            //当随机数是生成2个运算符时
    31                 numb1=rand()%max;
    32                 numb2=rand()%max;
    33                 numb3=rand()%max;
    34                 casetwo(numb1,numb2,numb3,max,i);
    35                 break;    
    36             default:printf("ERROR
    ");
    37             }
    38         }
    39         char file1[10],file2[10],s[3];
    40         int *exe;
    41         int *an;
    42         printf("校对文件答案并生成Grade.txt文件
    ");
    43         printf("请输入练习文本:
    "); 
    44         scanf("%s",file1);
    45         printf("请输入答案文本:
    "); 
    46         scanf("%s",file2);
    47         int n;
    48         n=Count(file1);
    49         exe=(int*)malloc(n*sizeof(int));
    50         an=(int*)malloc(n*sizeof(int));
    51         GetAnswers(file1,exe);
    52         GetAnswers(file2,an);
    53         Put_Judge(exe,an,n);
    54         return 0;
    55 
    56 }
    View Code

    子函数:

      1 int numb1,numb2,numb3,i;    //随机生成的数值
      2 int op1,op2;    //运算符
      3 FILE *fp;    //指向答案文件 
      4 FILE *fb;    //指向题目文件 
      5 
      6 int gcd(int numb1,int numb2)    //辗转相除法 
      7 {
      8         if(numb2==0) return numb1;
      9         return    gcd(numb2,numb1%numb2);    
     10 }
     11 
     12 int caseone(int numb1,int numb2,int max,int i)        
     13 {    
     14         int gcd(int numb1,int numb2);
     15         int temp;    //中间值
     16         int result;
     17         op1=rand()%4+1;        //op1的生成值为1到4,分别对应加法,减法,乘法,除法
     18         fb=fopen("Exercises.txt","a");
     19         fp=fopen("Answers.txt","a");    //打开文件
     20         switch(op1){
     21             case 1:        //op1为1的时候,执行加法操作
     22                 result=numb1+numb2;
     23                 fprintf(fp,"%d.答案=%d
    ",i,result);        //写入文件
     24                 fclose(fp);            //关闭文件
     25                 fprintf(fb,"%d.%d+%d=%d
    ",i,numb1,numb2,result);        
     26                 fclose(fb);    
     27                 break;
     28             case 2 :        //op1为2的时候,执行减法操作;
     29                 if(numb1<numb2)        //为保证结果不为零,当出现生成的被减数比减数小,进行两者值的交换
     30                 {
     31                 temp=numb1;
     32                 numb2=numb1;
     33                 numb1=temp;
     34                 }
     35                 result=numb1-numb2;
     36                 fprintf(fp,"%d.答案=%d
    ",i,result);
     37                 fclose(fp);
     38                 fprintf(fb,"%d.%d-%d =%d
    ",i,numb1,numb2,result);
     39                 fclose(fb);
     40                 break;
     41             case 3 :        //op1为3的时候,执行乘法操作;
     42                 result=numb1*numb2;
     43                 fprintf(fp,"%d.答案=%d
    ",i,result);
     44                 fclose(fp);
     45                 fprintf(fb,"%d.%d*%d =%d
    ",i,numb1,numb2,result);
     46                 fclose(fb);
     47                 break;
     48             case 4 :        //op1为4的时候,执行除法操作;
     49                 if(numb2==0)
     50                     numb2=rand()%max+1;
     51                 temp=gcd(numb1,numb2);
     52                 fprintf(fp,"%d.答案=%d/%d
    ",i,numb1/temp,numb2/temp);
     53                 fclose(fp);
     54                 fprintf(fb,"%d.%d/%d =%d/%d
    ",i,numb1,numb2,numb1/temp,numb2/temp);
     55                 fclose(fb);
     56                 break;
     57             default:printf("ERROR
    ");
     58         }
     59         return 0;
     60 }
     61 
     62 int casetwo(int numb1,int numb2,int numb3,int max,int i)
     63 {    
     64         int gcd(int numb1,int numb2);
     65         int result, result1,temp,temp1;
     66         op1=rand()%4+1;        
     67         op2=rand()%4+1;                        //op1,op2的生成值为1到4,分别对应加法,减法,乘法,除法
     68         fp=fopen("Answers.txt","a");
     69         fb=fopen("Exercises.txt","a");
     70         switch(op1){
     71             case 1 :        
     72                 switch(op2){
     73                 case 1 :                    //op1,op2均为加法的情况
     74                     result1=numb1+numb2;
     75                     result=result1+numb3;
     76                     fprintf(fp,"%d.答案=%d
    ",i,result);
     77                     fclose(fp);
     78                     fprintf(fb,"%d.%d+%d+%d%=%d
    ",i,numb1,numb2,numb3,result);
     79                     fclose(fb);
     80                     break;
     81                 case 2 :                    //op1为加法,op2为减法的情况
     82                     result1=numb1+numb2;
     83                     if(result1<numb3)
     84                     {
     85                         temp=numb3;
     86                         numb3=numb2;
     87                         numb2=temp;
     88                     }
     89                     result=numb1+numb2-numb3;
     90                     fprintf(fp,"%d.答案=%d
    ",i,result);
     91                     fclose(fp);
     92                     fprintf(fb,"%d.%d+%d-%d%=%d
    ",i,numb1,numb2,numb3,result);
     93                     fclose(fb);
     94                     break;
     95                 case 3 :                    //op1为加法,op2为乘法的情况
     96                     result1=numb2*numb3;
     97                     result=numb1+result1;
     98                     fprintf(fp,"%d.答案=%d
    ",i,result);
     99                     fclose(fp);
    100                     fprintf(fb,"%d.%d+%d*%d%=%d
    ",i,numb1,numb2,numb3,result);
    101                     fclose(fb);
    102                     break;
    103                 case 4 :                    //op1为加法,op2为除法的情况
    104                     if(numb3==0)
    105                     {
    106                     numb3=rand()%max+1;
    107                     }
    108                     temp=gcd(numb2,numb3);
    109                     fprintf(fp,"%d.答案=%d'%d/%d
    ",i,numb1,numb2/temp,numb3/temp);
    110                     fclose(fp);
    111                     fprintf(fb,"%d.%d+%d/%d%=%d'%d/%d
    ",i,numb1,numb2,numb3,numb1,numb2/temp,numb3/temp);
    112                     fclose(fb);
    113                     break;
    114                 default:printf("ERROR
    ");
    115                 }
    116                 break;
    117             case 2 :        
    118                 switch(op2){
    119                     case 1 :                    //op1为减法,op2为加法的情况
    120                         if(numb1<numb2)            //为保证结果不为零,当出现生成的被减数比减数小,进行两者值的交换
    121                         {
    122                             temp=numb1;
    123                             numb2=numb1;
    124                             numb1=temp;
    125                         }
    126                         result=numb1-numb2+numb3;
    127                         fprintf(fp,"%d.答案=%d
    ",i,result);
    128                         fclose(fp);
    129                         fprintf(fb,"%d.%d-%d+%d%=%d
    ",i,numb1,numb2,numb3,result);
    130                         fclose(fb);
    131                         break;
    132                     case 2 :                    //op1为减法,op2为减法的情况
    133                         do{
    134                         numb1=rand()%max;
    135                         numb2=rand()%max;
    136                         numb3=rand()%max;
    137                         }while((numb1-numb2-numb3)<=0);
    138                         result=numb1-numb2-numb3;
    139                         fprintf(fp,"%d.答案=%d
    ",i,result);
    140                         fclose(fp);
    141                         fprintf(fb,"%d.%d-%d-%d%=%d
    ",i,numb1,numb2,numb3,result);
    142                         fclose(fb);
    143                         break;
    144                     case 3 :                    //op1为减法,op2为乘法的情况
    145                         do{
    146                         numb1=rand()%max;
    147                         numb2=rand()%max;
    148                         numb3=rand()%max;
    149                         }while((numb1-numb2*numb3)<0);
    150                         result=numb1-numb2*numb3;
    151                         fprintf(fp,"%d.答案=%d
    ",i,result);
    152                         fclose(fp);
    153                         fprintf(fb,"%d.%d-%d*%d%=%d
    ",i,numb1,numb2,numb3,result);
    154                         fclose(fb);
    155                         break;
    156                     case 4 :                    //op1为减法,op2为除法的情况
    157                         do{
    158                         numb1=rand()%max;
    159                         numb2=rand()%max;
    160                         numb3=rand()%max;
    161                         }while((numb1-numb2/numb3)<0||numb3==0);
    162                         result=numb1-numb2/numb3;
    163                         fprintf(fp,"%d.答案=%d
    ",i,result);
    164                         fclose(fp);
    165                         fprintf(fb,"%d.%d-%d/%d%=%d
    ",i,numb1,numb2,numb3,result);
    166                         fclose(fb);
    167                         break;
    168                 default:printf("ERROR
    ");
    169                 }
    170                 break;
    171             case 3 :        
    172                 switch(op2){
    173                     case 1 :                    //op1为乘法,op2为加法的情况
    174                         result=numb1*numb2+numb3;
    175                         fprintf(fp,"%d.答案=%d
    ",i,result);
    176                         fclose(fp);
    177                         fprintf(fb,"%d.%d*%d+%d%=%d
    ",i,numb1,numb2,numb3,result);
    178                         fclose(fb);
    179                         break;
    180                     case 2 :                    //op1为乘法,op2为减法的情况
    181                         do{
    182                         numb1=rand()%max;
    183                         numb2=rand()%max;
    184                         numb3=rand()%max;
    185                         }while((numb1*numb2-numb3)<0);
    186                         result=numb1*numb2-numb3;
    187                         fprintf(fp,"%d.答案=%d
    ",i,result);
    188                         fclose(fp);
    189                         fprintf(fb,"%d.%d*%d-%d%=%d
    ",i,numb1,numb2,numb3,result);
    190                         fclose(fb);
    191                         break;
    192                     case 3 :                    //op1为乘法,op2为乘法的情况
    193                         result=numb1*numb2*numb3;
    194                         fprintf(fp,"%d.答案=%d
    ",i,result);
    195                         fclose(fp);
    196                         fprintf(fb,"%d.%d*%d*%d%=%d
    ",i,numb1,numb2,numb3,result);
    197                         fclose(fb);
    198                         break;
    199                     case 4 :                    //op1为乘法,op2为除法的情况
    200                         do{
    201                         numb3=rand()%max;
    202                         }while(numb3==0);
    203                         temp1=numb1*numb2;
    204                         temp=gcd(temp1,numb3);
    205                         fprintf(fp,"%d.答案=%d/%d
    ",i,temp1/temp,numb3/temp);
    206                         fclose(fp);
    207                         fprintf(fb,"%d.%d*%d/%d%=%d/%d
    ",i,numb1,numb2,numb3,temp1/temp,numb3/temp);
    208                         fclose(fb);
    209                         break;
    210                 default:printf("ERROR
    ");
    211                 }
    212                 break;
    213             case 4 :        
    214                 switch(op2){
    215                     case 1 :                    //op1为除法,op2为加法的情况
    216                         do{
    217                         numb2=rand()%max;
    218                         }while(numb2==0);
    219                         temp=gcd(numb1,numb2);
    220                         fprintf(fp,"%d.答案=%d'%d/%d
    ",i,numb3,numb1/temp,numb2/temp);
    221                         fclose(fp);
    222                         fprintf(fb,"%d.%d/%d+%d%=%d'%d/%d
    ",i,numb1,numb2,numb3,numb3,numb1/temp,numb2/temp);
    223                         fclose(fb);
    224                         break;
    225                     case 2 :                    //op1为除法,op2为减法的情况
    226                         do{
    227                         numb3=rand()%max;
    228                         }while(    (numb1/numb2-numb3)<0||numb2==0);
    229                         result=numb1/numb2-numb3;
    230                         fprintf(fp,"%d.答案=%d
    ",i,result);
    231                         fclose(fp);
    232                         fprintf(fb,"%d.%d/%d-%d%=%d
    ",i,numb1,numb2,numb3,result);
    233                         fclose(fb);
    234                         break;
    235                     case 3 :                    //op1为除法,op2为乘法的情况
    236                         do{
    237                         numb2=rand()%max;
    238                         }while(numb2==0);
    239                         temp1=numb1*numb3;
    240                         temp=gcd(temp1,numb2);
    241                         result=numb1/numb2*numb3;
    242                         fprintf(fp,"%d.答案=%d/%d
    ",i,temp1/temp,numb2/temp);
    243                         fclose(fp);
    244                         fprintf(fb,"%d.%d/%d*%d%=%d/%d
    ",i,numb1,numb2,numb3,temp1/temp,numb2/temp);
    245                         fclose(fb);
    246                         break;
    247                     case 4 :                    //op1为除法,op2为除法的情况
    248                         do{
    249                         numb2=rand()%max;
    250                         numb3=rand()%max;
    251                         }while(numb3==0||numb2==0);
    252                         result=numb1/numb2/numb3;
    253                         temp1=numb2*numb3;
    254                         temp=gcd(temp1,numb1);
    255                         fprintf(fp,"%d.答案=%d/%d
    ",i,numb1/temp,temp1/temp);
    256                         fclose(fp);
    257                         fprintf(fb,"%d.%d/%d/%d%=%d/%d
    ",i,numb1,numb2,numb3,numb1/temp,temp1/temp);
    258                         fclose(fb);
    259                         break;
    260                 default:printf("ERROR
    ");
    261                 }
    262                 break;
    263             default:printf("ERROR
    ");
    264         }
    265         return 0;
    266 }
    267 
    268 
    269 int Count(char file[])  /*计算的题目数量*/ 
    270 {
    271     FILE *fp1;
    272     char a;
    273     int x=0;
    274     if((fp1=fopen(file,"r"))==NULL)
    275     {
    276         printf("read file failed!
    ");
    277         exit(0);
    278     }
    279     while(!feof(fp1))
    280     {
    281         a=fgetc(fp1);
    282         if(a=='
    ')
    283             x++;
    284     }      
    285     fclose(fp1);
    286     return x;
    287 }
    288 
    289 void Put_Judge(int *str1,int *str2,int n) /* 答案判断对错函数*/ 
    290 {
    291     int i,j;
    292     FILE *out;
    293     out=fopen("Grade.txt","w");
    294     for(i=0,j=0;i<n;i++)     /*对的个数*/ 
    295         if(*(str1+i)==*(str2+i))
    296         j++;    
    297     fprintf(out,"Correct:%d (",j);
    298     for(i=0;i<n;i++)     /*对的序号*/ 
    299     {
    300         if(*(str1+i)==*(str2+i))
    301         fprintf(out," %d ",(i+1));
    302     }
    303     fprintf(out,")
    ");
    304      fprintf(out,"Wrong:%d (",(n-j));
    305     for(i=0;i<n;i++)  /*错的序号*/ 
    306     {
    307         if(*(str1+i)!=*(str2+i))
    308         fprintf(out," %d ",(i+1));
    309     }
    310     fprintf(out,")
    ");
    311     fclose(out);
    312     printf("OK");
    313 }
    314 
    315 void GetAnswers(char infile[],int *str)  /*读取学生答案的函数*/ 
    316 {
    317     FILE *in;
    318     char a;
    319     int i=0;
    320 if((in=fopen(infile,"r"))==NULL)
    321     {
    322        printf("read file failed!
    "); 
    323        exit(0);
    324     } 
    325     while(!feof(in))
    326     {
    327         *(str+i)=0;
    328         a=fgetc(in);        
    329         if(a!='=') 
    330         continue;
    331         while(1)
    332         {
    333             a=fgetc(in);
    334             if(a=='
    ')break;
    335             *(str+i)*=10;    
    336             *(str+i)+=(a-48);
    337         }
    338             printf("%d ",*(str+i));
    339             i++;
    340     }
    341     printf("
    ");
    342     fclose(in);
    343 }
    View Code

    6.测试运行

    生成10道题目:

     

     生成100道题目:

     

     生成10000道题目:

     

     故意将前三道题目答案改错:

    7.项目完结个人PSP

     

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划 10 10
    · Estimate · 估计这个任务需要多少时间 20 10
    Development 开发 1200 1200
    · Analysis · 需求分析 (包括学习新技术) 180 120
    · Design Spec · 生成设计文档 60 30
    · Design Review · 设计复审 (和同事审核设计文档) 20 30
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 60 60
    · Design · 具体设计 120 150
    · Coding · 具体编码 360 390
    · Code Review · 代码复审 60 90
    · Test · 测试(自我测试,修改代码,提交修改) 180 210
    Reporting 报告 60 90
    · Test Report · 测试报告 60 30
    · Size Measurement · 计算工作量 10 10
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 30
    合计   2430 2460

    8.项目小结:

    收获:更熟悉psp的操作方法,对c语言文件读写方法有了更深的理解,是一次很好的打码练习,同时作为合作项目,认识到1+1>2的道理,队友的作用不在于分担了多少代码量,关键时刻的提醒和建议往往起到事半功倍的作用。

    不足:部分功能未能实现,个人能力需要加强。

  • 相关阅读:
    uva 550
    uva 10110
    uva 10014
    uva 10177
    uva 846
    Dear Project Manager, I Hate You
    创业型软件公司的心得
    架构设计的心得
    程序员常去的103个网站
    66个经典源码网站
  • 原文地址:https://www.cnblogs.com/Qiu-Bin/p/12617120.html
Copyright © 2020-2023  润新知