软件工程 | 网工1934班级链接 |
---|---|
作业要求 | 作业要求链接 |
作业目标 | 体验结对编程 |
欧柱轩 3119005391
黄俊鸿 3119005373
项目 GitHub 链接
一、PSP 表格
PSP 2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 60 | 85 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 240 | 320 |
· Design Spec | · 生成设计文档 | 30 | 25 |
· Design Review | · 设计复审 | 10 | 3 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 15 |
· Design | · 具体设计 | 120 | 200 |
· Coding | · 具体编码 | 150 | 285 |
· Code Review | · 代码复审 | 60 | 80 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 95 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 15 | 25 |
· Size Measurement | · 计算工作量 | 5 | 15 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 12 |
· 合计 | 750 | 1160 |
二、设计实现过程
模块设计
- Expression 类:使用二叉树封装表达式的类,包含了一个生成表达式二叉树的方法。
- Ran 类:包括随机生成运算符、整数、分数和子节点位置的方法。
- TreeNode 类:getResult(),获取每个结点的运算结果并检验是否出现负数、除数为0的情况;toString(),按照优先级添加及去除括号,形成表达式串。
- Generator 类:generate(),根据要求数量及最大值生成题目和答案并写入 txt 文件。
- Calculator 类:实现真分数的加减乘除运算。
- Check 类:实现对练习答案中对错的判定及数量统计。
- FileUtil 类:txt 写入工具类。
- CommandResolver 类:解析命令参数,包括 -n、-r、-e、-a。
项目结构
## 关键函数 getResult():三、代码说明
生成二叉树
public void createBTree(){
TreeNode lchild, rchild, lnode, rnode;
if(num == 1){ //一个运算符的情况
lchild = new TreeNode(String.valueOf(Ran.getNumber(max)), null, null); //生成随机数并赋值给叶节点
rchild = new TreeNode(String.valueOf(Ran.getNumber(max)), null, null);
root = new TreeNode(String.valueOf(Ran.getOperator()), lchild, rchild); //随机运算符根节点
}
else{
int num1 = 0;
boolean[] place = Ran.getChildPlace(num);
root = new TreeNode(String.valueOf(Ran.getOperator()), null, null);
opeList.add(root);
for(int i = 0; i < place.length; i++){
if(place[i]){ //生成一个运算符节点
lnode = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
rnode = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
if(i%2 == 0){
lchild = new TreeNode(String.valueOf(Ran.getOperator()), lnode, rnode);
opeList.add(lchild);
opeList.get(num1).setLchild(lchild);
}
else{
rchild = new TreeNode(String.valueOf(Ran.getOperator()), lnode, rnode);
opeList.add(rchild);
opeList.get(num1).setRchild(rchild);
}
}
else{ //生成一个左/右孩子
if(i%2 == 0){
lchild = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
opeList.get(num1).setLchild(lchild);
}
else{
rchild = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
opeList.get(num1).setRchild(rchild);
}
}
num1 = num1 + i%2; //num1为偶说明孩子未生成
}
}
}
校验统计练习答案对错
public void grade(String Exercisefile,String AnswerFile) throws IOException {
file1 = Exercisefile;
file2 = AnswerFile;
try {
br1 = new BufferedReader(new FileReader(file1));
br2 = new BufferedReader(new FileReader(file2));
bw = new BufferedWriter(new FileWriter(file3));
} catch (IOException e) {
e.printStackTrace();
}
result1 = "correct:";
result2 = "wrong:";
sb1.append("(");
sb2.append("(");
String str = null, str1 = null;
String[] strings = null, strings1 = null;
while ((str = br1.readLine()) != null && (str1 = br2.readLine()) != null) {
strings = str.split("="); //分割练习字符串,=后为答案
strings1 = str1.split("\\."); //分割答案字符串,.后为答案
if (strings[1].equals(strings1[1])) {
rightCount++;
sb1.append(strings1[0] + ",");
}else {
wrongCount++;
sb2.append(strings1[0] + ",");
}
}
//去掉尾部多余的,
if(rightCount != 0)
sb1.deleteCharAt(sb1.length() - 1);
if(wrongCount != 0)
sb2.deleteCharAt(sb2.length() - 1);
sb1.append(")");
sb2.append(")");
result1 += rightCount + sb1.toString();
result2 += wrongCount + sb2.toString();
bw.write(result1);
bw.newLine();
bw.write(result2);
br1.close();
br2.close();
bw.close();
}
四、性能分析
五、测试分析
public class TestGenerator {
/**
* 测试无 -r 参数情况
*/
@Test
public void testCommandNotParamR() throws IOException {
Main.main(new String[]{"-n", "5"});
}
/**
* 测试 -r 参数后无输入整数情况
*/
@Test
public void testCommandFormatError() throws IOException {
Main.main(new String[]{"-r", "五"});
}
/**
* 测试无 -n 参数情况(默认为5,即生成5道题)
*/
@Test
public void testCommandNotParamN() throws IOException {
//无指定-n时默认为5
Main.main(new String[]{"-r", "10"});
}
/**
* 测试参数输入错误情况
*/
@Test
public void testCommandParamError() throws IOException {
Main.main(new String[]{"-nsfd", "5", "-r", "6"});
}
/**
* 测试参数个数错误的情况(非2非4)
*/
@Test
public void testCommandParamNumError() throws IOException {
Main.main(new String[]{"-r", "5", "-n"});
}
/**
* 生成6道题,最大值为10的情况(-n参数在前)
*/
@Test
public void testCommandFirstNThenR() throws IOException {
Main.main(new String[]{"-n", "6", "-r", "10"});
}
/**
* 生成10道题,最大值为10的情况(-n参数在后)
*/
@Test
public void testCommandFirstRThenN() throws IOException {
Main.main(new String[]{"-r", "10", "-n", "20"});
}
/**
* 生成10000道题,最大值为10的情况
*/
@Test
public void testCommandNice2() throws IOException {
Main.main(new String[]{"-n", "1000", "-r", "10"});
}
/**
* 测试判断答案对错并统计
*/
@Test
public void testGrade() throws IOException {
Main.main(new String[]{"-e", "F:\\Unicourses\\SE\\arithmetic-generator\\Exercise.txt", "-a", "F:\\Unicourses\\SE\\arithmetic-generator\\Answers.txt"});
}
}
测试截图:
六、项目小结
欧柱轩:
刚看到题目时以为比较简单,但到了真正动手做的时候,发现要考虑的事情还挺多。在和俊鸿互相探讨交流的过程里,逐渐明确了目标以及分工,最后终于是完成了课题。这是我第一次与他人合作完成任务,让我深刻意识到交流是多么的重要。俊鸿对代码的严谨和一丝不苟十分值得我学习。
黄俊鸿:
两个人的思想碰撞是一件很有趣的事儿,虽然可能没有完全按照结对编程的分工流程,但还是挺享受其中的过程的。柱轩对项目全局的把控很到位,十分值得我学习。