第三周结对项目
第三周项目:小学四则运算题目自动生成器
1. 作业信息
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 计科 24 级 56 班 |
| 这个作业要求在哪里 | 第三周结对项目 |
| 这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序,并支持答案批改、Git 版本管理和技术文档整理。 |
| 项目成员 | 3124004049 |
| 完成方式 | 本项目由一人完成。 |
| GitHub 项目地址 | onychen/gdut-software-engineering-2026(项目目录:3124004049/pair_arithmetic/) |
| 开发环境 | Windows 11、Python 3.13、Python 标准库 |
2. 项目简介与运行方式
程序提供两种命令行模式:
# 生成 10 道数值范围为 [0, 10) 的题目
python main.py -n 10 -r 10 --seed 42
# 批改题目文件与学生答案文件
python main.py -e Exercises.txt -a StudentAnswers.txt
生成模式会在当前工作目录写出 Exercises.txt 和 Answers.txt;批改模式会写出 Grade.txt。示例格式如下:
Correct: 8 (1, 3, 5, 6, 7, 8, 9, 10)
Wrong: 2 (2, 4)
实现的功能和约束如下。
| 编号 | 作业要求 | 实现方式 |
|---|---|---|
| 1 | 使用 -n 控制题目数量、使用 -r 控制范围 |
argparse 解析参数;生成模式缺少 -r 会显示帮助错误。 |
| 2 | 支持自然数、真分数与带分数 | 使用 fractions.Fraction;支持 3/5 和 2’3/8,也兼容 ASCII 单引号。 |
| 3 | 减法中间结果不为负 | 构造减法节点前比较左右子树,必要时交换,保证 left >= right。 |
| 4 | 除法结果为真分数 | 仅接受严格满足 0 < left / right < 1 的除法节点。 |
| 5 | 每题不超过 3 个运算符 | 随机生成 1 至 3 个运算符的表达式树。 |
| 6 | 一次生成中题目不重复 | 对 +、× 的左右子树规范串排序;-、÷ 保留顺序后放入集合去重。 |
| 7 | 输出题目和标准答案文件 | 分别写入 Exercises.txt、Answers.txt。 |
| 8 | 支持 10,000 道题 | 固定种子下实际生成 10,000 道互不重复题目。 |
| 9 | 支持批改 | 重新解析每一行题目,精确比较答案,输出 Correct / Wrong 题号列表。 |
3. PSP2.1 表格
单位:分钟。以下记录按本项目的个人完成过程整理。
| PSP2.1 | Personal Software Process Stages | 预估耗时 | 实际耗时 |
|---|---|---|---|
| Planning | 计划 | 20 | 18 |
| · Estimate | 估计这个任务需要多少时间 | 20 | 18 |
| Development | 开发 | 285 | 296 |
| · Analysis | 需求分析(包括学习新技术) | 35 | 32 |
| · Design Spec | 生成设计文档 | 30 | 36 |
| · Design Review | 设计复审 | 20 | 22 |
| · Coding Standard | 代码规范 | 10 | 8 |
| · Design | 具体设计 | 40 | 43 |
| · Coding | 具体编码 | 110 | 118 |
| · Code Review | 代码复审 | 15 | 14 |
| · Test | 测试(自我测试、修改代码、提交修改) | 25 | 23 |
| Reporting | 报告 | 60 | 59 |
| · Test Report | 测试报告 | 25 | 24 |
| · Size Measurement | 计算工作量 | 10 | 10 |
| · Postmortem & Process Improvement Plan | 事后总结并提出过程改进计划 | 25 | 25 |
| 合计 | 365 | 373 |
4. 效能分析
4.1 测试方法与结果
使用固定随机种子执行以下命令,以便复现生成结果:
python tools\benchmark.py
python -m cProfile -s cumulative tools\benchmark.py
本机一次实际运行结果:
| 指标 | 结果 |
|---|---|
| 生成数量 | 10,000 |
| 规范键去重后的数量 | 10,000 |
| 普通计时耗时 | 0.3215 秒 |
| cProfile 总函数调用次数 | 3,648,013 |
| cProfile 总耗时 | 1.115 秒 |
cProfile 会插入统计开销,因此其总耗时不能与普通计时直接比较。累计耗时最高的业务函数是 generate_problems() 和递归的 make_candidate();随后是 Fraction 的构造、表达式求值和规范键生成。
4.2 分析与改进
题目生成的主要开销来自构建候选表达式并校验减法、除法限制。当前实现把约束放在每个二叉树节点的构造阶段:减法直接调整左右子树顺序,除法只保留真分数结果;不符合条件的候选立即丢弃,避免生成后再对整棵树进行额外的全树校验。
去重使用 set 保存表达式规范键,平均插入和查询复杂度为 O(1)。在固定范围下,整体生成过程对题目数量近似线性;当范围太小、无法提供足量互异题目时,程序达到重试上限后会明确报错,不会无限循环。
5. 设计实现过程
5.1 模块组织
| 文件 | 职责 | 主要接口 |
|---|---|---|
main.py |
命令行入口、生成/批改模式分发、文件输出 | build_parser()、run() |
expression.py |
表达式树、求值、最小括号输出、规范键 | Expr、evaluated、render()、canonical() |
fraction_utils.py |
整数/真分数/带分数解析与格式化 | parse_number()、format_fraction() |
generator.py |
合法题目生成、去重和重试上限 | make_candidate()、generate_problems() |
parser.py |
递归下降表达式解析 | tokenize()、parse_expression()、parse_answer() |
grader.py |
读取文件、逐题批改、生成报告 | grade_files()、GradeResult |
tools/benchmark.py |
10,000 题性能验证 | main() |
tests/test_project.py |
自动化单元测试与边界测试 | 10 个测试用例 |
模块依赖关系:
main.py ──┬── generator.py ──┬── expression.py ── fraction_utils.py
│ └── fraction_utils.py
└── grader.py ──── parser.py ────────── expression.py
5.2 核心设计
每道题用不可变的二叉表达式树 Expr 表示。叶子节点保存 Fraction,非叶子节点保存运算符与左右子树。因此求值、输出题目、生成答案和去重都针对同一份数据结构进行,避免多份字符串状态不一致。
为了处理题目要求的“有限次交换 + 和 × 左右操作数”的重复定义,canonical() 会递归生成规范串:加法和乘法节点先比较两侧子树的规范串并排序;减法、除法保持左右顺序。这样 23 + 45 与 45 + 23 会判重,3 + (2 + 1) 与 1 + 2 + 3 也会判重,而 1 + 2 + 3 与 3 + 2 + 1 不会被误判为同题。
表达式输出会遵循优先级并保留必要括号。例如右子树与父节点同优先级但运算符不同的 8 + (5 - 3) 不会被错误输出为 8 + 5 - 3;解析后仍和原表达式的值一致。
6. 测试结果
运行命令:
python -m unittest discover -s tests -v
当前结果:10 个测试全部通过。
| 编号 | 测试内容 | 预期结果 | 结果 |
|---|---|---|---|
| T01 | 真分数、带分数的解析与格式化 | 19/8 输出为 2’3/8 |
通过 |
| T02 | 精确分数计算 | 1/6 + 1/8 = 7/24 |
通过 |
| T03 | 加法交换律与嵌套交换去重 | 指定等价式判重,非等价式不判重 | 通过 |
| T04 | 非法表达式 | 含非法字符时抛出格式错误 | 通过 |
| T05 | 同优先级右子树括号 | 输出并重新解析后计算值不变 | 通过 |
| T06 | 300 道随机生成 | 无重复、运算符不超过 3、每个节点满足约束 | 通过 |
| T07 | 生成—解析闭环 | 100 道题重新解析后结果与原树一致 | 通过 |
| T08 | 10,000 道题生成 | 题目数量为 10,000 | 通过 |
| T09 | 混合答案批改 | 正确题和错误题的题号列表正确 | 通过 |
| T10 | 缺失答案 | 缺失行对应题目判错且程序不崩溃 | 通过 |
7. 项目小结
本项目把“出题、求值、显示、解析、批改”统一在表达式树和精确有理数模型上。使用 Fraction 后,分数约分、带分数格式化和答案等价比较都不需要手工处理浮点误差;通过递归下降解析器,可以对输出题目重新计算并用于批改,形成完整闭环。
后续可继续扩展图形界面、难度分级或更多可配置项,但命令行版本已经覆盖作业的核心生成、去重、10,000 题和判题要求。
浙公网安备 33010602011771号