结对项目
温吞:
结对项目
这个作业属于哪个课程 | 软件工程4班 |
---|---|
这个给作业要求在哪里 | 结对项目 |
这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序 |
合作人员
学号 | 姓名 |
---|---|
3122004557 | 蔡昱鹏 |
3122004567 | 韩逸朗 |
Github链接
PSS表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 15 |
Estimate | 估计这个任务要多少时间 | 5 | 5 |
Development | 开发 | 200 | 300 |
Analysis | 需求分析(包括学习新技术) | 200 | 200 |
Design Spec | 生成设计文档 | 10 | 20 |
Design Review | 设计复审 | 10 | 20 |
Coding Standard | 代码规范 | 20 | 20 |
Design | 具体设计 | 30 | 30 |
Coding | 具体编码 | 300 | 350 |
Code Review | 代码复审 | 30 | 30 |
Test | 测试 | 50 | 50 |
Reporting | 报告 | 60 | 60 |
Test Repor | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后总结 改进计划 | 30 | 30 |
All | 总计 | 1025 | 1200 |
效能分析
设计实现过程
一、函数部分
generate_expression(r)生成表达式
generate_exercises(exercises, answers, n, r)生成表达式以及答案列表
save_exercises_and_answers(exercises, answers, script_dir)保存表达式以及答案到文件中
is_valid(expression)表达式的合法性判断
grade_answers(exercise_file, answer_file)比对答案正确性
save_grade(correct_answers, wrong_answers, script_dir)保存得分文件
二、命令行参数解析
使用 argparse 解析命令行参数,包括生成题目数量 -n、数值范围 -r、题目文件路径 -e 和答案文件路径 -a。
三、主程序逻辑:
根据命令行参数判断是否提供了题目文件和答案文件,若提供了则执行评分逻辑,否则执行生成题目和答案的逻辑。
四、文件操作:
使用文件读写操作来保存题目、答案和评分结果。
五、异常处理:
在生成题目时进行合法性检查,避免出现负数或除零错误。
注:本次没有使用类,而是采用了函数式编程的方式来组织逻辑。不同函数之间通过参数传递数据,实现了不同功能的模块化。
代码说明
生成题目
def generate_expression(r):
# 由于运算符数量不定,需要特殊处理
num_operators = random.randint(1, 3)
num_operand = num_operators + 1
operators = ['+', '-', '*', '/']
operands = [random.randint(0, r) for _ in range(num_operand)]
select_operator = random.sample(operators, num_operators)
expression = "" # 初始化一个空表达式
expression += str(operands[0]) + " "
for i in range(num_operators):
expression += str(select_operator[i]) + " " + str(operands[i + 1]) + " "
return expression
生成题目以及答案列表
def generate_exercises(exercises, answers, n, r):
while len(exercises) < n:
expression = generate_expression(r)
if is_valid(expression):
exercises.append(expression)
answer = eval(expression)
fraction = Fraction(answer).limit_denominator() # 将答案转换为真分数
whole_part = fraction.numerator // fraction.denominator # 获取整数部分
numerator = abs(fraction.numerator) % fraction.denominator # 获取真分数的分子(取绝对值)
denominator = fraction.denominator # 获取真分数的分母
if numerator == 0: # 如果分子为0
if whole_part == 0: # 如果整数部分也为0
answers.append("0") # 答案为0
else: # 如果整数部分不为0
answers.append(f"{whole_part}") # 只输出整数部分
else: # 如果分子不为0
if whole_part == 0: # 如果整数部分为0
answers.append(f"{numerator}/{denominator}") # 答案直接为真分数
else: # 如果整数部分不为0
answers.append(f"{whole_part}'{numerator}/{denominator}")
保存题目和答案到文件中
def save_exercises_and_answers(exercises, answers, script_dir):
exercise_file = os.path.join(script_dir, "exercises.txt")
answer_file = os.path.join(script_dir, "answers.txt")
with open(exercise_file, "w") as exercises_file:
for i, exercise in enumerate(exercises, start=1):
exercises_file.write(f"{i}. {exercise}\n")
with open(answer_file, "w") as answers_file:
for i, answer in enumerate(answers, start=1):
answers_file.write(f"{i}. {answer}\n")
合法性判断
def is_valid(expression):
try:
if eval(expression) < 0:
return False
except ZeroDivisionError:
return False
return True
正确率计数
def grade_answers(exercise_file, answer_file):
exercises = load_file(exercise_file)
answers = load_file(answer_file)
correct_answers = []
wrong_answers = []
for i in range(len(answers)):
if exercises[i].strip() == answers[i].strip():
wrong_answers.append(i + 1)
else:
correct_answers.append(i + 1)
return correct_answers, wrong_answers
计数保存到文件中
def save_grade(correct_answers, wrong_answers, script_dir):
total_correct = len(correct_answers)
total_wrong = len(wrong_answers)
grade_file_path = os.path.join(script_dir, "grade.txt")
with open(grade_file_path, "w") as grade_file:
grade_file.write(f"Correct: {total_correct}\n")
if total_correct > 0:
grade_file.write("(")
for idx, correct in enumerate(correct_answers, start=1):
grade_file.write(f"{correct},")
grade_file.write(")\n")
grade_file.write(f"Wrong: {total_wrong}\n")
if total_wrong > 0:
grade_file.write("(")
for idx, wrong in enumerate(wrong_answers, start=1):
grade_file.write(f"{wrong},")
grade_file.write(")\n")
主函数调用parser模块部分
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-n', type=int, help='Number of exercises to generate', default=10)
parser.add_argument('-r', type=int, help='Range of numbers in exercises', default=10)
parser.add_argument('-e', '--exercisefile', type=str, help='Exercise file path')
parser.add_argument('-a', '--answerfile', type=str, help='Answer file path')
args = parser.parse_args()
script_dir = os.path.dirname(os.path.realpath(__file__))
exercises = []
answers = []
if args.exercisefile and args.answerfile:
correct_answers, wrong_answers = grade_answers(args.exercisefile, args.answerfile)
save_grade(correct_answers, wrong_answers, script_dir)
else:
generate_exercises(exercises, answers, args.n, args.r)
save_exercises_and_answers(exercises, answers, script_dir)
测试运行
项目小结
在本次项目中,两人合作共同完成了一个关于小学四则运算的生成项目,因为是与舍友合作,所以在项目的进展中合作较为顺利,遇到难题可以共同即使讨论出解决方法。也积累了很多的经验,相信在下次合作中可以更加顺利合作。