结对项目
项目 | 内容 |
---|---|
这个作业属于哪个课程 | (信息安全1812)的链接 |
这个作业要求在哪里 | (结对项目)作业要求的链接 |
这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序,熟悉结对开发项目的流程。 |
1、前言
github地址:
https://github.com/J0knK3ats/3118005384/tree/master/结对作业
合作“对友”:
姓名 | 学号 |
---|---|
吴旻哲 | 3118005384 |
朱亮 | 3118005393 |
2、PSP 表格
*PSP2.1* | *Personal Software Process Stages* | *预估耗时(分钟)* | *实际耗时(分钟)* |
---|---|---|---|
Planning | 计划 | 20 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 20 | 30 |
Development | 开发 | 400 | 550 |
· Analysis | · 需求分析 (包括学习新技术) | 30 | 60 |
· Design Spec | · 生成设计文档 | 30 | 10 |
· Design Review | · 设计复审 (和同事审核设计文档) | 20 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 20 |
· Design | · 具体设计 | 30 | 60 |
· Coding | · 具体编码 | 200 | 300 |
· Code Review | · 代码复审 | 20 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 30 |
Reporting | 报告 | 80 | 110 |
· Test Report | · 测试报告 | 60 | 90 |
· Size Measurement | · 计算工作量 | 10 | 5 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 15 |
合计 | 600 | 690 |
3、设计实现过程
各个模块的类、方法如下:
3.1、check.py(查重模块)
- def get_num_op(formula):
- def check(formula, form):
3.2、cal.py(计算模块)
- def trsan_standard(formula):
- class Cal:
- def formula(op, left, right):
- def get_answer(self):
- def grad(u_ans, lists):
- def trsan_ans(answer):
- class Node:
- def _init _(self):
- def get_answer(self):
- def get_formula(self):
- class tree:
- def _init _(self):
- def gen_formula(self, num_range, number):
3.3、main.py(主模块)
- def write_file(expr_set, ans_set, exp_file, ans_file):
- if _ name _ == '_ main _':
4、代码说明
4.1、四则运算式子生成
- 这里使用了二叉树的方法生成随机式子,因为可以方便生成之后输出标准式子,
- 通过中序遍历读取树、通过节点符号的优先级添加括号生成式子
1、二叉树生成
while i < number:
node_list = [self.root] # 每次生成一个树
for _ in range(degree):
node = random.choice(node_list)
node_list.remove(node)
node.op = random.choice(self.op_list)[0] # 确定操作符
node.type = 2 # 修改type
node.left = Node()
node_list.append(node.left)
node.right = Node()
node_list.append(node.right)
2、节点随机数生成
try:
for node in node_list: # 节点生成随机数
node.type = 1
num_type = random.choices(self.type_list)[0]
if num_type == 1:
node.number = random.randint(1, num_range)
else:
node.number = Fraction(random.randint(1, num_range), random.randint(1, num_range))
4.2、查重设计
- 本来想着用二叉树直接进行对比,但是二叉树左右旋又变相增加难度,
- 所以就直接通过判断答案是否一致然后如果式子中存在 + 或者 x 的运算符号再所用数字是否一致来进行一个对比
# 查重
num = 0
self.root.get_answer()
for num in range(0, i):
if Cal.trsan_ans(self.root.number) == self.ans_list[num]:
if check.check(trsan_standard(self.root.get_formula()), self.form_list[num]): #存在返回T
num = -1
break
def check(formula, form):
f_nlist, f_olist = get_num_op(formula)
if ' + ' in f_olist or ' × ' in f_olist:
n_list, o_list = get_num_op(form)
if f_nlist.sort() == n_list.sort():
return True
else:
return False
5、效能分析
- 基于 -n 10000 -r 10
- 消耗最大的函数在 trans_ans(将分数转换成真分数格式)
def trsan_ans(self):
if (self > 1 or self < -1) and self.denominator != 1:
a_numerator = self.numerator % self.denominator
a_denominator = self.denominator
a_right = Fraction(a_numerator, a_denominator)
a_left = self.numerator // self.denominator
result = str(a_left) + '\'' + str(a_right)
else:
result = str(self)
return result
- 因为随机出来的节点形式(数字类型)大多数为分数形式,所有每次生成四则运算式子时会多次调用分数转化真分数形式,同时当出现除0的分数是又会产生异常处理重新生成四则运算式子,所有耗时会比较久
6、测试运行
测试的代码覆盖率:
测试结果:
7、项目小结
个人总结如下:
吴旻哲:
这次编程作业有很多不足的地方:生成式子时会产生很多分数所以耗时会久,可以进一步优化为纯分数或者纯数字的式子 或者通过设置权重的方式在随机生成数字时减少分数出现的可能,同时可以通过生成多个临时列表用刚生成的式子作为查重列表、分数先不化为真分数、在生成新的式子时查重就不用先转换为标准式子再去和标准输出列表式子进行对比,减少函数调用。结对编程可以通过交流更快的确定需求以及具体构思,可以大量节省时间。
朱亮:
通过这次的结对编程,我有了不少的收获。我认为,对于结对开发,需要和小伙伴要保持充分的沟通和交流,要互相了解到对方需求和进度,互相配合,互相解决困难,因为这样才可以最大程度地进行快速的结对开发。也正是因为我们一直遵循这样的准则,我们才能完好地互相配合完成开发。最后,我觉得“对友”吴旻哲是个非常不错的伙伴:打码能力强、做事效率高。本程序的大部分代码均由吴旻哲同学完成。代码习惯良好,可读性强。有自己独特的想法。