github地址
这个作业属于哪个课程 | 计科22级12班 |
---|---|
这个作业要求在哪里 | 作业要求链接 |
这个作业的目标 | 结对实现一个自动生成小学四则运算题目的命令行程序 |
姓名 | 任务 |
---|---|
郑铠洋 | 程序实现 |
彭培炎 | 测试 |
一、PSP表格
阶段 | 描述 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 5 | 5 |
· Estimate | · 估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | 160 | 180 |
· Analysis | · 需求分析 (包括学习新技术) | 10 | 10 |
· Design Spec | · 生成设计文档 | 10 | 10 |
· Design Review | · 设计复审 | 10 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 10 | 10 |
· Coding | · 具体编码 | 60 | 90 |
· Code Review | · 代码复审 | 10 | 10 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 60 | 60 |
· Test Report | · 测试报告 | 40 | 40 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 225 | 245 |
二、效能分析
覆盖率:
大约85%
时间:
150ms左右可生成一次
空间:
因为要存储之前的题目以判断题目的唯一性,所以这里空间开的比较多
三、设计思路
文件结构:
程序流程:
实现逻辑:
- 写一个Fraction类将数字转为分数结构,分母为1时为整数
- 在createQuestion类随机分子分母,符号,并且根据符号随即添加括号
- answerChecker用于比对答案
四、代码说明
主要的create函数
用random()随机生成
ppublic static void create(int number, int range, List<String> exercises, List<String> answers) {
Random rand = new Random();
while (exercises.size() < number) {
try{
// 生成分子和分母,控制整数和分数的出现概率
int[] fraction1 = generateNumberOrFraction(rand, range);
int[] fraction2 = generateNumberOrFraction(rand, range);
int[] fraction3 = generateNumberOrFraction(rand, range);
// 获取分数或整数
Fraction num1=new Fraction (fraction1[0],fraction1[1]);
Fraction num2=new Fraction (fraction2[0],fraction2[1]);
Fraction num3=new Fraction (fraction3[0],fraction3[1]);
// 生成两个运算符
char operator1 = createOperator();
char operator2 = createOperator();
// 随机决定是否添加括号
boolean addBracket = rand.nextBoolean();
boolean[] bracket1Ref = {false};
boolean[] bracket2Ref = {false};
// 生成题目
String question = createBracket(addBracket, fraction1, fraction2, fraction3, operator1, operator2, bracket1Ref, bracket2Ref);
if (!generatedQuestions.contains(question)) {
boolean bracket1 = bracket1Ref[0];
boolean bracket2 = bracket2Ref[0];
String answer = calculateAnswer(num1, num2, num3, operator1, operator2,bracket1, bracket2);
exercises.add(question);
answers.add(answer);
generatedQuestions.add(question);// 记录生成的题目
}
}catch (ArithmeticException e) {
continue;
}
}
}
/*
* 生成整数或分数,根据随机数控制出现概率
*/
private static int[] generateNumberOrFraction(Random rand, int range) {
// 50% 概率生成整数,50% 概率生成分数
if (rand.nextBoolean()) {
int numerator = rand.nextInt(range); // 生成整数
return new int[]{numerator, 1}; // 分母为1,表示整数
} else {
int numerator = rand.nextInt(range);
int denominator = rand.nextInt(range - 1) + 1; // 确保分母不为0
return new int[]{numerator, denominator};
}
}
添加括号
将加入括号的频率设置成50%,对每个符号都有几率添加括号
private static String createBracket(boolean addParentheses, int[] fraction1, int[] fraction2,
int[] fraction3, char operator1, char operator2, boolean[] bracket1, boolean[] bracket2) {
String question;
// 获取分数或整数
double num1 = (double) fraction1[0] / fraction1[1];
double num2 = (double) fraction2[0] / fraction2[1];
double num3 = (double) fraction3[0] / fraction3[1];
// 随机添加括号
if (addParentheses && ((operator1 == '+' || operator1 == '-') && (operator2 == '*' || operator2 == '/'))
|| ((operator2 == '+' || operator2 == '-') && (operator1 == '*' || operator1 == '/')))
{
if(operator1 == '+' || operator1 == '-')
{
bracket1[0]=true;
if(operator1 == '-' && num1<num2)swap(fraction1,fraction2);
question = "(" + formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " " +
formatFraction(fraction2[0], fraction2[1]) + ") " + operator2 + " " +
formatFraction(fraction3[0], fraction3[1]) + " = ";
}
else
{
bracket2[0]=true;
if(operator2 == '-' && num2<num3)swap(fraction2,fraction3);
question = formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " (" +
formatFraction(fraction2[0], fraction2[1]) + " " + operator2 + " " +
formatFraction(fraction3[0], fraction3[1]) + " )= ";
}
} else if (addParentheses) {
bracket2[0]=true;
if(operator2 == '-' && num2<num3)swap(fraction2,fraction3);
question = formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " (" +
formatFraction(fraction2[0], fraction2[1]) + " " + operator2 + " " +
formatFraction(fraction3[0], fraction3[1]) + " )= ";
} else {
question = formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " " +
formatFraction(fraction2[0], fraction2[1]) + " " + operator2 + " " +
formatFraction(fraction3[0], fraction3[1]) + " = ";
}
return question;
}
计算答案
对加入括号的优先计算,再计算剩下的
public static String calculateAnswer(Fraction num1, Fraction num2, Fraction num3,
char operator1, char operator2, boolean bracket1, boolean bracket2) {
Fraction finalResult = new Fraction(1,1);
if (bracket1) {
// 先计算括号内的操作
Fraction middleResult = applyOperator(num1, num2, operator1);
finalResult = applyOperator(middleResult, num3, operator2);
} else if (bracket2) {
Fraction middleResult = applyOperator(num2, num3, operator2);
finalResult = applyOperator(num1, middleResult, operator1);
} else {
// 正常顺序运算
if((operator1 == '+' || operator1 == '-') && (operator2 == '*' || operator2 == '/')) {
Fraction middleResult = applyOperator(num2, num3, operator2);
finalResult = applyOperator(num1, middleResult, operator1);
}
else
{
Fraction middleResult = applyOperator(num1, num2, operator1);
finalResult = applyOperator(middleResult, num3, operator2);
}
}
return finalResult.toString();
}
五、测试运行
题目
答案
其余测试用例
针对各个函数正确和错误以及空的测试
六、记录小结
我们第一次尝试结对任务,认为结对任务可以有效节省时间,减少差错,且对项目拥有更清楚的思路和理解。但是,在工作效率上仍有欠缺,主要涉及沟通交流