The Second Teamwork
1、题目要求
我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:
能够自动生成四则运算练习题
可以定制题目数量
用户可以选择运算符
用户设置最大数(如十以内、百以内等)
用户选择是否有括号、是否有小数
用户选择输出方式(如输出到文件、打印机等)
最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)
2、人员职能分工
本次作业要求两个人合作完成,驾驶员和导航员两个角色:
驾驶员:王佳雨
基本完成全部代码工作,程序基本实现全部要求功能,并将代码上传到GitHub代码托管系统(此处附代码地址)中,
并对导航员在本次编程工作中起到的作用给出客观评价;
导航员:张学鑫
辅助驾驶员完成全部代码工作,并且为关键函数选用合适的覆盖标准设计测试用例,并编写代码进行单元自动测试,并且根据代码检查表对驾驶员的本次工作进行评价;
3、代码实现
(1)头文件代码:
include.h 头文件代码:
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include<ctime>
#include "solve.h"
// TODO: 在此处引用程序需要的其他头文件#pragma once
solve.h头文件代码:
// include.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include<ctime>
#include "solve.h"
// TODO: 在此处引用程序需要的其他头文件#pragma once
targetver.h头文件代码:
#pragma once
// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
#include <SDKDDKVer.h>
#pragma once
(2)运算生成代码:
// 四则运算生成器.cpp : 定义控制台应用程序的入口点。
/* 能够自动生成四则运算练习题
可以定制题目数量
可以选择运算符
用户设置最大数
是否有括号, 是否有小数
输出方式 输出到文件, 打印机
最好提供图形界面*/
#include "include.h"
using namespace std;
int main()
{
cout << "========================================================" << endl;
cout << "||****************************************************||" << endl;
cout << "||****************************************************||" << endl;
cout << "||*** 欢迎使用四则运算程序 ***||" << endl;
cout << "||*** 随机生成四则运算并计算出正确结果 ***||" << endl;
cout << "||*** 请根据提示输入您想生成的题目类型 ***||" << endl;
cout << "||****************************************************||" << endl;
cout << "||****************************************************||" << endl;
cout << "========================================================" << endl;
srand((unsigned)time(NULL));
int num, max = 0;
char op[20] = { '\0' };
bool cld1, cld2; // cld1为1 表示可能含有括号, 为0表示不含括号, cld2 为1表示含有小数为2表示不含有小数;
float resArray[100] = { 0 };
int respos = 0;
// 输入操作
cout<<"请输入生成题目数量:"<<endl;
while (true) {
cin >> num;
if (num > 0) break;
cout << "输入有误, 请重新输入题目数量:\n";
}
cout<<"========================================================" << endl;
cout<<"请选择运算符, 例如:加减乘除 + - * / :\n ";
cin >> op;
cout<<"========================================================" << endl;
cout<<"请输入数值的最大值 0 - x,(输入x必须为正数):\n";
while (true) {
cin >> max;
if (max > 0) break;
cout << "输入有误, 请重新输入最大值:\n";
}
cout<<"========================================================" << endl;
cout<<"请选择是否有括号 1/0:" << endl;
cin >> cld1;
cout<<"========================================================" << endl;
cout<<"请选择是否有小数 1/0:" << endl;
cin >> cld2;
// **********************************************--------***********//
//生成操作
int opnum = 0; //统计op 并处理
while (true) {
if (op[opnum] != '\0') {
opnum++;
}
else {
break;
}
} // 此时 opnum 记录着 op操作符的数量;
/*****************************************************************/
// 考虑到实际中不太会有 过于长的多项式, 这里 设置一个随机数把含有的符号数限制到7个以内;
// opmax 为 + - * / 的最大个数, 限制了多项式的长度;
int pos = 0;
int opmax = 0;
int kuohao = 0;
int order = 1; //题目序号
int flag = 0; // 排除一个操作数左右两边括号的情况: (a) + b
Solve s1; //创建计算器, 用于实时计算字符串的值;
while (num--) {
s1.isolve(); //清空计算器;
s1.getCh('#'); // 放入'#' 准备接受算式开始计算;
float factor = 0;
cout << order++ << ". ";
pos = 0;
opmax = rand() % 6 + 1;
kuohao = 0;
while (opmax--) { //开始生成多项式
char vv = '\0';
bool lf = false; // 用于表示此次是否生成了左括号
if (cld1 == 1 && rand() % 8 > 5) { // 1/8 的概率出现括号;
flag = 0;
cout << '(';
kuohao++;
lf = true;
}
if (lf) {
s1.getCh('(');
}
factor = rand() % (max - 1) + 1 + ((rand() % 100) * 1.0 / 100) * cld2;
cout << factor;
//生成操作数 factor;
s1.getNum(factor); //操作数放入计算器
bool rf = false; //用于表示是否生成了右括号;
if (cld1 == 1 && kuohao > 0 && flag != 0) {
if (rand() % 4 > 2) {
cout << ')';
kuohao--;
rf = true;
}
}
if (rf) {
s1.getCh(')');
}
//生成操作符
pos = rand() % opnum;
cout << op[pos];
//将操作符放入计算器;
s1.getCh(op[pos]);
flag++;
}
factor = rand() % (max - 1) + 1 + ((rand() % 100) * 1.0 / 100) * cld2;
cout << factor;
//将最后一个操作数放入计算器
s1.getNum(factor);
while (kuohao--) {
cout << ')';
s1.getCh(')');
}
//将结尾符号'#'放入计算器;
s1.getCh('#');
cout<<"=?"<<endl;
//将最终的结果放入结果数组
resArray[respos++] = s1.getRes();
}
cout<<"========================================================"<<endl;
cout<<"||****************************************************||"<<endl;
cout<<"计算结果如下:"<<endl;
system("pause");
// 输出答案 *************************************************//:
for (int i = 0; i < respos; i++) {
cout << i + 1 << ". " << resArray[i] << endl;
if (i + 1 % 10 == 0) {
cout << endl;
}
}
cout<<"||****************************************************||"<<endl;
cout<<"========================================================"<<endl;
//******************************************************//
return 0;
}
(3)运算结果生成代码:
int Solve::table[7][7] = {// +, -, *, /, (, ), #,
{ -1, -1, -1, -1, 1, 0, 1 },
{ -1, -1, -1, -1, 1, 0, 1 },
{ 1, 1, -1, -1, 1, 0, 1 },
{ 1, 1, -1, -1, 1, 0, 1 },
{ 1, 1, 1, 1, 1, 0, 1 },
{ -1, -1, -1, -1, 0, 0 ,0 },
{-1, -1, -1, -1, 0, 0, 0}
};
Solve::Solve() { // 完成初始化操作符操作数堆栈置0
cst = new char[30];
fst = new float[30];
}
Solve::~Solve() {}
void Solve::isolve() {
cp = 0;
fp = 0;
}
void Solve::getNum(float c) {
fst[fp++] = c;
}
float Solve::getRes() {
return fst[--fp];
}
void Solve::getCh(char c) { // c 为新得到的字符;
if (cp == 0 && c == '#') { //接受第一个字符 '#'
cst[cp++] = c;
}
else { //若输入的是加减乘除'#';
char u = cst[cp - 1]; // u 栈顶字符
if (compare(c, u) == 1) { //新输入的优先级大于栈顶
cst[cp++] = c;
}
else if (compare(c, u) == 0) { // 新输入优先级小于栈顶
if (u == '(' && c == ')' || u == '#' && c == '#') {
cp--; //将左括号移出去;
}
else {
cout << "priority 0 error" << endl;
}
}
else if (compare(c, u) == -1) { //新输入优先级等于小于栈顶
do {
cp--;
compute(u); //拿出栈顶符号去计算
u = cst[cp - 1]; //新的栈顶符号
} while (compare(c, u) == -1);
//直到栈顶符号优先级不高于 最新输入的操作符优先级,跳出循环
if (u == '(' && c == ')' || u == '#' && c == '#') {
//如果优先级相等,就拿出去;
cp--; //将左括号移出去;
}
else { //如果新输入操作符优先级高,则放入;
cst[cp++] = c;
}
}
else {
cout<<"error"<<endl;
}
}
}
int Solve::compare(char a, char b) {
return table[getOdr(a)][getOdr(b)];
}
void Solve::compute(char c) {
float a, b;
float res;
b = fst[--fp];
a = fst[--fp];
if (c == '*') {
res = a * b;
}
else if (c == '/') { //现实世界除数为0是不被允许的,这里当除数为
//时当1处理,防止程序崩溃;
if (b == 0) {
res = a;
}
else {
res = 1.0 * a / b;
}
}
else if (c == '+') {
res = a + b;
}
else if (c == '-') {
res = a - b;
}
else {
cout << "compute error having excepted opr" << endl;
}
fst[fp++] = res; //将计算成功的结果返回堆栈;
}
int Solve::getOdr(char c) {
if (c == '+') return 0;
if (c == '-') return 1;
if (c == '*') return 2;
if (c == '/') return 3;
if (c == '(') return 4;
if (c == ')') return 5;
if (c == '#') return 6;
}
4、程序模块实现:
一、客户要求输入模块
二、生成运算式模块
三、正确正确结果模块
5、总结
相比较与上次的结对编程作业,此次的作业难度加大了,我和我的小伙伴查阅资料、共同完成了此次作业。此次作业任务中,我的角色是驾驶员,虽然我的基础相对好的同学来说,略有不足,但是我很开心这次能够独立完成了所有的代码任务,唯一美中不足的是没有做出来界面。希望下一次的作业可以有更加大的改进。在共同完成此次作业作业中,我的搭档和我共同探讨算法,共同改进,一起学习,一起成长,有的时候我们的意见不同了也会有争吵,但是最后总可以找到一个共识点。一个人的力量是渺小的,团队的力量才是伟大的。代码测评和单元测试交给我的搭档啦~~~
6、代码地址:
https://git.dev.tencent.com/dtid_faca7022745baf1e/The_second_teamwork_file.git