作业概述
这个作业属于哪个课程 | 软件工程 |
---|---|
这个作业要求在哪里 | 结对项目 |
这个作业的目标 | 和同伴共同合作完成项目 |
成员
- 曹富城 学号:3121005076
- 何继安 学号:3121005087
一、github链接
https://github.com/flash2-man/calculator
https://github.com/muxingtong/MyCalculator
二、PSP表
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 20 | 20 |
Development | 开发 | 330 | 380 |
· Analysis | · 需求分析 (包括学习新技术) | 40 | 50 |
· Design Spec | · 生成设计文档 | 40 | 50 |
· Design Review | · 设计复审 (和同事审核设计文档) | 20 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
· Design | · 具体设计 | 40 | 30 |
· Coding | · 具体编码 | 120 | 80 |
· Code Review | · 代码复审 | 20 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 90 |
Reporting | 报告 | 60 | 80 |
· Test Report | · 测试报告 | 20 | 30 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 30 |
合计 | 410 | 480 |
三、分析
- 题目:实现一个自动生成小学四则运算题目的命令行程序
需求
- 通过命令行参数控制程序功能
- 生成不重复的题目
- 计算题目答案
- 批改,对比正确答案
- 文件输入输出
初步模块设计图
最终采取的算法有所不同
思路
读取参数->调用对应模块
1、生成模块->检测模块->生成->写入模块
2、读取模块->计算模块->批改模块->写入模块
3、报错
四、实现
- 文件读写模块:包括读取文件和写入文件的函数,用于读取题目和答案文件,并将批改结果写入文件。
- 命令行参数解析模块:使用argparse库解析命令行参数,根据参数的不同执行不同的功能。
- 题目生成模块:根据指定的题目数量和运算数的最大值,生成指定数量的四则运算题目,并将题目和答案分别写入文件。
- 题目批改模块:读取题目和答案文件,逐行比较题目和答案,判断答案是否正确,并统计正确和错误的题目数量,最后将批改结果写入文件。
核心代码:
产生运算式子函数:
去重方法:使用集合expressions来保存已经生成的题目的逆波兰表达式。在生成每个题目之前,会将当前题目的逆波兰表达式与集合中的表达式进行比较,如果存在相同的逆波兰表达式或者结果小于0,则重新生成下一个题目。只有当题目的逆波兰表达式不重复且结果大于等于0时,才会将题目添加到集合中,并继续生成下一个题目。
def generate_expression(num_operators, scope):
if num_operators == 0:
num = random.randint(1, scope - 1)
return str(num)
else:
operator = random.choice(symbol)
num1 = generate_expression(num_operators - 1, scope)
num2 = generate_expression(num_operators - 1, scope)
expression = f"{num1} {operator} {num2}"
if random.choice([True, False]):
expression = f"({expression})"
return expression
去重函数:
def is_duplicate(expression):
rpn_expression = convert_to_rpn(expression)
return rpn_expression in expressions
# 将中缀表达式转换为逆波兰表达式
def convert_to_rpn(expression):
stack = []
rpn = []
for token in expression:
if token in symbol:
while stack and stack[-1] in symbol and symbol.index(stack[-1]) >= symbol.index(token):
rpn.append(stack.pop())
stack.append(token)
else:
rpn.append(token)
while stack:
rpn.append(stack.pop())
return tuple(rpn) # 返回元组以便比较
批改代码部分:
使用正则表达式识别题目
incorrect_questions = []
correct_questions = []
for i, (line1, line2) in enumerate(zip(exercises, answers), 1):
# 正则表达式!!!!!!!
expression_match = re.match(r'四则运算题目.\d+\t(.*?)=', line1)
result_match = re.search(r'\t(.*)$', line2)
if expression_match and result_match:
expression = expression_match.group(1).strip()
result = result_match.group(1).strip()
res = Fraction(eval(expression)).limit_denominator()
result_end = f"{res.numerator // res.denominator}'{res.numerator % res.denominator}/{res.denominator}" \
if res.numerator > res.denominator != 1 else str(res)
if result_end == str(result):
correct_count += 1
correct_questions.append(str(i))
else:
wrong_count += 1
incorrect_questions.append(str(i))
# 清空文件
open('Grade.txt', 'w').close()
writefile('Grade.txt', f"Correct: {correct_count} ({', '.join(correct_questions)})\n")
writefile('Grade.txt', f"Wrong: {wrong_count} ({', '.join(incorrect_questions)})\n")
print(f"Correct answers: {correct_count},({', '.join(correct_questions)})\n")
print(f"Wrong answers: {wrong_count},({', '.join(incorrect_questions)})\n")
五、性能测试
生成题目时
批改题目时
python main.py
python main.py -n 10
python main.py -n 10000
python main.py -r 10
python main.py -n 10 -r 10
python main.py -n 10000 -r 1000
python main.py -n -r #报错
python main.py -e path1 -a path2
python main.py -e -a #报错
运行结果
六、结对感受
- 曹富城同学:
这个项目总体上还是有难度的,之前想用别的语言写,但是实现难度有点大,后面就改用python了,总体来说这个项目做的还是挺可以的,满足了相关要求,在实践中也产生了很多很有价值的灵感,最终在不断实践纠错中提高自己,不过不足的地方在没有实现可视化界面的实现。结对编程让我对一个产品的开发有了更深的认识,可以看到一些之前没出现过的错误,两者相辅相成,将原本的版本修改的更符合用户体验了,同时也更明白了模块化的便捷性和合理性,更有助于开发项目。
- 何继安同学:
标签:结对,20,项目,python,res,模块,题目,expression From: https://www.cnblogs.com/moyuchenhui/p/17732902.html这是我第一次和同伴合作完成项目,总体来说我对这次项目完成感觉还可以,在这个项目里,我认识到了一个程序模块化的重要性,用户体验感的必要性,在优化的过程中,我更深刻地体会到这个程序的运行过程。在实现过程中,我负责代码最终测试和优化,以我的角度去复审同伴的代码,找出其中不足,这让我有不一样的体会,对结对编程和软件工程有了更深刻的认识,让我开始期待团队项目的开始。对于同伴的建议:希望同伴能重视程序的模块化和用户的体验感。