小组成员
姓名 |
班级 |
学号 |
林劲辰 |
计科2班 |
3121004707 |
许庆阳 |
计科2班 |
3121004931 |
项目要求
1、实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)
2、程序应能支持一万道题目的生成。
3、使用 n 参数控制生成题目的个数,使用 r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
4、不能出现负数,假分数,每题运算符不能超过3个
5、生成的题目存入执行程序的当前目录下的Exercises.txt文件,在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
6、程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,统计结果输出到文件Grade.txt
1.PSP表格
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
20 |
30 |
Estimate |
估计这个任务需要多少时间 |
10 |
10 |
Development |
开发 |
200 |
250 |
Analysis |
需求分析 (包括学习新技术) |
80 |
80 |
Design Spec |
生成设计文档 |
40 |
50 |
Design Review |
设计复审 |
20 |
30 |
Coding Standard |
代码规范 (为目前的开发制定合适的规范) |
20 |
20 |
Design |
具体设计 |
60 |
60 |
Coding |
具体编码 |
150 |
180 |
Code Review |
代码复审 |
20 |
30 |
Test |
测试(自我测试,修改代码,提交修改) |
90 |
110 |
Reporting |
报告 |
80 |
50 |
Test Repor |
测试报告 |
20 |
40 |
Size Measurement |
计算工作量 |
20 |
20 |
Postmortem & Process Improvement Plan |
事后总结, 并提出过程改进计划 |
30 |
30 |
|
合计 |
900 |
1000 |
2.模块接口设计
2.1流程图
2.2框架
2.3类
类名 |
作用 |
main |
主函数 |
BuildFormula |
随机生成式子 |
checkAnswer |
对照答案 |
FileOperation |
文件相关 |
Fraction |
表示分数 |
GetResultFromArray |
转换分数 |
2.4函数
函数名 |
功能 |
归属的类 |
generate |
随机生成公式,如果有减法,则判定减数和被减数的大小,确保计算的子过程不出现负数 |
BuildFormula类 |
addBrackets |
符合条件的话随机生成括号 |
BuildFormula类 |
check |
讲用户输入的答案与正确答案比较,正确则在后面打勾,否则打叉 |
checkAnswer类 |
writeFormulaIntoTxt |
讲生成的公式写入文件 |
FileOperation类 |
writeAnswerIntoTxt |
讲每条公式对应的答案写入文件 |
FileOperation类 |
createFraction |
根据分子分母构建分数 |
Fraction类 |
add |
分数的加操作 |
Fraction类 |
sub |
分数的减操作 |
Fraction类 |
mul |
分数的乘操作 |
Fraction类 |
div |
分数的除法操作 |
Fraction类 |
toString |
分数转换为字符串 |
Fraction类 |
calculateStringArray |
根据字符串数组中的公式将其转换为分数并计算其结果 |
GetResultFromArray类 |
2.5关键代码以及注释
式子生成:
点击查看代码
public void generate(){//生成一条公式1 + 1 + 1
Random random=new Random();
StringBuilder sb=new StringBuilder();
Fraction result=null;
String[] formula=new String[count];
String[] answer=new String[count];
for(int j=0;j<count;j++){
int numOfFraction=random.nextInt(3)+2;
boolean bracketsGenerate=random.nextBoolean();//是否随机生成括号
sb.setLength(0);
result=null;
int tag=0;
int operator;
for(int i=1;i<=numOfFraction;i++){//根据分数的个数生成公式和符号
if(i!=numOfFraction){
int denominator=random.nextInt(10)+1;//分母
int numerator=random.nextInt(denominator*range)+1;//分子
Fraction f=new Fraction(numerator,denominator);
sb.append(f.toString()+" ");
if(tag==0){
operator=random.nextInt(4);
}else{
operator=random.nextInt(2)+2;
}
if(operator==0||operator==1){
tag=1;
}
switch (operator) {
case 0:
sb.append("÷ ");
break;
case 1:
sb.append("- ");
break;
case 2:
sb.append("* ");
break;
case 3:
sb.append("+ ");
break;
}
}else{
int denominator=random.nextInt(10)+1;//分母
int numerator=random.nextInt(denominator*range)+1;//分子
Fraction f=new Fraction(numerator,denominator);
sb.append(f.toString());
}
}
String[] s=sb.toString().split(" ");
s=swapOrder(s);
if(numOfFraction!=2&&bracketsGenerate){//符合生成括号的条件
//String[] s=sb.toString().split(" ");
int leftindex=2*(random.nextInt(numOfFraction-1));//4个操作时 0 1 2
int rightindex=0;
if(numOfFraction==3){
switch (leftindex){
case 0:
rightindex=2;
break;
case 2:
rightindex=4;
break;
}
}else if(numOfFraction==4){
switch(leftindex){
case 0:
rightindex=2*(random.nextInt(2)+1);
break;
case 2:
rightindex=2*(random.nextInt(2)+2);
break;
case 4:
rightindex=6;
break;
}
}
GetResultFromArray g=new GetResultFromArray();
String[] news=null;
news=addBrackets(s,leftindex,rightindex);
result=g.calculateStringArray(news);
sb.setLength(0);
for (String str : news) {
sb.append(str+" ");
}
}else{
GetResultFromArray g=new GetResultFromArray();
//s=sb.toString().split(" ");
result=g.calculateStringArray(s);
}
sb.append("= ");
formula[j]=sb.toString();
if(result==null){
answer[j]="不可计算";
}else{
answer[j]=result.toString();
}
}
FileOperation fo=new FileOperation();
fo.writeFormulaIntoTxt(formula);
fo.writeAnswerIntoTxt(answer);
}
计算答案:
点击查看代码
public static Fraction calculateStringArray(String[] inputArray) {
if (inputArray == null || inputArray.length == 0) {
return new Fraction(0, 1); // 返回默认分数 0/1
}
Stack<Fraction> numStack = new Stack<>();
Stack<Character> operatorStack = new Stack<>();
for (String token : inputArray) {
if (isFraction(token)) {
numStack.push(new Fraction(token));
} else if (token.equals("(")) {
operatorStack.push('(');
} else if (token.equals(")")) {
while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
if (performOperation(numStack, operatorStack)) {
return null;
}
}
operatorStack.pop(); // Pop the opening parenthesis
} else if (isOperator(token)) {
while (!operatorStack.isEmpty() && hasPrecedence(token.charAt(0), operatorStack.peek())) {
if (performOperation(numStack, operatorStack)) {
return null;
}
}
operatorStack.push(token.charAt(0));
}
}
while (!operatorStack.isEmpty()) {
if (performOperation(numStack, operatorStack)) {
return null;
}
}
return numStack.pop();
}
答案对照:
点击查看代码
public void check() throws IOException {
String filePath="D:\\IdeaProjects\\PeerWork\\src\\main\\resources\\Exercises.txt";
String filePath1="D:\\IdeaProjects\\PeerWork\\src\\main\\resources\\Answer.txt";
String[] useranswer=readLinesToArray(filePath);
String[] realanswer=readLinesToArray(filePath1);
String[] result=new String[useranswer.length];
int i=0;
for(String line:useranswer){
String[] ss=line.split(" ");
String answer=ss[ss.length-1];//用户写的
int index=realanswer[i].indexOf("、");
String realAnswer=realanswer[i].substring(index+1);
if(realAnswer.equals(answer)){
result[i]="✓";
}else{
result[i]="×";
}
i++;
}
List<String> lines = new ArrayList<>();
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line;
i=0;
while ((line = reader.readLine()) != null) {
lines.add(line + result[i]);
i++;
}
reader.close();
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
for (String updatedLine : lines) {
writer.write(updatedLine);
writer.newLine();
}
writer.close();
}
3代码性能分析
4单元测试展示
4.1测试代码
生成测试
点击查看代码
public class TestMain {
public static void main(String[] args) {//测试生成公式和答案
//-n 10 -r 10
int range=10;
int count=10;
BuildFormula bf=new BuildFormula(range,count);
bf.generate();
}
}
答案测试
点击查看代码
public class TestCheckAnswer {//测试校对答案
public static void main(String[] args) {
checkAnswer ca=new checkAnswer();
try {
ca.check();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.2测试结果
式子生成:
答案生成:
命令行测试
测试结果:成功生成式子,并且结果正确,没有出现问题。
4.3测试覆盖率
5.作业总结
团结协作是一切事业成功的基础,个人和集体只有依靠团结的力量才能把人人的愿望和团队的目标结合起来,超越人体的局限,发挥集体的协作作用,产生1+1>2的效果,在合作中,我们对出现的问题进行统一讨论,有时候我没能解决的问题,对方能解决。我们彼此都能想到对方想不到的点,这样互相完善,比起一个人来说,效率大大提升了。在这次代码中遇到最大的问题就是公式生成不合理的问题,因为之前没有学习过相关方面的问题,经过这次作业,也让我们学到了新的东西,取得了一定的进步。对于以后的结对编程,我们的建议是可以先了解彼此的长处,合理分配任务,是项目完成更加高效。