这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230 |
这个作业的目标 | 1. 加深对项目开发流程的理解 2. 学会在团队中沟通与合作 3. 进一步提升编码能力 |
姓名 | 学号 | Github地址 |
---|---|---|
李超 | 3122004484 | https://github.com/LiChao258932589/LiChao258932589/tree/main/3122004484/结对项目 |
陈卓嘉 | 3122004473 | https://github.com/czoj/czoj.git |
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 50 |
· Estimate | · 估计这个任务需要多少时间 | 60 | 50 |
Development | 开发 | 635 | 665 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 50 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 | 25 | 35 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
· Design | · 具体设计 | 60 | 50 |
· Coding | · 具体编码 | 300 | 300 |
· Code Review | · 代码复审 | 20 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 150 |
Reporting | 报告 | 90 | 90 |
· Test Repor | · 测试报告 | 40 | 50 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 20 |
· 合计 | 785 | 805 |
二、效能分析
从上图中可以看出,消耗最大的函数是main()函数
三、设计实现过程
代码以模块化设计,共有以下几个关键模块:
- 解析命令行参数模块,负责解析命令行参数供程序使用
- 生成数字模块,负责生成随机的整数和真分数
- 生成四则表达式模块,负责随机生成四则运算表达式
- 生成文件模块,负责生成题目文件和答案文件
- 判卷功能模块,负责根据用户提供的题目文件和答案文件,进行判卷
函数调用图:
三、代码说明
1. parse_args()函数
def parse_args():
parser = argparse.ArgumentParser(description="自动生成小学四则运算题目的命令行程序") # 为程序生成的帮助信息添加描述
parser.add_argument("-n", type=int, help="生成题目的数量") # 添加参数 -n,指定生成题目的数量
parser.add_argument("-r", type=int, help="数值范围(自然数、真分数和真分数分母的范围)") # 添加参数 -r,指定数值范围
parser.add_argument("-e", type=str, help="题目文件路径") # 添加参数 -e,指定题目文件路径
parser.add_argument("-a", type=str, help="答案文件路径") # 添加参数 -a,指定答案文件路径
args = parser.parse_args()
# 判断是否输入参数 -r
if args.n and not args.r:
print("请输入数值范围!")
exit(1)
# 验证参数合理性
if args.n and args.n < 0:
print("题目数量必须为正数!")
exit(1)
if args.r and args.r < 0:
print("数值范围必须为正数!")
exit(1)
return args
- 思路:
- 使用
argparse
模块添加四个参数:-n
、-r
、-e
、-a
。 - 检查参数的合理性,如果缺少必要参数或参数值不合法,给出提示并退出程序。
- 使用
2. generate_number()函数
def generate_expression(max_range):
operators = ['+', '-', '*', '/'] # 定义可选的运算符
# 定义标志用于判断括号的生成
left_flag = False
right_flag = False
expression = str(generate_number(max_range)) # 随机生成第一个数
# 随机决定是否在表达式开头添加左括号
if random.choice([True, False]):
expression = "(" + expression
left_flag = True
# 随机循环1到3次,生成剩余的运算符和数字
for _ in range(random.randint(1, 3)):
op = random.choice(operators)
num = generate_number(max_range)
# 决定括号的位置
if not left_flag and random.choice([True, False]):
expression += f" {op} ({num}"
left_flag = True
elif left_flag and not right_flag:
expression += f" {op} {num})"
right_flag = True
left_flag = False
else:
expression += f" {op} {num}"
# 如果左括号未闭合,添加右括号
if left_flag and not right_flag:
expression += ")"
# 去除无意义的括号
if expression[0] == '(' and expression[-1] == ')':
expression = expression[1:-1] # 去除首尾的括号
expression = re.sub(r'\((\d+|\d+/\d+)\)', r'\1', expression) # 去除单个数字的括号
return expression
- 思路:
- 随机选择运算符和操作数,构建表达式字符串。
- 随机决定是否在某些位置添加括号,增加表达式的复杂度。
- 使用正则表达式去除无意义的括号,确保表达式的合法性。
3. grade_exercises()函数
def grade_exercises(exercise_file, answer_file):
with open(exercise_file, "r") as f_ex, open(answer_file, "r") as f_ans:
exercises = f_ex.readlines()
answers = f_ans.readlines()
correct = []
wrong = []
for idx, (ex, ans) in enumerate(zip(exercises, answers), 1):
# 提取用户答案和正确答案
ex_ans = re.search(r'=(.*)', ex).group(1).strip() # 用户答案
ans_ans = re.search(r'\d+\.(.*)', ans).group(1).strip() # 正确答案
if ex_ans == ans_ans:
correct.append(idx)
else:
wrong.append(idx)
# 输出成绩到文件
with open("Grade.txt", "w") as f_grade:
f_grade.write(f"Correct: {len(correct)} ({', '.join(map(str, correct))})\n")
f_grade.write(f"Wrong: {len(wrong)} ({', '.join(map(str, wrong))})\n")
- 思路:
- 读取题目文件和答案文件,逐行对比答案。
- 使用正则表达式提取用户的答案和正确答案。
- 记录正确和错误的题目编号。
- 将结果写入
Grade.txt
文件,包含正确和错误题目的数量和编号。
四、测试运行
测试用例 1: 基本生成测试
命令:
python main.py -n 5 -r 10
预期结果:
- 程序生成5道四则运算题目,数字范围在1到10之间,可能包含自然数和真分数。
- 生成的
Exercises.txt
中题目格式正确,Answers.txt
中答案符合预期。
验证:手动检查生成的题目格式是否正确,计算器核对答案。
测试用例 2: 单分数测试
命令:
python main.py -n 3 -r 3
预期结果:
- 程序生成3道题,范围为1-3,这很有可能生成真分数。
- 检查生成的题目是否包含分数,并且答案的分数形式是否正确。
验证:题目中应有分数,并且分数答案符合 a/b
格式或带分数形式。
测试用例 3: 大范围测试
命令:
python main.py -n 10 -r 100
预期结果:
- 程序生成10道题,数字范围为1-100,可能包含分数和自然数。
- 检查是否有大数运算,计算器核对答案。
验证:通过计算器验证答案的正确性。
测试用例 4: 零除异常处理测试
命令:
python main.py -n 5 -r 5
预期结果:
- 由于可能会产生除以0的情况,程序应跳过无效的表达式并生成有效的题目。
验证:检查生成的题目,确保没有零除异常(如 / 0
)。
测试用例 5: 重复题目处理
命令:
python main.py -n 10 -r 5
预期结果:
- 程序应生成10道不重复的题目,即使在小范围内重复生成同样答案的题目,程序也应跳过并生成新的题目。
验证:检查 Exercises.txt
和 Answers.txt
,确认没有重复题目或答案。
测试用例 6: 答案文件路径错误
命令:
python main.py -e Exercises.txt -a WrongPath.txt
预期结果:
- 程序无法找到
WrongPath.txt
文件并抛出错误。
验证:检查程序是否正确处理文件不存在的错误情况,并输出合理的提示信息。
测试用例 7: 正确答案判断测试
命令:
python main.py -e Exercises.txt -a Answers.txt
预期结果:
- 程序根据
Exercises.txt
和Answers.txt
对照判断正确与否,并生成Grade.txt
,包括正确和错误的题目编号。
验证:手动比较 Exercises.txt
中的表达式和 Answers.txt
中的答案,检查 Grade.txt
是否正确反映结果。
测试用例 8: 运算符优先级与括号处理
命令:
python main.py -n 5 -r 10
预期结果:
- 检查生成的表达式中是否正确处理了运算符优先级和括号使用,确保括号的生成与移除符合预期。
验证:手动查看 Exercises.txt
,确保没有多余括号且符合运算优先级。
测试用例 9: 带整数部分的分数测试
命令:
python main.py -n 5 -r 7
预期结果:
- 如果生成带整数部分的分数(即假分数),程序应正确将其格式化为
整数'分子/分母
形式。
验证:检查生成的答案中是否有带整数部分的真分数。
测试用例 10: 随机题目数值测试
命令:
python main.py -n 1 -r 2
预期结果:
- 题目只能生成很小的数值(1或2),答案应为简单的运算结果。
验证:通过手动计算确认生成的题目和答案是否正确。
确认程序正确性的依据
- 边界值分析:通过不同的范围和题目数量,确保程序能够在边界条件下正确生成题目。
- 零除处理:程序能够跳过非法的除以零操作,生成有效的题目。
- 分数与自然数混合:生成的题目中既有自然数也有真分数,并且分数的格式化符合预期。
- 去除无意义括号:程序去除无意义的括号,确保生成的表达式合理简洁。
- 正确性验证:通过手动和计算器核对生成的答案是否正确。
- 防止重复题目:程序通过检查,确保不会生成相同的题目和答案组合。
- 答案格式化:程序能够正确将分数答案转换为合适的格式(整数或带分数形式),确保题目和答案对应。
五、项目小结
1. 成功之处
-
需求理解清晰:项目的需求明确,生成四则运算题目并评估结果,是一个相对明确且清晰的目标。在初期需求讨论中,我们很快就确定了各自的任务和模块的划分,确保项目推进的节奏一致。
-
代码设计合理:我们将功能模块化,划分为输入解析、题目生成、答案计算、文件读写、答案验证等模块。这样不仅提高了代码的可读性,也方便了后续的维护和扩展。
-
异常处理完善:在生成题目时,我们考虑到了零除、负数答案以及重复题目的问题,通过异常处理和逻辑判断保证了生成题目的有效性。比如避免零除异常、重复题目过滤等细节。
-
团队合作顺利:在项目过程中,我们保持了良好的沟通,确保了代码风格一致、功能实现紧密衔接。结对合作中,我们在每个环节的讨论与反馈都帮助我们优化了方案,并迅速解决了代码中的问题。
-
测试覆盖全面:通过设计多样化的测试用例,从边界条件、特殊情况(如分数运算、括号处理)、异常情况(如零除)等多方面验证了程序的正确性。程序通过了多个场景的验证,功能稳定。
2. 项目中的挑战与不足
-
复杂运算逻辑的处理:在生成四则运算题目时,如何合理地处理括号以及运算符优先级的问题是一个挑战。尽管最终解决了这些问题,但过程中也反复调试并调整了括号生成和表达式的简化逻辑。
-
重复生成题目问题:在题目数量较多或数值范围较小时,程序有时会生成相同的题目。虽然我们通过答案去重机制解决了这一问题,但这一点让我们意识到随机性处理在类似项目中需要更复杂的算法设计。
-
错误处理逻辑改进:我们初期的错误处理设计较为简单,在某些情况下并没有及时给出用户反馈。后续我们加强了对文件路径错误、参数缺失等情况的提示,使程序更加健壮和用户友好。
-
协作工具的选择与使用:尽管我们在合作中利用了版本控制系统来同步代码,但在早期没有很好地使用分支功能,导致了一些代码的冲突问题。这个教训让我们更加重视使用版本控制系统的分支管理来避免不必要的冲突。
3. 结对感受与反思
结对编程带来的最大收获是实时反馈与共同进步。在项目的每个阶段,我们都进行了密切的沟通,通过对彼此代码的审视和建议,项目得以顺利推进,同时也提高了彼此的编程技巧。我们意识到结对合作不仅仅是分工合作,而是通过交流与反馈,及时发现并解决问题,使项目质量不断提高。
4. 对彼此的闪光点与建议
-
队友的闪光点:
- 严谨的代码风格:队友在编码过程中表现出极强的严谨性和逻辑性,每一处细节都考虑周全,尤其是在处理运算符优先级、括号逻辑等复杂环节时,展现了出色的编程能力和耐心。
- 迅速的调试能力:在项目中遇到问题时,队友总是能够迅速定位问题,并通过调试和反复测试快速找到解决方案,这大大提升了开发效率。
-
对队友的建议:
- 更早的结构设计:虽然项目完成得很顺利,但在初期的结构设计上我们可以更加系统化一些,提前设计好完整的模块结构会避免一些后续代码重构的工作。
- 多样化的测试:我们在测试阶段非常注重手动测试,但如果能引入自动化测试工具,可能会节省不少时间,特别是在确保代码的稳定性和一致性方面,自动化测试能带来更多帮助。
5. 总结与经验教训
通过这次结对项目,我们不仅在技术层面上提升了对Python和项目开发流程的理解,还学到了如何有效地在团队中沟通与合作。结对编程的实践证明,良好的沟通与反馈机制可以让我们发现自己单独编程时可能忽略的问题。在未来的项目中,我们会更注重早期设计规划和测试工具的引入,以提高开发效率与项目质量。
结对编程是一次宝贵的经历,不仅提升了项目质量,还让我们加深了对团队合作的理解和信任。
标签:结对,题目,项目,生成,括号,答案,txt,expression From: https://www.cnblogs.com/LiChao258932589/p/18431255