第三次作业
软件工程第三次作业
1.成员与代码
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | *计划 | 60 | 60 |
Estimate | ·估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | 1500 | 1400 |
Analysis | 需求分析 (包括学习新技术) | 120 | 120 |
Design Spec | 生成设计文档 | 60 | 60 |
Design Review | 设计复审 | 20 | 20 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 1300 | 1500 |
Code Review | 代码复审 | 100 | 100 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 120 |
Reporting | 报告 | 30 | 30 |
Test Repor | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 5 | 5 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 1880 | 1980 |
3.需求分析
实现一个自动生成小学四则运算题目的命令行程序
题目分析
-
使用参数控制生成题目个数和数值范围
-
作业要求生成四则运算式,运算符最多三个,不能出现负数,分数必须是真分数,题目不能重复
-
将生成的算式,答案,判题结果都存储到文件中,支持一万道题目生成
-
涉及到程序参数获取,随机数生成,字符串拼接,数值校验,文件I/O流操作等,本次作业采用python完成,使用到argparse参数解析,re正则匹配,random随机数生成,Fraction分数计算
4.设计过程
Util类(主要的工具类)实现分数题目的形成,整数题目的形成,分数类题目的运算操作,将题目插入文本文件,以及答案的检查。
util类主要分成了AnswerCheckUtil(答案的检查,正确与错误),ExerciseFractionUtil(生成分数题目),ExerciseIntegerUtil(生成整数题目),ExerciseInsertUtil(将题目与答案输出,写入文本文件),FractionOperationUtil(分数的操作),其中
-
ExerciseFractionUtil中通过设置随机符号与随机符号数,分类实现,又Math.random函数实现随机,由用户输入题目个数以及题目中数值范围实现对随机题目的控制,当输入进后,由代码实现随机生成。
-
ExerciseIntegerUtil同分数类的情况
-
FractionOperationUtil中有方法simplifiedFraction,changeToProperFraction,simplified。simplified递归实现求最大公约数,simplifiedFraction对simplified的调用,实现对分数的化简,而changeToProperFraction则是将假分数变成真分数,化成x'x/x的形式
-
ExerciseInsertUtil则是对生成的题目与答案输入到文本文件中
-
AnswerCheckUtil则是将用户输入的答案与标准答案进行对比,批改,若正确则记录,错误也记录,最终输入正确与错误的题号。
5.测试运行
6.效能分析
7.关键代码展示
ExerciseIntegerUtil全部为整数的题目
package utils;
/**
* 全部为整数的题目
*/
public class ExerciseIntegerUtil {
/*
* 未处理除法的情况下变为分数
* 仅仅是变成了两位小数输出
*/
//n为传入的题目数量,x为传入的数值范围
public static void getExerise(int n,int x) {
//结果
double sum=0;
//题目数量
int count=0;
double[] results=new double[n+1];
String[] exercise=new String[n+1];
while(count!=n) {
//四个数据a,b,c,d
double a=(int) (Math.random()*x)+1;
double b=(int) (Math.random()*x)+1;
double c=(int) (Math.random()*x)+1;
double d=(int) (Math.random()*x)+1;
//随机运算符+-*/,0表示+,1表示-,2表示*,3表示/
int operator1=(int) (Math.random()*4);
int operator2=(int) (Math.random()*4);
int operator3=(int) (Math.random()*4);
//控制题目的项数,0表示2两项,1表示3项,2表示4项
int nterms=(int) (Math.random()*3);
//运算符为1个的情况下
if(operator1==0&&nterms==0) {
sum=a+b;
exercise[++count]=a+"+"+b+"=";
}
//运算符为2个的情况下
else if(operator1==0&&operator2==0&&nterms==1) {
sum=a+b+c;
exercise[++count]=a+"+"+b+"+"+c+"=";
}
else if(operator1==0&&operator2==2&&nterms==1) {
sum=a+b*c;
exercise[++count]=a+"+"+b+"×"+c+"=";
}
else if(operator1==0&&operator2==1&&nterms==1) {
if(a+b<c) {
sum=a+c-b;
exercise[++count]=a+"+"+c+"-"+b+"=";
}
else {
sum=a+b-c;
exercise[++count]=a+"+"+b+"-"+c+"=";
}
}
else if(operator1==0&&operator2==3&&nterms==1) {
if(c==0&&b!=0) {
sum=a+c/b;
exercise[++count]=a+"+"+c+"÷"+b+"=";
}
else if(c!=0){
sum=a+b/c;
exercise[++count]=a+"+"+b+"÷"+c+"=";
}
}
else if(operator1==1&&nterms==0) {
if(a<b) {
sum=b-a;
exercise[++count]=b+"-"+a+"=";
}
else {
sum=a-b;
exercise[++count]=a+"-"+b+"=";
}
}
else if(operator1==1&&operator2==0&&nterms==1) {
if(a-b+c<0) {
sum=b-a+c;
exercise[++count]=b+"-"+a+"+"+c+"=";
}
else {
sum=a-b+c;
exercise[++count]=a+"-"+b+"+"+c+"=";
}
}
else if(operator1==1&&operator2==1&&nterms==1) {
if(a-b-c<0) {
continue;
}
else {
sum=a-b-c;
exercise[++count]=a+"-"+b+"-"+c+"=";
}
}
else if(operator1==1&&operator2==2&&nterms==1) {
if(a<b) {
sum=(b-a)*c;
exercise[++count]="("+b+"-"+a+")"+"×"+c+"=";
}
else {
sum=(a-b)*c;
exercise[++count]="("+a+"-"+b+")"+"×"+c+"=";
}
}
else if(operator1==1&&operator2==3&&nterms==1) {
if(a-b<0) {
if(c==0) {
continue;
}
else {
sum=(b-a)/c;
exercise[++count]="("+b+"-"+a+")"+"÷"+c+"=";
}
}
else if(c!=0){
sum=(a-b)/c;
exercise[++count]="("+a+"-"+b+")"+"÷"+c+"=";
}
}
else if(operator1==2&&nterms==0) {
sum=a*b;
exercise[++count]=a+"×"+b+"=";
}
else if(operator1==2&&operator2==0&&nterms==1) {
sum=a*b+c;
exercise[++count]=a+"×"+b+"+"+c+"=";
}
else if(operator1==2&&operator2==1&&nterms==1) {
if(a*b<c) {
sum=a*c-b;
exercise[++count]=a+"×"+c+"+"+b+"=";
}
else {
sum=a*b-c;
exercise[++count]=a+"×"+b+"+"+c+"=";
}
}
else if(operator1==2&&operator2==2&&nterms==1) {
sum=a*b*c;
exercise[++count]=a+"×"+b+"×"+c+"=";
}
else if(operator1==2&&operator2==3&&nterms==1) {
if(c==0&&b!=0) {
sum=a*c/b;
exercise[++count]=a+"×"+c+"÷"+b+"=";
}
else if(c!=0){
sum=a*b/c;
exercise[++count]=a+"×"+b+"÷"+c+"=";
}
}
else if(operator1==3&&nterms==0) {
if(b==0&&a!=0) {
sum=b/a;
exercise[++count]=b+"÷"+a+"=";
}
else if(b!=0){
sum=a/b;
exercise[++count]=a+"÷"+b+"=";
}
}
else if(operator1==3&&operator2==0&&nterms==1) {
if(b==0&&c!=0) {
sum=a/c+b;
exercise[++count]=a+"÷"+c+"+"+b+"=";
}
else if(b!=0) {
sum=a/b+c;
exercise[++count]=a+"÷"+b+"+"+c+"=";
}
}
else if(operator1==3&&operator2==2&&nterms==1) {
if(b==0&&c!=0) {
sum=a/c*b;
exercise[++count]=a+"÷"+c+"×"+b+"=";
}
else if(b!=0) {
sum=a/b*c;
exercise[++count]=a+"÷"+b+"×"+c+"=";
}
}
else if(operator1==3&&operator2==1&&nterms==1) {
if(b==0&&c!=0&&a/c>b) {
sum=a/c-b;
exercise[++count]=a+"÷"+c+"×"+b+"=";
}
else if(b!=0&&a/b>c) {
sum=a/b-c;
exercise[++count]=a+"÷"+b+"×"+c+"=";
}
}
else if(operator1==3&&operator2==3&&nterms==1) {
if(a!=0&&b!=0&&c!=0) {
sum=a/b/c;
exercise[++count]=a+"÷"+b+"÷"+c+"=";
}
}
//运算符为3个的情况下
else if(operator1==0&&operator2==0&&operator3==0&&nterms==2) {
sum=a+b+c+d;
exercise[++count]=a+"+"+b+"+"+c+"+"+d+"=";
}
else if(operator1==0&&operator2==2&&operator3==0&&nterms==2) {
sum=a+b*c+d;
exercise[++count]=a+"+"+b+"×"+c+"+"+d+"=";
}
else if(operator1==0&&operator2==1&&operator3==0&&nterms==2) {
if(a+b-c+d<0) {
continue;
}
else {
sum=a+b-c+d;
exercise[++count]=a+"+"+b+"-"+c+"+"+d+"=";
}
}
else if(operator1==0&&operator2==3&&operator3==0&&nterms==2) {
if(c==0) {
continue;
}
else {
sum=a+b/c+d;
exercise[++count]=a+"+"+b+"÷"+c+"+"+d+"=";
}
}
else if(operator1==0&&operator2==3&&operator3==1&&nterms==2) {
if(c==0||a+b/c-d<0) {
continue;
}
else {
sum=a+b/c-d;
exercise[++count]=a+"+"+b+"÷"+c+"-"+d+"=";
}
}
else if(operator1==0&&operator2==3&&operator3==2&&nterms==2) {
if(c==0) {
continue;
}
else {
sum=a+b/c*d;
exercise[++count]=a+"+"+b+"÷"+c+"×"+d+"=";
}
}
else {
continue;
}
//存储结果
results[count]=sum;
}
//此处为实现将答案存入文本文件
ExerciseInsertUtil.insertExercise(exercise);
ExerciseInsertUtil.insertAnswer(results);
//将答案存起来
AnswerCheckUtil.setResults(results);
}
}
ExerciseFractionUtil全部为分数的题目
package utils;
/**
* 全部为分数的题目
*/
public class ExerciseFractionUtil {
// n为传入的题目数量,x为传入的数值范围
public static void getExercise(int n, int x) {
// 结果
int sum = 0;
// 题目数量
int count = 0;
// 数值,运算符,运算符个数
int a, b, c, d, e, f, g, h, operator1, operator2, operator3, nterms;
// 储存题目以及答案
String[] results = new String[n + 1];
String[] exercise = new String[n + 1];
// 随机运算符+-*/,0表示+,1表示-,2表示*,3表示/
while (n != count) {
operator1 = (int) (Math.random() * 4);
operator2 = (int) (Math.random() * 4);
operator3 = (int) (Math.random() * 4);
a = (int) (Math.random() * x);
b = (int) (Math.random() * x);
c = (int) (Math.random() * x);
d = (int) (Math.random() * x);
e = (int) (Math.random() * x);
f = (int) (Math.random() * x);
g = (int) (Math.random() * x);
h = (int) (Math.random() * x);
nterms = (int) (Math.random() * 3);
//一个运算符的情况下
if (b != 0 && d != 0 && nterms == 0) {
if (operator1 == 0) {
exercise[++count] = a + "/" + b + "+" + c + "/" + d + "=";
// 储存临时值,方便化简
sum = a * d + b * c;
b = b * d;
//判断是否为假分数,下同
if (sum > b)
//将其转换成带分数,下同
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
//将分数化简,下同
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator1 == 1) {
if ((a / b) > (c / d)) {
exercise[++count] = a + "/" + b + "-" + c + "/" + d + "=";
// 储存临时值,方便化简
sum = a * d - b * c;
b = b * d;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
} else if (operator1 == 2) {
exercise[++count] = a + "/" + b + "×" + c + "/" + d + "=";
// 储存临时值,方便化简
sum = a * c;
b = b * d;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator1 == 3) {
// 防止C为0出错
if (c == 0)
continue;
exercise[++count] = a + "/" + b + "÷" + c + "/" + d + "=";
// 储存临时值,方便化简
sum = a * d;
b = b * c;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
//两个运算符的情况下
} else if (b != 0 && d != 0 && f != 0 && nterms == 1) {
if (operator1 == 0) {
if (operator2 == 0) {
exercise[++count] = a + "/" + b + "+" + c + "/" + d + "+" + e + "/" + f + "=";
b = b * d * f;
sum = a * d * f + c * b * f + e * b * d;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
} else if (operator2 == 1) {
if ((a / b + c / d - e / f) > 0) {
exercise[++count] = a + "/" + b + "+" + c + "/" + d + "-" + e + "/" + f + "=";
b = b * d * f;
sum = a * d * f + c * b * f - e * b * d;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
} else if (operator2 == 2) {
exercise[++count] = a + "/" + b + "+" + c + "/" + d + "×" + e + "/" + f + "=";
sum = a * d * f + c * e * b;
b = b * d * f;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator2 == 3 && e != 0) {
exercise[++count] = a + "/" + b + "+" + c + "/" + d + "÷" + e + "/" + f + "=";
sum = a * d * e + c * f * b;
b = b * d * e;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator1 == 1) {
if (operator2 == 0)
if ((a / b - c / d + e / f) > 0) {
exercise[++count] = a + "/" + b + "-" + c + "/" + d + "+" + e + "/" + f + "=";
sum = a * d * f - c * b * f + e * b * d;
b = b * d * f;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator2 == 1)
if ((a / b - c / d - e / f) > 0) {
exercise[++count] = a + "/" + b + "-" + c + "/" + d + "-" + e + "/" + f + "=";
sum = a * d * f - c * b * f - e * b * d;
b = b * d * f;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator2 == 2) {
if ((a / b - (c / d) * (e / f)) > 0) {
exercise[++count] = a + "/" + b + "-" + c + "/" + d + "×" + e + "/" + f + "=";
sum = a * d * f - b * c * e;
b = b * d * f;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
} else if (operator2 == 3) {
if ((a / b - (c / d) / (e / f)) > 0) {
exercise[++count] = a + "/" + b + "-" + c + "/" + d + "÷" + e + "/" + f + "=";
sum = a * d * e - b * c * f;
b = b * d * e;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
} else if (operator1 == 2) {
exercise[++count] = a + "/" + b + "×" + c + "/" + d + "×" + e + "/" + f + "=";
sum = a * c * e;
b = b * d * f;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
} else if (operator1 == 3) {
if (a / b * c / d * e / f >= 0) {
exercise[++count] = a + "/" + b + "÷" + c + "/" + d + "÷" + e + "/" + f + "=";
sum = a * d * f;
b = b * c * e;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
}
//3个运算符的情况下,仅仅举出了较为简单的运算+法
} else if (b != 0 && d != 0 && f != 0 && h != 0 && nterms == 2) {
if (operator1 == 0 && operator2 == 0 && operator3 == 0) {
exercise[++count] = a + "/" + b + "+" + c + "/" + d + "+" + e + "/" + f + "+" + g + "/" + h
+ "=";
sum = a * d * f * h + c * b * f * h + e * b * d * h + g * b * d * f;
b = b * d * f * h;
if (sum > b)
results[count] = FractionOperationUtil.changeToProperFraction(sum, b);
else
results[count] = FractionOperationUtil.simplifiedFraction(sum, b);
}
}
}
}
// 此处为实现将答案存入文本文件
ExerciseInsertUtil.insertExercise(exercise);
ExerciseInsertUtil.insertAnswer(results);
// 将答案存起来
AnswerCheckUtil.setResults(results);
}
}
ExerciseInsertUtil将题目以及答案存储进文本文件中
package utils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
/**
* 将题目以及答案存储进文本文件中
*/
public class ExerciseInsertUtil {
private static String filename1="Exercise.txt";
private static String filename2="Answer.txt";
public static void insertAnswer(String[] answer) {
File file=new File(filename2);
FileOutputStream fos=null;
OutputStreamWriter osw=null;
BufferedWriter bw=null;
try {
if(!file.exists())
file.createNewFile();
fos=new FileOutputStream(file);
osw=new OutputStreamWriter(fos);
bw=new BufferedWriter(osw);
for(int i=1;i<=answer.length-1;i++) {
bw.write("答案"+i+":"+" "+answer[i]+"\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(bw!=null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(osw!=null)
try {
osw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(fos!=null)
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void insertAnswer(double[] answer) {
File file=new File(filename2);
FileOutputStream fos=null;
OutputStreamWriter osw=null;
BufferedWriter bw=null;
BigDecimal fomat=null;
double result=0;
try {
if(!file.exists())
file.createNewFile();
fos=new FileOutputStream(file);
osw=new OutputStreamWriter(fos);
bw=new BufferedWriter(osw);
for(int i=1;i<=answer.length-1;i++) {
//转化为两位小数
fomat=new BigDecimal(answer[i]);
result=fomat.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
bw.write("答案"+i+":"+" "+result+"\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(bw!=null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(osw!=null)
try {
osw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(fos!=null)
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void insertExercise(String[] exercise) {
File file=new File(filename1);
FileOutputStream fos=null;
OutputStreamWriter osw=null;
BufferedWriter bw=null;
try {
if(!file.exists())
file.createNewFile();
fos=new FileOutputStream(file);
osw=new OutputStreamWriter(fos);
bw=new BufferedWriter(osw);
for(int i=1;i<=exercise.length-1;i++) {
bw.write("题目"+i+":"+" "+exercise[i]+"\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(bw!=null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(osw!=null)
try {
osw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(fos!=null)
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
8.项目小结
张镇柯:
-
结对编程体现了沟通交流,思想灵感碰撞的魅力与无限创新可能,在项目中互相讨论,提出自己的思路见解,不断完善设计规划,锻炼了沟通的能力,体现了协作交流的重要性
-
第一次尝试结对合作,收获还是很多的,这次结对项目我们首先进行了开会讨论,研究项目的细节与大致的框架,确定方向,认真研究分析了需求,开会讨论了很多的方案,收获颇多。
-
在开发的过程中,我们积极交流,将遇到的问题与困难及时向对方反馈,认真聆听对方的意见,将我们各自的进度在做项目的时候总结汇报。让我体会到了团队的力量,以前在一个人开发时候总会遇到各种问题
-
李在代码实现方面更具天赋,在开发代码过程中帮了大忙,大大缩短了代码书写时间
李建森:
-
在结对项目中我们更有互相的支持与鼓励,有问题一起分担,一起解决,形成了一个极度良好的团队氛围。
-
在此次项目中也遇到一些困难,比如假分数换成真分数呀,如何实现随机运算,怎样把题目生成,最后不得已用了最笨的办法,穷举,虽然还是少考虑了一些情况,以后会更加优化我们的算法,不断提升自我。
-
结对编程体现了合作的关键性,在项目经过需求分析和详细设计后,要进入真正实现的过程,对于程序的推进,需要明确各自的目标,尽可能达到最优的实现方案,完成负责的模块,提高开发效率
-
张在代码计划与布局方面更胜一筹,在安排计划与整体布局上的贡献都来自于他,没有他的布局,我开发代码的舒适度也将大大降低。