结对编程二:小学四则运算题目生成器
1.题目
- 题目:
我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:
- 能够自动生成四则运算练习题
- 可以定制题目数量
- 用户可以选择运算符
- 用户设置最大数(如十以内、百以内等)
- 用户选择是否有括号、是否有小数
- 用户选择输出方式(如输出到文件、打印机等)
- 最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)
2.角色选择
- 驾驶员
- 能够完成全部代码工作,程序基本实现全部要求功能,并将代码上传至coding.net或者GitHub代码托管系统中
- 能够对导航员在本次编程工作中起到的作用给出客观评价,并完成500字以上的总结
- 领航员
- 能够辅助驾驶员完成全部代码工作,并且为关键函数选用合适的覆盖标准设计测试用例,并编写代码进行单元自动测试
- 能够根据上次作业的代码检查表对驾驶员的本次工作进行评价
能够对本次工作完成500字以上的总结
针对本次题目的要求,我和我的结对小伙伴郭金鑫商量之后,在此次作业中我选择了驾驶员这一角色,当然了,不是开车的老司机那种,而是开飞机的呢。
3.需求分析
拿到题目之后,我第一感觉是这次的作业已经开始真正的“软件工程”了。本次题目对我来说并不陌生,相信对很多人来说也都并不陌生。在上小学的时候,我的数学老师就要求我们买四则运算册子,每一篇都是同样的一种运算题型,针对性训练,一篇的题目量大约在50道左右,天天做,对于提升小学的运算水平有很大的提升。
回到题目,这次作业需要的就是一个小程序可以基本满足于小学数学四则运算的题目生成,若使用的人群是小学数学老师,还应该满足自动生成题目之后可以选择打印出来,方便学生们进行演算。
4.代码实现
- 首先应作业要求将我的程序代码上传到github:代码地址
- 其实整个程序功能最核心的部分就是随机数的生成,随机数既然有了结合运算符就可以生成运算式,而针对用户可以设置出题数量,仅需一个循环即可实现。
- 针对用户可以选择运算符这一需求,我想起了我当初做运算题册的时候,是针对性训练,即这一篇是加法,下一篇就是减法,这一篇全是乘法,下一篇就全是除法,这给了我启发,针对这一要求,我可以使用switch语句,每一个case就可以对应每一个运算,这样需求就实现了。功能代码如下:
switch(inmain)
{
case 1: //加法
for(int i=0;i<num;++i)
{
A[i] = rand()%10;
B[i] = rand()%10;
fout<<A[i]<<"+"<<B[i]<<"="<<endl;
cout<<A[i]<<"+"<<B[i]<<"="<<endl;
}break;
case 2: //减法
for(int i=0;i<num;++i)
{
A[i] = rand()%10;
B[i] = rand()%10;
cout<<A[i]<<"-"<<B[i]<<"="<<endl;
fout<<A[i]<<"-"<<B[i]<<"="<<endl;
}break;
case 3: //乘法
for(int i=0;i<num;++i)
{
A[i] = rand()%10;
B[i] = rand()%10;
cout<<A[i]<<"*"<<B[i]<<"="<<endl;
fout<<A[i]<<"*"<<B[i]<<"="<<endl;
}break;
case 4: //除法
for(int i=0;i<num;++i)
{
A[i] = (rand()%10)+1;
B[i] = (rand()%10)+1;
cout<<A[i]<<"/"<<B[i]<<"="<<endl;
fout<<A[i]<<"/"<<B[i]<<"="<<endl;
}break;
- 接下来就是解决混合型运算也就是带括号的运算,但凡一个运算式带了括号,一定是三元即三元以上,先来考虑没有括号的一个式子:a+b* c= 以及这个式子加了括号:(a+b) c= 、a+(bc)=;可以看到第二个式子所加的括号完全是没有必要的,也就是说在加括号时还必须考虑到所加括号是否有实际意义,也就是得把运算符的优先级考虑进来。之前说的其实是建立在某个基础之上的,这个基础就是首先得把整个运算式转换成字符串,之后使用针对字符串的遍历才能实现括号在正确的位置正确加入,而将数字转换为字符串的一个函数是itoa函数,
悲剧的是linux下此函数用不了,我又看到了sprintf函数,想到这儿,我跪了,太费事了...于是我转换了思路,一个简单的不能再简单的思路...先贴代码:
case 9:
for(int i=0;i<num;++i)
{
A[i] = rand()%100;
B[i] = rand()%100;
C[i] = rand()%100;
D[i] = rand()%100;
if(i%2==0)
{
cout<<A[i]<<"*"<<"("<<B[i]<<"-"<<C[i]<<")"<<"+"<<D[i]<<endl;
fout<<A[i]<<"*"<<"("<<B[i]<<"-"<<C[i]<<")"<<"+"<<D[i]<<endl;
}
else if(i%3==0)
{
cout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%5==0)
{
cout<<"("<<A[i]<<"+"<<B[i]<<")"<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<"("<<A[i]<<"+"<<B[i]<<")"<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%7==0)
{
cout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
fout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
}
else
{
cout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
fout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
}
}break;
可以看到这个样子就无比的简单,因为是小学运算,所以我默认混合运算设置为四元运算,同时我的括号是直接输出的,这样就解决了我的括号无论何时都是有意义的,潜在的问题就是在这个case下,我如果不对题目进行调整,一个循环出来后所有的题目假设30道,这30道题目所有的括号位置,包括题目格式都是一样的...想到这儿,我必须对题目做一个分类,其实也很简单,就是对用户输入进来的题目总数,假设还是30道,将这个按照能分别被2、3、5、7整除进行分类,调整了题目格式和括号所在的位置,这样,小朋友们做卷子时就不会有“哇,怎么题目都是千篇一律的!”的感受了...这么整,我觉得既简单的同时又很好的满足了需要。
- 至于小数的加入,就非常简单了,十以内的小数生成和百以内的小数生成无非是在整数的基础上动了点手脚
A[i] = (rand()%100)/10.0+1;
B[i] = (rand()%100)/10.0+1;
C[i] = (rand()%100)/10.0+1;
D[i] = (rand()%100)/10.0+1;
A[i] = (rand()%1000)/10.0+1;
B[i] = (rand()%1000)/10.0+1;
C[i] = (rand()%1000)/10.0+1;
D[i] = (rand()%1000)/10.0+1;
- 至此,基本上整个成品也成型了,为了便于查看,在此将全部代码贴上:
/*************************************************************************
> File Name: 四则运算生成.cpp
> Author: liililiu
> Created Time: 2018年04月12日 星期四 10时52分09秒
************************************************************************/
#include<iostream>
#include<ctime>
#include<stdlib.h>
#include<fstream>
using namespace std;
int srand(int);
int main()
{
srand((unsigned int)time(0));
int inmain;
float A[1000];
float B[1000];
float C[1000];
float D[1000];
int num;
char a;
int file;
cout<<"请选择你想要哪种运算?"<<endl
<<"1 为十以内加法运算;"<<endl
<<"2 为十以内减法运算;"<<endl
<<"3 为十以内乘法运算;"<<endl
<<"4 为十以内除法运算;"<<endl
<<"5 为百以内加法运算;"<<endl
<<"6 为百以内减法运算;"<<endl
<<"7 为百以内乘法运算;"<<endl
<<"8 为百以内除法运算;"<<endl
<<"9 为多元混合型运算;"<<endl
<<"10 为十以内小数运算;"<<endl
<<"11 为百以内小数运算;"<<endl
<<"0 为退出程序!"<<endl;
cin>>inmain;
if(inmain==0)
{
cout<<"谢谢使用"<<endl;
exit(0);
}
cout<<"请输入出题数量:"<<endl;
cin>>num;
cout<<"题目是否需要打印? 1是,0否!"<<endl;
cin>>file;
ofstream fout;
if(file==1)
{
fout.open("四则运算.txt");
fout<<num<<"道四则运算题如下:"<<endl;
}
else
{
cout<<num<<"道四则运算题如下:"<<endl;
}
switch(inmain)
{
case 1:
for(int i=0;i<num;++i)
{
A[i] = rand()%10;
B[i] = rand()%10;
fout<<A[i]<<"+"<<B[i]<<"="<<endl;
cout<<A[i]<<"+"<<B[i]<<"="<<endl;
}break;
case 2:
for(int i=0;i<num;++i)
{
A[i] = rand()%10;
B[i] = rand()%10;
cout<<A[i]<<"-"<<B[i]<<"="<<endl;
fout<<A[i]<<"-"<<B[i]<<"="<<endl;
}break;
case 3:
for(int i=0;i<num;++i)
{
A[i] = rand()%10;
B[i] = rand()%10;
cout<<A[i]<<"*"<<B[i]<<"="<<endl;
fout<<A[i]<<"*"<<B[i]<<"="<<endl;
}break;
case 4:
for(int i=0;i<num;++i)
{
A[i] = (rand()%10)+1;
B[i] = (rand()%10)+1;
cout<<A[i]<<"/"<<B[i]<<"="<<endl;
fout<<A[i]<<"/"<<B[i]<<"="<<endl;
}break;
case 5:
for(int i=0;i<num;++i)
{
A[i] = rand()%100;
B[i] = rand()%100;
cout<<A[i]<<"+"<<B[i]<<"="<<endl;
fout<<A[i]<<"+"<<B[i]<<"="<<endl;
}break;
case 6:
for(int i=0;i<num;++i)
{
A[i] = rand()%100;
B[i] = rand()%100;
cout<<A[i]<<"-"<<B[i]<<"="<<endl;
fout<<A[i]<<"-"<<B[i]<<"="<<endl;
}break;
case 7:
for(int i=0;i<num;++i)
{
A[i] = rand()%100;
B[i] = rand()%100;
cout<<A[i]<<"*"<<B[i]<<"="<<endl;
fout<<A[i]<<"*"<<B[i]<<"="<<endl;
}break;
case 8:
for(int i=0;i<num;++i)
{
A[i] = (rand()%100)+1;
B[i] = (rand()%100)+1;
cout<<A[i]<<"/"<<B[i]<<"="<<endl;
fout<<A[i]<<"/"<<B[i]<<"="<<endl;
}break;
case 9:
for(int i=0;i<num;++i)
{
A[i] = rand()%100;
B[i] = rand()%100;
C[i] = rand()%100;
D[i] = rand()%100;
if(i%2==0)
{
cout<<A[i]<<"*"<<"("<<B[i]<<"-"<<C[i]<<")"<<"+"<<D[i]<<endl;
fout<<A[i]<<"*"<<"("<<B[i]<<"-"<<C[i]<<")"<<"+"<<D[i]<<endl;
}
else if(i%3==0)
{
cout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%5==0)
{
cout<<"("<<A[i]<<"+"<<B[i]<<")"<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<"("<<A[i]<<"+"<<B[i]<<")"<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%7==0)
{
cout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
fout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
}
else
{
cout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
fout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
}
}break;
case 10:
for(int i=0;i<num;++i)
{
A[i] = (rand()%100)/10.0+1;
B[i] = (rand()%100)/10.0+1;
C[i] = (rand()%100)/10.0+1;
D[i] = (rand()%100)/10.0+1;
if(i%2==0)
{
cout<<A[i]<<"*"<<B[i]<<"-"<<C[i]<<"+"<<D[i]<<endl;
fout<<A[i]<<"*"<<B[i]<<"-"<<C[i]<<"+"<<D[i]<<endl;
}
else if(i%3==0)
{
cout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%5==0)
{
cout<<A[i]<<"+"<<B[i]<<"*"<<C[i]<<"-"<<D[i]<<endl;
fout<<A[i]<<"+"<<B[i]<<"*"<<C[i]<<"-"<<D[i]<<endl;
}
else if(i%7==0)
{
cout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
fout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
}
else
{
cout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
fout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
}
}break;
case 11:
for(int i=0;i<num;++i)
{
A[i] = (rand()%1000)/10.0+1;
B[i] = (rand()%1000)/10.0+1;
C[i] = (rand()%1000)/10.0+1;
D[i] = (rand()%1000)/10.0+1;
if(i%2==0)
{
cout<<A[i]<<"*"<<"("<<B[i]<<"-"<<C[i]<<")"<<"+"<<D[i]<<endl;
fout<<A[i]<<"*"<<"("<<B[i]<<"-"<<C[i]<<")"<<"+"<<D[i]<<endl;
}
else if(i%3==0)
{
cout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<A[i]<<"+"<<B[i]<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%5==0)
{
cout<<"("<<A[i]<<"+"<<B[i]<<")"<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
fout<<"("<<A[i]<<"+"<<B[i]<<")"<<"*"<<"("<<C[i]<<"-"<<D[i]<<")"<<endl;
}
else if(i%7==0)
{
cout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
fout<<A[i]<<"+"<<"("<<B[i]<<"-"<<C[i]<<")"<<"/"<<D[i]<<endl;
}
else
{
cout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
fout<<A[i]<<"/"<<"("<<B[i]<<"-"<<C[i]<<")"<<"*"<<D[i]<<endl;
}
}break;
}
if(file==1)
{
fout.close();
}
return 0;
}
liililiu@liililiu-PC:~/Desktop$
5.效果展示
首先我们来看下编译运行后的样子:
拿几个例子试验一下:
我们再来看下是否能保存到文件以备需求我的数学老师为可爱的小朋友们打印:
最后看一下是否友好交互:
到此,大吉大利!此次作业完成。
6.总结反思
通过这次结对作业编程,我锻炼了与人沟通的能力,在这个过程中,有很多小问题以及小思路上的不同见解,都是通过沟通解决的,同时也体会到了程序员解决问题一定是奔着需求去的,不能自己天马星空的想象,自以为是的增删需求。其实我这个随机的实现正如题目所说是伪随机,并没有真正的实现完全意义上的随机生成,这一点我后来会继续学习思考解决。在解决问题的过程中,一定要有耐心,有毅力,最后才能攻克困难。下面是我们的工作照: