结对项目(自动生成四则运算题目程序)

Posted vigor-0726

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结对项目(自动生成四则运算题目程序)相关的知识,希望对你有一定的参考价值。

一、Github项目地址:https://github.com/Vigor-creat/-.git

项目成员:胡兆禧 3118005092  余金龙 3118005116

二.PSP

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

  

三、效能分析

10道题目,运算符个数最大为3,数值100以内,生成并计算需要157.548s

由于程序实现过程中运用了随机函数,但c语言的随机数函数的时间种子无法在短暂的时间内变动,为使得每次调用随机数函数产生的值不同,不得已加入sleep()函数,导致程序运行时间增加。

技术图片

四、设计实现过程

技术图片

五、代码说明

1.四则运算表达式生成和计算程序代码

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<time.h>
  4 #include<stack>
  5 #include<windows.h>
  6 
  7 
  8 
  9 using std::stack;
 10 //计算算术表达式
 11 int ch2num ( const char &ch )  //读取运算符
 12 {
 13     int num ( -1 );
 14     switch ( ch )
 15     {
 16     case#:
 17         num = 0;
 18         break;
 19     case+:
 20         num = 1;
 21         break;
 22     case-:
 23         num = 2;
 24         break;
 25     case*:
 26         num = 3;
 27         break;
 28     case/:
 29         num = 4;
 30         break;
 31     case(:
 32         num = 5;
 33         break;
 34     case):
 35         num = 6;
 36         break;
 37     }
 38     return num;
 39 }
 40 
 41 int operator_2 ( const int &num1, const int &num2, const char &ch )  //进行单个运算符的运算
 42 {
 43     int num ( -1 );
 44     switch ( ch )
 45     {
 46     case+:
 47         num = num2 + num1;
 48         break;
 49     case-:
 50         num = num2 - num1;
 51         break;
 52     case*:
 53         num = num2 * num1;
 54         break;
 55     case/:
 56         num = num2 / num1;
 57         break;
 58     }
 59     return num;
 60 }
 61 
 62 int compare[5][6] = { { 0 }, { 1, 0, 0, 0, 0, 1 }, { 1, 0, 0, 0, 0, 1 }, { 1, 1, 1, 0, 0, 1 }, { 1, 1, 1, 0, 0, 1 } };  //创建一个二维数组记录运算符之间的优先级
 63 
 64 int Calculation ( char *str, int i )  //计算算术表达式主体函数
 65 {
 66     stack<int>S_num;  //创建两个栈存放数值和运算符
 67     stack<char>S_ch;
 68     while ( !S_ch.empty() )
 69         S_ch.pop();
 70     S_ch.push ( # );
 71     while ( !S_num.empty() )
 72         S_num.pop();
 73     int tnum ( 0 );
 74     for ( int i ( 0 ); str[i] != ; )
 75     {
 76         if ( 0 <= str[i] && str[i] <= 9 )  //将字符数组中的数字由字符型转化为整型
 77         {
 78             tnum *= 10;
 79             tnum += str[i] - 0;
 80             ++i;
 81         }
 82         else if ( str[i] == ( )  //判断小括号类型并压入字符栈
 83         {
 84             S_ch.push ( ( );
 85             ++i;
 86         }
 87         else if ( str[i] == ) )
 88         {
 89             S_num.push ( tnum );
 90             char ch = S_ch.top();  //计算小括号内的表达式,并将结果压入数值栈
 91             if ( ch != ( )
 92             {
 93                 S_ch.pop();
 94                 int num1 = S_num.top();
 95                 S_num.pop();
 96                 int num2 = S_num.top();
 97                 S_num.pop();
 98                 tnum = operator_2 ( num1, num2, ch );
 99             }
100             else
101             {
102                 tnum = S_num.top();
103                 S_num.pop();
104             }
105             S_ch.pop();
106             ++i;
107         }
108         else
109         {
110             S_num.push ( tnum );
111             tnum = 0;
112             if ( compare[ch2num ( str[i] )][ch2num ( S_ch.top() )] == 1 )  //读入运算符优先级高则直接压入运算符栈
113                 S_ch.push ( str[i] );
114             else
115             {
116                 while ( compare[ch2num ( str[i] )][ch2num ( S_ch.top() )] == 0 )  //读入运算符优先级低,则将已读入优先级高的运算符先做运算并弹出,再压入
117                 {
118                     char ch = S_ch.top();
119                     S_ch.pop();
120                     int num1 = S_num.top();
121                     S_num.pop();
122                     int num2 = S_num.top();
123                     S_num.pop();
124                     S_num.push ( operator_2 ( num1, num2, ch ) );
125                 }
126                 S_ch.push ( str[i] );
127             }
128             ++i;
129         }
130     }
131     S_num.push ( tnum );
132     char ch (  );
133     while ( ( ch = S_ch.top() ) != # )  //将剩余运算符依次弹出执行
134     {
135         S_ch.pop();
136         int num1 = S_num.top();
137         S_num.pop();
138         int num2 = S_num.top();
139         S_num.pop();
140         S_num.push ( operator_2 ( num1, num2, ch ) );
141     }
142     FILE *fpWrite = fopen ( "Answers.txt", "a" );  //将计算结果写入Answers文件
143     if ( fpWrite == NULL )
144     {
145         return 0;
146     }
147     fprintf ( fpWrite, "Answer%d:	%d
", i, S_num.top() );
148     return 1;
149 }
150 
151 
152 
153 
154 
155 //生成算术表达式
156 int Random ( int m )  //随机生成给定范围内一个数字
157 {
158     int a;
159     srand ( ( unsigned ) time ( NULL ) );
160     Sleep ( 1000 );
161     a = rand() % m + 1;
162     return a;
163 }
164 
165 
166 char Symbol()  //随机生成‘+、-、*、/’运算符其中一个
167 {
168     int a, b = 0;
169     char x;
170     a = Random ( 4 );
171     do
172     {
173 
174 
175         switch ( a )
176         {
177         case 1:
178             x = +;
179             break;
180 
181         case 2:
182             x = -;
183             break;
184 
185         case 3:
186             x = *;
187             break;
188 
189         case 4:
190             x = /;
191             break;
192 
193         default:
194             b = 1;
195 
196         }
197     }
198     while ( b );
199     return x;
200 }
201 
202 
203 
204 char Brackets ( int co, int ad )  //根据给定参数判断并随机生成‘(、)’小括号
205 {
206     int a;
207     char x = #;
208     switch ( ad )
209     {
210     case 0:
211     {
212         a = Random ( 2 );
213         switch ( a )
214         {
215         case 1:
216             x = (;
217             break;
218 
219         case 2:
220             break;
221 
222         default:
223             break;
224         }
225     }
226 
227     case 1:
228     {
229         a = Random ( 2 );
230         if ( co != 0 )
231             switch ( a )
232             {
233             case 1:
234                 x = );
235                 break;
236 
237             case 2:
238                 break;
239 
240             default:
241                 break;
242             }
243         else
244             break;
245     }
246     }
247 
248     return x;
249 }
250 
251 
252 int File_write ( char *a, int i )  //将生成的算术表达式写入Eercises.txt文件
253 {
254     int j = 0;
255     FILE *fpWrite = fopen ( "Exercises.txt", "a" );
256     if ( fpWrite == NULL )
257     {
258         return 0;
259     }
260     fprintf ( fpWrite, "topic%d:	", i );
261     while ( a[j] != NULL )
262     {
263         if ( a[j] == + || a[j] == - || a[j] == * || a[j] == / || a[j] == = )
264             fprintf ( fpWrite, " %c ", a[j++] );
265         else
266             fprintf ( fpWrite, "%c", a[j++] );
267     }
268     fprintf ( fpWrite, " = " );
269     fprintf ( fpWrite, "
" );
270     fclose ( fpWrite );
271     return 1;
272 }
273 
274 
275 
276 void Arithmetic ( int i, int n, int m )  //生成算术表达式主体函数,n为最大运算符个数,m为数值范围,i为题目编号
277 {
278     char a[250] = {0};  //定义一个字符数组存放算术表达式
279     int x, p, add, rge, rng_num, count = 0, j = 0;  //count作为计数器,记录生成左括号的个数
280     rge = Random ( n );
281     for ( int k = 0; k < rge; k++ )  //循环生成算术表达式
282     {
283         add = 0;  //add作为标志值,影响Brackets()小括号生成函数内部执行
284         a[j] = Brackets ( count, add );  //随机生成左括号
285         if ( a[j] == ( )
286         {
287             j++;
288             count++;
289         }
290 
291         rng_num = Random ( m );  //生成一个参与表达式的数值
292         x = 1;
293         p = 0;
294         while ( rng_num / x )
295         {
296             x *= 10;
297         }
298         x /= 10;
299 
300         while ( x )
301         {
302             a[j++] = rng_num / x + 0;
303             rng_num = rng_num % x;
304             x /= 10;
305             p++;
306         }
307 
308         if ( a[j - 1 - p] != ( )
309         {
310             add = 1;
311             a[j] = Brackets ( count, add );
312             if ( a[j] == ) )
313             {
314                 j++;
315                 count--;
316             }
317         }
318 
319         a[j++] = Symbol();  //随机生成一个运算符
320 
321     }
322 
323 
324 
325     rng_num = Random ( m );  //生成一个随机结尾数值
326     x = 1;
327     while ( rng_num / x )
328     {
329         x *= 10;
330     }
331     x /= 10;
332 
333     while ( x )
334     {
335         a[j++] = rng_num / x + 0;
336         rng_num = rng_num % x;
337         x /= 10;
338     }
339 
340     while ( count )  //根据count值是否为0,判断所有左括号均有右括号对应
341     {
342 
343         a[j++] = );
344         count--;
345     }
346     while ( File_write ( a, i ) == 0 );  //写入生成的算术表达式
347     while ( Calculation ( a, i ) == 0 );  //计算结果
348 }
349 
350 
351 
352 
353 //主函数
354 int main()
355 {
356     int n, m, s, i;
357     printf ( "请输入算术表达式最多含运算符的个数:" );
358     scanf ( "%d,%d,%d", &n );
359     printf ( "请输入算术表达式内数值的范围:" );
360     scanf ( "%d", &m );
361     printf ( "请输入生成算术表达式的数量:" );
362     scanf ( "%d", &s );
363     FILE *fp1, *fp2;
364     fp1 = fopen ( "Exercises.txt", "w" );
365     fclose ( fp1 );
366     fp2 = fopen ( "Answers.txt", "w" );
367     fclose ( fp2 );
368     for ( i = 1; i <= s; i++ )
369     {
370         Arithmetic ( i, n, m );
371     }
372     return 0;
373 }

2.计算答案检验代码

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int main()
 5 {
 6     FILE *file1 = NULL, *file2 = NULL;
 7     char fp1, fp2;
 8     int r = 0, w = 0, wo[100] = {0}, ri[100] = {0}, t = 1, i = 0, j = 0;
 9     if ( ( file1 = fopen ( "Answers.txt", "r" ) ) == 0 )
10     {
11         printf ( "can‘t find the file-Answers
" );
12         exit ( 0 );
13     }
14     if ( ( file2 = fopen ( "exercisefile.txt", "r" ) ) == 0 )
15     {
16         printf ( "can‘t find the file-exercisefile
" );
17         exit ( 0 );
18     }
19     while ( ( fp1 = fgetc ( file1 ) ) != EOF && ( fp2 = fgetc ( file2 ) ) != EOF )
20     {
21         for ( ; fp1 != 
 || fp2 != 
; )
22         {
23             if ( fp1 != fp2 )
24             {
25                 w++;
26                 wo[i++] = t;
27                 break;
28             }
29             fp1 = fgetc ( file1 ), fp2 = fgetc ( file2 );
30         }
31         if ( fp1 == 
 && fp2 == 
 )
32         {
33             r++;
34             ri[j++] = t;
35         }
36         else if ( fp1 != 
 && fp1 != EOF )
37             while ( fp1 != 
 )
38                 fp1 = fgetc ( file1 );
39         while ( fp2 != 
 && fp2 != EOF )
40             fp2 = fgetc ( file2 );
41         t++;
42     }
43     FILE *fp3 = fopen ( "Grade.txt", "w" );
44     fclose ( fp3 );
45     FILE *fpWrite = fopen ( "Grade.txt", "a" );
46     fprintf ( fpWrite, "Correct:	%d", r );
47     if ( ri[0] != 0 )
48     {
49         fprintf ( fpWrite, "(" );
50         for ( i = 0; ri[i] != 0; i++ )
51             fprintf ( fpWrite, "%d,", ri[i] );
52         fprintf ( fpWrite, ")
" );
53     }
54     fprintf ( fpWrite, "Wrong:	%d", w );
55     if ( wo[0] != 0 )
56     {
57         fprintf ( fpWrite, "(" );
58         for ( i = 0; wo[i] != 0; i++ )
59             fprintf ( fpWrite, "%d,", wo[i] );
60         fprintf ( fpWrite, ")" );
61     }
62     fclose ( fpWrite );
63     fclose ( file1 );
64     fclose ( file2 );
65 }

 

六、测试运行

1.文件目录

技术图片

2.输入生成四则运算表达式要求

技术图片

3.题目Exercises.txt文件内容

技术图片

4.标准答案Answers.txt文件内容

技术图片

5.输入计算答案至exercisefile.txt文件中

技术图片

6.记录答案对错文件Grade.txt文件

技术图片

七、项目小结

1.此次项目采用C语言编程,设计过程中有一些问题难以解决,比如随机数生成函数需要保证数值不重复,必须采用sleep()函数,但增加了运行时间。

2.由于疫情影响,结对项目不得不在线上进行,队员之间的时间安排比较困难,并且队员之间的交流只能通过线上方式,很多想法的交流受到了一定的限制。

3.目前仍有一些要求的功能未实现,比如筛选重复的算术式,分数的运算等,这体现了解决问题的能力还有待提高。

以上是关于结对项目(自动生成四则运算题目程序)的主要内容,如果未能解决你的问题,请参考以下文章

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

结对项目:四则运算题目生成器(JAVA+GUI)

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

20175325 第二周结对编程项目 四则运算

# 2019-2020-4 《Java 程序设计》结对项目总结

20172316 结对编程-四则运算 第二周 阶段总结