结对作业
结对项目
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/InformationSecurity1912-Softwareengineering |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/InformationSecurity1912-Softwareengineering/homework/12147 |
这个作业的目标 | 尝试与同伴一起合作完成项目,学习了解团队合作的方式 |
一.小组成员信息
姓名 | 邓盛永 | 王嘉杰 |
---|---|---|
学号 | 3119005456 | 3119005474 |
Github项目地址 | https://github.com/Dengsy0516/fourRule.git | https://github.com/Jaywilde/3119005474/tree/main/ArithmeticOperations |
仓库截图
邓盛永
王嘉杰
二.PSP表格
PSP是卡耐基梅隆大学(CMU)的专家们针对软件工程师所提出的一套模型:Personal Software Process (PSP, 个人开发流程,或称个体软件过程)。
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 90 |
Estimate | 估计这个任务需要多少时间 | 20 | 25 |
Development | 开发 | 600 | 800 |
Analysis | 需求分析(包括学习新技术) | 80 | 100 |
Design Spec | 生成设计文档 | 40 | 45 |
Design Review | 设计复审 | 30 | 35 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 15 | 13 |
Design | 具体设计 | 90 | 75 |
Coding | 具体代码 | 800 | 850 |
Code Review | 代码复审 | 50 | 65 |
Test | 测试(自我测试,修改代码,提交修改) | 20 | 20 |
Reporting | 报告 | 120 | 140 |
Test Repor | 测试报告 | 30 | 50 |
Size Measurement | 计算工作量 | 20 | 20 |
Postmortem & Process Improvement Plan | 事后总结,并提出过程改进计划 | 60 | 45 |
合计 | 2035 | 2373 |
三.效能分析
四.设计实现过程
1.需求分析
(1)使用 -n 参数控制生成题目的个数
(2)使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
(3)生成的题目中计算过程不能产生负数
(4)生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数
(5)每道题目中出现的运算符个数不超过3个
(6)程序一次运行生成的题目不能重复
(7)生成的题目存入执行程序的当前目录下的Exercises.txt文件
(8)在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
(9)程序应能支持一万道题目的生成
2.类说明
(1)AirthmeticMain
主方法,用于调用Utils包内的各种类
(2)CalculateRule
定义四则运算的规则
(3)CalculationsChangeUtils
用于将中缀表达式转换成后缀表达式
(4)ExpressionIOUtils
用于文件的读取和写入
(5)Fraction
用于定义分数类型的数值
(6)OperationValue
用于定义四则运算符的优先级
(7)RandomUtils
用于生成符合要求的随机数
(8)RepealtCheck
用于检测是否生成相同的四则运算式
3.类关系
五.代码说明
1.随机数生成
在随机数类中,我们设置了多个随机数,分别包含有不同功能,例如在此处,我们通过为四则运算符加权,通过产生的随机数来决定下一个位置应该放置哪一个运算符。但是在加权的时候,原本我们打算通过生成装有对应ASCII码的集合中的数值来生成相应的运算符,结果发现÷找不到对应的ASCII码,如果使用\的话也会和分数混淆,最终我们并未采用这种生成方式,转而直接加权1-4。
public static String OpChooseRandom(){
int choose_ran = (int)(Math.random()*(4-1+1)+1);
String operate;
if (choose_ran == 1){operate = "+";}
else if(choose_ran == 2){operate = "-";}
else if(choose_ran == 3){operate = "×";}
else {operate = "÷";}
return operate;
}
2.算式生成
我们采用了三个if的方式,通过判断随机数OperateNumber(生成运算符个数)来决定每次生成的是几元运算式。比如:OperateNumber=2的时候,我们生成的是三元一次计算式。然后再通过字符串的拼接生成表达式并输出。
我们通过mark标记该类计算式生成的个数,mark经过计算转化最终可以作为查重数组的下标使用。
if (OperateNumber == 2) {
Fraction Value1 = RandomUtils.FractionRandom(ValueRange);
String OpChoose1 = RandomUtils.OpChooseRandom();
Fraction Value2 = RandomUtils.FractionRandom(ValueRange);
String OpChoose2 = RandomUtils.OpChooseRandom();
Fraction Value3 = RandomUtils.FractionRandom(ValueRange);
mark2 = mark2 + 1;
String Expression2 = Value1 + OpChoose1 + Value2 + OpChoose2 + Value3;
System.out.println(Expression2 + "=");
String PolishExpression2 = CalculationsChangeUtils.ExpressionChange(Expression2, stack);
RepeatCheck.Check(QuestionNumber, mark2, PolishExpressionSave2, QuestionSave2, PolishExpression2, Expression2);
PolishExpression2 = PolishExpression2.replace("[", "");
PolishExpression2 = PolishExpression2.replace(" ", "");
PolishExpression2 = PolishExpression2.replace("]", "");
List<String> list = Arrays.asList(PolishExpression2.split(","));
for (int k = 0; k < list.size(); k++) {
get[k] = list.get(k);
stack.push(get[k]);
}
String result = CalculationsChangeUtils.doCalculation(stack);
KeySave2[mark2] = result;
System.out.println(KeySave2[mark2]);
}
在编写本段代码的时候我们踩了一个大坑,原本我们用List来储存字符串,但通过遍历字符串运算题目答案的时候总是有误。
debug我们会发现无法识别+-×÷符号,并且输出格式不规范。比如说中缀表达式:1\2÷5+2,当转换为后缀表达式的时候应该为1/2,5,÷,2,+;但实际上输出的是[1/2, 5, ÷, 2, +]。
经过多处资料查证,最后发现当直接使用print语句打印List的时候,逆波兰式会被[]括起来,并且在每一个逗号后都会添加一个空白字符。这对于我们后续遍历逆波兰式进行运算时造成了极大的困扰。
PolishExpression2 = PolishExpression2.replace("[", "");
PolishExpression2 = PolishExpression2.replace(" ", "");
PolishExpression2 = PolishExpression2.replace("]", "");
通过以上语句,我们最终将不想要的字符转换为NULL,实现了删除的功能。
3.算式查重
此处我们通过数组存入已经生成并经过重复检验的逆波兰式,然后在每一个新逆波兰式生成时,再次与数组内部的式子进行循环检验,最终我们可以获得不重复的四则运算式。
public static void Check(int QuestionNumber, int mark, String[] PolishExpressionSave, String[] QuestionSave, String PolishExpression,String Expression){
for(int k=0;k<QuestionNumber;k++){
if(PolishExpressionSave[k] == null){
QuestionSave[mark] = Expression;
PolishExpressionSave[mark] = PolishExpression;
} else if(PolishExpressionSave[k].equals(PolishExpression)){
mark=mark-1;
}else{
QuestionSave[mark] = Expression;
PolishExpressionSave[mark] = PolishExpression;
}
}
}
六.测试运行
七.项目小结
1.结对感受
邓盛永:在本次项目中,我领悟到了团队合作的优势,也学会了如何利用合作来加快我们完成项目的进度,于此同时,在本次项目中也发现了自己在代码能力上的不足,有思路但无法通过代码实现,只是我往后需要努力的方向
王嘉杰:在本次结对项目中,我体会到了结对合作的好处:思维的碰撞能够给予彼此非常多的灵感,并且在交流的过程中也能够锻炼自己的逻辑能力和表达能力。除去团队合作,我也有发现了自己在代码能力上有非常多的不足之处,Java有很多函数我都不了解,甚至说根本没见过;在完成项目的过程中会犯拖延症,总是无法保证每天都能够完成预期中的量。
2.闪光点或建议分享
邓盛永:本次项目是双人完成,按理来讲应该是会比一个人更容易完成,事实上也确实会更轻松,两个人有更多的想法,有更广的思路,解决同一个问题的方法也更多,但在拥有这些便利的同时,沟通至关重要,如果没有良好的沟通,两个人无法达成一致,将会导致进度的卡壳,幸运的事我与嘉杰组队,在有分歧的时候我们都能耐心地与对方分享,所以我们的进度顺利且迅速。
王嘉杰:在一起思考代码逻辑的时候,盛永给我了非常多的灵感,并且在我逻辑出现问题的时候,能够非常快速且清晰地向我指出我的不足之处。搭档拥有比我更加灵活的思维方式,并且在代码写作上具有极佳的大局观,非常值得我好好学习。希望的日后的学习打码生涯中能够多多交流,互相学习,共同进步。